summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Vakulenko <avakulenko@google.com>2016-01-15 13:02:14 -0800
committerIan Pedowitz <ijpedowitz@google.com>2016-01-20 16:43:08 -0800
commitcce46a0c214b37e8da48c522c83037e8ffa4f9fd (patch)
treefda1edce8588baf15dc32fbc640f8281a65521f6
parent6b7c08d27852da2b8d52ee88a05e6808370f3f74 (diff)
downloadlibchrome-cce46a0c214b37e8da48c522c83037e8ffa4f9fd.tar.gz
libchrome: Uprev the library to r369476 from Chromium
Pulled the latest and greatest version of libchrome from Chromium. The merge was done against r369476 which corresponds to git commit 0471d0e2e2ef4a544a63481a389e1df33ea7c00a of Jan 14, 2016 Notable changes are: - base::scoped_ptr<T> is now almost identical to std::unique_ptr<T> No Pass() method, now std::move() is used on scoped pointers - basictypes.h is removed and custom int types such as int32 are now replaced with the standard int32_t and similar from <stdint.h> - String utility functions are cleaned up/refactored. Now all are in base:: namespace, many now return values rather than take pointers for results, ambiguous Booleans are replaced with enums, such as: base::StartsWithASCII(current_url, "https://", false); now is: base::StartsWith(current_url, "https://", base::CompareCase::INSENSITIVE_ASCII); - COMPILE_ASSERT() is now replaced with standard static_assert() - Numeric range constants such as kuint64max are removed in favor of standard <limits> constructs such as std::numeric_limits<uint64_t>::max() - base::Value and derived classes use scoped_ptr<> more and support for raw pointers to base::Value is deprecated and/or removed in many places. - base::MessageLoopProxy is completely removed (was marked deprecated before) - base::MessageLoop::Quit() and QuitClosure are renamed to QuitWhenIdle and QuitWhenIdleClosure for more semantic clarity. (cherry picked from commit 0d205d712abd16eeed2f5d5b1052a367d23a223f) Change-Id: I4fb67d80eacd03186868c12c9509189d184e00bd
-rw-r--r--Android.mk38
-rw-r--r--base/BUILD.gn885
-rw-r--r--base/DEPS4
-rw-r--r--base/OWNERS13
-rw-r--r--base/allocator/BUILD.gn185
-rw-r--r--base/allocator/README11
-rw-r--r--base/allocator/allocator.gyp424
-rw-r--r--base/allocator/allocator_extension.h47
-rwxr-xr-xbase/allocator/prep_libc.py29
-rw-r--r--base/allocator/type_profiler_control.cc38
-rw-r--r--base/allocator/type_profiler_control.h31
-rw-r--r--base/android/OWNERS3
-rw-r--r--base/android/java/src/org/chromium/base/ActivityState.java40
-rw-r--r--base/android/java/src/org/chromium/base/AnimationFrameTimeHistogram.java145
-rw-r--r--base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java418
-rw-r--r--base/android/java/src/org/chromium/base/ApkAssets.java45
-rw-r--r--base/android/java/src/org/chromium/base/ApplicationStatus.java448
-rw-r--r--base/android/java/src/org/chromium/base/BaseChromiumApplication.java170
-rw-r--r--base/android/java/src/org/chromium/base/BaseSwitches.java32
-rw-r--r--base/android/java/src/org/chromium/base/BuildInfo.java125
-rw-r--r--base/android/java/src/org/chromium/base/CalledByNative.java23
-rw-r--r--base/android/java/src/org/chromium/base/CollectionUtil.java41
-rw-r--r--base/android/java/src/org/chromium/base/CommandLine.java383
-rw-r--r--base/android/java/src/org/chromium/base/ContentUriUtils.java150
-rw-r--r--base/android/java/src/org/chromium/base/CpuFeatures.java40
-rw-r--r--base/android/java/src/org/chromium/base/EventLog.java17
-rw-r--r--base/android/java/src/org/chromium/base/FieldTrialList.java33
-rw-r--r--base/android/java/src/org/chromium/base/ImportantFileWriterAndroid.java29
-rw-r--r--base/android/java/src/org/chromium/base/JNIAdditionalImport.java35
-rw-r--r--base/android/java/src/org/chromium/base/JNINamespace.java20
-rw-r--r--base/android/java/src/org/chromium/base/JNIUtils.java20
-rw-r--r--base/android/java/src/org/chromium/base/JavaHandlerThread.java56
-rw-r--r--base/android/java/src/org/chromium/base/LocaleUtils.java55
-rw-r--r--base/android/java/src/org/chromium/base/Log.java353
-rw-r--r--base/android/java/src/org/chromium/base/MemoryPressureListener.java114
-rw-r--r--base/android/java/src/org/chromium/base/NativeCall.java24
-rw-r--r--base/android/java/src/org/chromium/base/NativeClassQualifiedName.java25
-rw-r--r--base/android/java/src/org/chromium/base/OWNERS2
-rw-r--r--base/android/java/src/org/chromium/base/ObserverList.java249
-rw-r--r--base/android/java/src/org/chromium/base/PackageUtils.java55
-rw-r--r--base/android/java/src/org/chromium/base/PathService.java24
-rw-r--r--base/android/java/src/org/chromium/base/PathUtils.java127
-rw-r--r--base/android/java/src/org/chromium/base/PerfTraceEvent.java379
-rw-r--r--base/android/java/src/org/chromium/base/PowerMonitor.java98
-rw-r--r--base/android/java/src/org/chromium/base/PowerStatusReceiver.java23
-rw-r--r--base/android/java/src/org/chromium/base/README_logging.md181
-rw-r--r--base/android/java/src/org/chromium/base/ResourceExtractor.java484
-rw-r--r--base/android/java/src/org/chromium/base/SecureRandomInitializer.java42
-rw-r--r--base/android/java/src/org/chromium/base/SysUtils.java139
-rw-r--r--base/android/java/src/org/chromium/base/SystemMessageHandler.java111
-rw-r--r--base/android/java/src/org/chromium/base/ThreadUtils.java209
-rw-r--r--base/android/java/src/org/chromium/base/TraceEvent.java285
-rw-r--r--base/android/java/src/org/chromium/base/VisibleForTesting.java12
-rw-r--r--base/android/java/src/org/chromium/base/annotations/AccessedByNative.java20
-rw-r--r--base/android/java/src/org/chromium/base/annotations/CalledByNativeUnchecked.java27
-rw-r--r--base/android/java/src/org/chromium/base/annotations/NoSideEffects.java17
-rw-r--r--base/android/java/src/org/chromium/base/annotations/SuppressFBWarnings.java20
-rw-r--r--base/android/java/src/org/chromium/base/annotations/UsedByReflection.java24
-rw-r--r--base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java509
-rw-r--r--base/android/java/src/org/chromium/base/library_loader/LibraryLoaderHelper.java338
-rw-r--r--base/android/java/src/org/chromium/base/library_loader/Linker.java1095
-rw-r--r--base/android/java/src/org/chromium/base/library_loader/LoaderErrors.java16
-rw-r--r--base/android/java/src/org/chromium/base/library_loader/ProcessInitException.java35
-rw-r--r--base/android/java/src/org/chromium/base/metrics/RecordHistogram.java177
-rw-r--r--base/android/java/src/org/chromium/base/metrics/RecordUserAction.java36
-rw-r--r--base/android/java/templates/NativeLibraries.template95
-rw-r--r--base/android/javatests/src/org/chromium/base/AdvancedMockContextTest.java68
-rw-r--r--base/android/javatests/src/org/chromium/base/ApiCompatibilityUtilsTest.java71
-rw-r--r--base/android/javatests/src/org/chromium/base/CommandLineTest.java128
-rw-r--r--base/android/javatests/src/org/chromium/base/ObserverListTest.java326
-rw-r--r--base/android/javatests/src/org/chromium/base/metrics/RecordHistogramTest.java159
-rw-r--r--base/android/jni_generator/android_jar.classes98
-rw-r--r--base/android/jni_generator/golden_sample_for_tests_jni.h400
-rw-r--r--base/android/jni_generator/java/src/org/chromium/example/jni_generator/SampleForTests.java304
-rw-r--r--base/android/jni_generator/jni_generator.gyp68
-rwxr-xr-xbase/android/jni_generator/jni_generator.py1557
-rw-r--r--base/android/jni_generator/jni_generator_helper.h40
-rwxr-xr-xbase/android/jni_generator/jni_generator_tests.py1175
-rw-r--r--base/android/jni_generator/testCalledByNatives.golden510
-rw-r--r--base/android/jni_generator/testConstantsFromJavaP.golden2233
-rw-r--r--base/android/jni_generator/testEagerCalledByNativesOption.golden146
-rw-r--r--base/android/jni_generator/testFromJavaP.golden267
-rw-r--r--base/android/jni_generator/testFromJavaPGenerics.golden65
-rw-r--r--base/android/jni_generator/testInnerClassNatives.golden60
-rw-r--r--base/android/jni_generator/testInnerClassNativesBothInnerAndOuter.golden81
-rw-r--r--base/android/jni_generator/testInnerClassNativesMultiple.golden82
-rw-r--r--base/android/jni_generator/testInputStream.javap228
-rw-r--r--base/android/jni_generator/testJNIInitNativeNameOption.golden71
-rw-r--r--base/android/jni_generator/testJarJarRemapping.golden85
-rw-r--r--base/android/jni_generator/testMotionEvent.javap2295
-rw-r--r--base/android/jni_generator/testMotionEvent.javap72370
-rw-r--r--base/android/jni_generator/testMultipleJNIAdditionalImport.golden88
-rw-r--r--base/android/jni_generator/testNativeExportsOption.golden219
-rw-r--r--base/android/jni_generator/testNativeExportsOptionalOption.golden288
-rw-r--r--base/android/jni_generator/testNatives.golden218
-rw-r--r--base/android/jni_generator/testNativesLong.golden65
-rw-r--r--base/android/jni_generator/testPureNativeMethodsOption.golden66
-rw-r--r--base/android/jni_generator/testSingleJNIAdditionalImport.golden84
-rw-r--r--base/android/jni_int_wrapper.h56
-rw-r--r--base/android/junit/src/org/chromium/base/BaseChromiumApplicationTest.java94
-rw-r--r--base/android/junit/src/org/chromium/base/LogTest.java226
-rw-r--r--base/android/library_loader/library_load_from_apk_status_codes.h49
-rw-r--r--base/android/linker/BUILD.gn27
-rw-r--r--base/android/linker/DEPS4
-rw-r--r--base/android/linker/config.gni8
-rw-r--r--base/android/thread_utils.h16
-rw-r--r--base/async_socket_io_handler.h110
-rw-r--r--base/at_exit.h2
-rw-r--r--base/atomic_sequence_num.h2
-rw-r--r--base/atomicops.h64
-rw-r--r--base/atomicops_internals_arm64_gcc.h307
-rw-r--r--base/atomicops_internals_arm_gcc.h294
-rw-r--r--base/atomicops_internals_atomicword_compat.h6
-rw-r--r--base/atomicops_internals_gcc.h106
-rw-r--r--base/atomicops_internals_mac.h197
-rw-r--r--base/atomicops_internals_mips_gcc.h280
-rw-r--r--base/atomicops_internals_portable.h2
-rw-r--r--base/atomicops_internals_x86_gcc.cc103
-rw-r--r--base/atomicops_internals_x86_gcc.h228
-rw-r--r--base/atomicops_internals_x86_msvc.h3
-rw-r--r--base/atomicops_unittest.cc7
-rw-r--r--base/auto_reset.h2
-rw-r--r--base/base.gyp197
-rw-r--r--base/base.gypi97
-rw-r--r--base/base.isolate40
-rw-r--r--base/base64.cc2
-rw-r--r--base/base64url.cc102
-rw-r--r--base/base64url.h56
-rw-r--r--base/base64url_unittest.cc115
-rw-r--r--base/base_export.h5
-rw-r--r--base/base_nacl.gyp12
-rw-r--r--base/base_switches.cc24
-rw-r--r--base/base_switches.h11
-rw-r--r--base/base_unittests.isolate2
-rw-r--r--base/basictypes.h45
-rw-r--r--base/bind.h49
-rw-r--r--base/bind_helpers.h168
-rw-r--r--base/bind_internal.h77
-rw-r--r--base/bind_internal_win.h10
-rw-r--r--base/bind_unittest.cc170
-rw-r--r--base/bits.h18
-rw-r--r--base/bits_unittest.cc17
-rw-r--r--base/callback.h44
-rw-r--r--base/callback_forward.h4
-rw-r--r--base/callback_helpers.h2
-rw-r--r--base/callback_internal.h97
-rw-r--r--base/callback_list.h8
-rw-r--r--base/callback_list_unittest.cc55
-rw-r--r--base/callback_unittest.cc37
-rw-r--r--base/cancelable_callback.h1
-rw-r--r--base/command_line.cc21
-rw-r--r--base/command_line_unittest.cc3
-rw-r--r--base/compiler_specific.h35
-rw-r--r--base/containers/adapters.h25
-rw-r--r--base/containers/hash_tables.h109
-rw-r--r--base/containers/mru_cache.h13
-rw-r--r--base/containers/scoped_ptr_hash_map.h10
-rw-r--r--base/containers/scoped_ptr_map.h137
-rw-r--r--base/containers/small_map.h5
-rw-r--r--base/containers/stack_container.h6
-rw-r--r--base/cpu.cc32
-rw-r--r--base/cpu.h10
-rw-r--r--base/cpu_unittest.cc88
-rw-r--r--base/critical_closure.h2
-rw-r--r--base/debug/BUILD.gn76
-rw-r--r--base/debug/debugger.cc1
-rw-r--r--base/debug/debugger_posix.cc10
-rw-r--r--base/debug/leak_tracker.h2
-rw-r--r--base/debug/proc_maps_linux.h5
-rw-r--r--base/debug/stack_trace.cc4
-rw-r--r--base/debug/stack_trace.h19
-rw-r--r--base/debug/stack_trace_posix.cc113
-rw-r--r--base/debug/task_annotator.cc36
-rw-r--r--base/debug/task_annotator.h18
-rw-r--r--base/debug/task_annotator_unittest.cc3
-rw-r--r--base/environment.cc9
-rw-r--r--base/environment_unittest.cc3
-rw-r--r--base/file_descriptor_posix.h13
-rw-r--r--base/file_version_info.h23
-rw-r--r--base/file_version_info_unittest.cc82
-rw-r--r--base/files/OWNERS3
-rw-r--r--base/files/dir_reader_fallback.h2
-rw-r--r--base/files/dir_reader_linux.h7
-rw-r--r--base/files/dir_reader_posix_unittest.cc1
-rw-r--r--base/files/file.cc53
-rw-r--r--base/files/file.h109
-rw-r--r--base/files/file_enumerator.h7
-rw-r--r--base/files/file_enumerator_posix.cc4
-rw-r--r--base/files/file_path.cc132
-rw-r--r--base/files/file_path.h50
-rw-r--r--base/files/file_path_constants.cc3
-rw-r--r--base/files/file_path_unittest.cc7
-rw-r--r--base/files/file_path_watcher.cc1
-rw-r--r--base/files/file_path_watcher.h7
-rw-r--r--base/files/file_path_watcher_fsevents.cc1
-rw-r--r--base/files/file_path_watcher_fsevents.h2
-rw-r--r--base/files/file_path_watcher_kqueue.cc1
-rw-r--r--base/files/file_path_watcher_kqueue.h1
-rw-r--r--base/files/file_path_watcher_linux.cc33
-rw-r--r--base/files/file_path_watcher_mac.cc1
-rw-r--r--base/files/file_path_watcher_unittest.cc3
-rw-r--r--base/files/file_posix.cc131
-rw-r--r--base/files/file_tracing.cc20
-rw-r--r--base/files/file_tracing.h19
-rw-r--r--base/files/file_unittest.cc85
-rw-r--r--base/files/file_util.cc7
-rw-r--r--base/files/file_util.h29
-rw-r--r--base/files/file_util_mac.mm1
-rw-r--r--base/files/file_util_posix.cc37
-rw-r--r--base/files/important_file_writer.cc65
-rw-r--r--base/files/important_file_writer.h28
-rw-r--r--base/files/important_file_writer_unittest.cc11
-rw-r--r--base/files/memory_mapped_file.h30
-rw-r--r--base/files/scoped_file.cc1
-rw-r--r--base/files/scoped_temp_dir.h1
-rw-r--r--base/files/scoped_temp_dir_unittest.cc1
-rw-r--r--base/format_macros.h3
-rw-r--r--base/guid.cc2
-rw-r--r--base/guid.h5
-rw-r--r--base/guid_posix.cc6
-rw-r--r--base/guid_unittest.cc11
-rw-r--r--base/id_map.h66
-rw-r--r--base/id_map_unittest.cc22
-rw-r--r--base/json/BUILD.gn37
-rw-r--r--base/json/json_file_value_serializer.cc120
-rw-r--r--base/json/json_file_value_serializer.h106
-rw-r--r--base/json/json_parser.cc53
-rw-r--r--base/json/json_parser.h38
-rw-r--r--base/json/json_parser_unittest.cc63
-rw-r--r--base/json/json_reader.cc30
-rw-r--r--base/json/json_reader.h14
-rw-r--r--base/json/json_reader_unittest.cc664
-rw-r--r--base/json/json_string_value_serializer.cc7
-rw-r--r--base/json/json_string_value_serializer.h6
-rw-r--r--base/json/json_value_converter.cc37
-rw-r--r--base/json/json_value_converter.h516
-rw-r--r--base/json/json_value_converter_unittest.cc256
-rw-r--r--base/json/json_value_serializer_unittest.cc500
-rw-r--r--base/json/json_writer.cc10
-rw-r--r--base/json/json_writer.h4
-rw-r--r--base/json/json_writer_unittest.cc7
-rw-r--r--base/json/string_escape.cc29
-rw-r--r--base/json/string_escape_unittest.cc7
-rw-r--r--base/lazy_instance.cc1
-rw-r--r--base/lazy_instance.h1
-rw-r--r--base/lazy_instance_unittest.cc2
-rw-r--r--base/location.h9
-rw-r--r--base/logging.cc284
-rw-r--r--base/logging.h89
-rw-r--r--base/logging_unittest.cc46
-rw-r--r--base/mac/OWNERS13
-rw-r--r--base/mac/foundation_util.h9
-rw-r--r--base/mac/foundation_util.mm17
-rw-r--r--base/mac/libdispatch_task_runner.cc4
-rw-r--r--base/mac/mac_logging.h2
-rw-r--r--base/mac/mac_util.h27
-rw-r--r--base/mac/mach_logging.cc1
-rw-r--r--base/mac/mach_logging.h2
-rw-r--r--base/mac/scoped_aedesc.h2
-rw-r--r--base/mac/scoped_authorizationref.h2
-rw-r--r--base/mac/scoped_block.h83
-rw-r--r--base/mac/scoped_cffiledescriptorref.h68
-rw-r--r--base/mac/scoped_cftyperef.h23
-rw-r--r--base/mac/scoped_ioobject.h66
-rw-r--r--base/mac/scoped_ioplugininterface.h70
-rw-r--r--base/mac/scoped_launch_data.h64
-rw-r--r--base/mac/scoped_mach_port.h29
-rw-r--r--base/mac/scoped_nsautorelease_pool.h2
-rw-r--r--base/mac/scoped_nsobject.h131
-rw-r--r--base/mac/scoped_typeref.h21
-rw-r--r--base/macros.h123
-rw-r--r--base/md5.h1
-rw-r--r--base/md5_unittest.cc1
-rw-r--r--base/memory/BUILD.gn70
-rw-r--r--base/memory/aligned_memory.cc1
-rw-r--r--base/memory/aligned_memory.h43
-rw-r--r--base/memory/aligned_memory_unittest.cc1
-rw-r--r--base/memory/linked_ptr.h6
-rw-r--r--base/memory/raw_scoped_refptr_mismatch_checker.h73
-rw-r--r--base/memory/ref_counted.h16
-rw-r--r--base/memory/ref_counted_delete_on_message_loop.h3
-rw-r--r--base/memory/ref_counted_memory.cc25
-rw-r--r--base/memory/ref_counted_memory.h25
-rw-r--r--base/memory/ref_counted_memory_unittest.cc14
-rw-r--r--base/memory/ref_counted_unittest.cc36
-rw-r--r--base/memory/scoped_ptr.h371
-rw-r--r--base/memory/scoped_ptr_unittest.cc329
-rw-r--r--base/memory/scoped_ptr_unittest.nc32
-rw-r--r--base/memory/scoped_vector.h18
-rw-r--r--base/memory/scoped_vector_unittest.cc26
-rw-r--r--base/memory/shared_memory.h129
-rw-r--r--base/memory/singleton.h55
-rw-r--r--base/memory/singleton_unittest.cc20
-rw-r--r--base/memory/weak_ptr.h16
-rw-r--r--base/memory/weak_ptr_unittest.nc7
-rw-r--r--base/message_loop/incoming_task_queue.cc8
-rw-r--r--base/message_loop/incoming_task_queue.h4
-rw-r--r--base/message_loop/message_loop.cc77
-rw-r--r--base/message_loop/message_loop.h70
-rw-r--r--base/message_loop/message_loop_proxy.cc17
-rw-r--r--base/message_loop/message_loop_proxy.h50
-rw-r--r--base/message_loop/message_loop_proxy_impl_unittest.cc129
-rw-r--r--base/message_loop/message_loop_task_runner.cc (renamed from base/message_loop/message_loop_proxy_impl.cc)26
-rw-r--r--base/message_loop/message_loop_task_runner.h (renamed from base/message_loop/message_loop_proxy_impl.h)31
-rw-r--r--base/message_loop/message_loop_task_runner_unittest.cc (renamed from base/message_loop/message_loop_proxy_unittest.cc)192
-rw-r--r--base/message_loop/message_loop_test.cc58
-rw-r--r--base/message_loop/message_loop_unittest.cc66
-rw-r--r--base/message_loop/message_pump.h4
-rw-r--r--base/message_loop/message_pump_default.cc10
-rw-r--r--base/message_loop/message_pump_default.h1
-rw-r--r--base/message_loop/message_pump_libevent.cc53
-rw-r--r--base/message_loop/message_pump_libevent.h7
-rw-r--r--base/message_loop/message_pump_mac.h5
-rw-r--r--base/message_loop/message_pump_mac.mm46
-rw-r--r--base/metrics/BUILD.gn49
-rw-r--r--base/metrics/bucket_ranges.cc120
-rw-r--r--base/metrics/bucket_ranges.h20
-rw-r--r--base/metrics/bucket_ranges_unittest.cc6
-rw-r--r--base/metrics/field_trial.cc166
-rw-r--r--base/metrics/field_trial.h62
-rw-r--r--base/metrics/field_trial_unittest.cc59
-rw-r--r--base/metrics/histogram.cc121
-rw-r--r--base/metrics/histogram.h78
-rw-r--r--base/metrics/histogram_base.cc31
-rw-r--r--base/metrics/histogram_base.h36
-rw-r--r--base/metrics/histogram_delta_serialization.h5
-rw-r--r--base/metrics/histogram_flattener.h2
-rw-r--r--base/metrics/histogram_macros.h7
-rw-r--r--base/metrics/histogram_samples.cc64
-rw-r--r--base/metrics/histogram_samples.h62
-rw-r--r--base/metrics/histogram_snapshot_manager.cc16
-rw-r--r--base/metrics/histogram_snapshot_manager.h12
-rw-r--r--base/metrics/histogram_snapshot_manager_unittest.cc3
-rw-r--r--base/metrics/histogram_unittest.cc41
-rw-r--r--base/metrics/metrics_hashes.cc31
-rw-r--r--base/metrics/metrics_hashes.h21
-rw-r--r--base/metrics/metrics_hashes_unittest.cc35
-rw-r--r--base/metrics/sample_map.cc4
-rw-r--r--base/metrics/sample_map.h8
-rw-r--r--base/metrics/sample_map_unittest.cc14
-rw-r--r--base/metrics/sample_vector.cc57
-rw-r--r--base/metrics/sample_vector.h29
-rw-r--r--base/metrics/sample_vector_unittest.cc21
-rw-r--r--base/metrics/sparse_histogram.cc34
-rw-r--r--base/metrics/sparse_histogram.h15
-rw-r--r--base/metrics/sparse_histogram_unittest.cc19
-rw-r--r--base/metrics/statistics_recorder.cc87
-rw-r--r--base/metrics/statistics_recorder.h37
-rw-r--r--base/metrics/statistics_recorder_unittest.cc193
-rw-r--r--base/move.h257
-rw-r--r--base/move_unittest.cc49
-rw-r--r--base/numerics/safe_conversions.h48
-rw-r--r--base/numerics/safe_conversions_impl.h65
-rw-r--r--base/numerics/safe_math.h34
-rw-r--r--base/numerics/safe_math_impl.h152
-rw-r--r--base/numerics/safe_numerics_unittest.cc207
-rw-r--r--base/observer_list.h8
-rw-r--r--base/observer_list_threadsafe.h7
-rw-r--r--base/pickle.cc116
-rw-r--r--base/pickle.h64
-rw-r--r--base/pickle_unittest.cc181
-rw-r--r--base/port.h18
-rw-r--r--base/posix/safe_strerror.h2
-rw-r--r--base/posix/unix_domain_socket_linux.cc14
-rw-r--r--base/posix/unix_domain_socket_linux.h9
-rw-r--r--base/posix/unix_domain_socket_linux_unittest.cc11
-rw-r--r--base/power_monitor/power_monitor.h2
-rw-r--r--base/power_monitor/power_monitor_device_source.h5
-rw-r--r--base/power_monitor/power_monitor_source.h2
-rw-r--r--base/prefs/OWNERS1
-rw-r--r--base/prefs/persistent_pref_store.h3
-rw-r--r--base/prefs/writeable_pref_store.h23
-rw-r--r--base/process/BUILD.gn108
-rw-r--r--base/process/internal_linux.cc20
-rw-r--r--base/process/internal_linux.h8
-rw-r--r--base/process/kill.h2
-rw-r--r--base/process/kill_posix.cc3
-rw-r--r--base/process/launch.cc1
-rw-r--r--base/process/launch.h28
-rw-r--r--base/process/launch_mac.cc17
-rw-r--r--base/process/launch_posix.cc147
-rw-r--r--base/process/process.h44
-rw-r--r--base/process/process_handle.h38
-rw-r--r--base/process/process_handle_mac.cc1
-rw-r--r--base/process/process_info.h1
-rw-r--r--base/process/process_iterator.cc1
-rw-r--r--base/process/process_iterator.h4
-rw-r--r--base/process/process_iterator_linux.cc6
-rw-r--r--base/process/process_iterator_mac.cc6
-rw-r--r--base/process/process_metrics.cc21
-rw-r--r--base/process/process_metrics.h149
-rw-r--r--base/process/process_metrics_linux.cc150
-rw-r--r--base/process/process_metrics_mac.cc47
-rw-r--r--base/process/process_metrics_posix.cc9
-rw-r--r--base/process/process_metrics_unittest.cc174
-rw-r--r--base/process/process_posix.cc44
-rw-r--r--base/profiler/alternate_timer.cc4
-rw-r--r--base/profiler/scoped_profile.h1
-rw-r--r--base/profiler/scoped_tracker.h1
-rw-r--r--base/profiler/tracked_time.cc11
-rw-r--r--base/profiler/tracked_time.h14
-rw-r--r--base/profiler/tracked_time_unittest.cc6
-rw-r--r--base/rand_util.cc24
-rw-r--r--base/rand_util.h13
-rw-r--r--base/rand_util_posix.cc6
-rw-r--r--base/rand_util_unittest.cc34
-rw-r--r--base/run_loop.cc1
-rw-r--r--base/run_loop.h6
-rw-r--r--base/scoped_clear_errno.h2
-rw-r--r--base/scoped_generic.h3
-rw-r--r--base/scoped_generic_unittest.cc12
-rw-r--r--base/scoped_observer.h8
-rw-r--r--base/security_unittest.cc200
-rw-r--r--base/sequence_checker_impl.h2
-rw-r--r--base/sequence_checker_unittest.cc19
-rw-r--r--base/sequenced_task_runner_helpers.h2
-rw-r--r--base/sha1.h2
-rw-r--r--base/sha1_portable.cc29
-rw-r--r--base/sha1_unittest.cc3
-rw-r--r--base/stl_util.h13
-rw-r--r--base/strings/pattern.cc169
-rw-r--r--base/strings/pattern.h26
-rw-r--r--base/strings/pattern_unittest.cc50
-rw-r--r--base/strings/safe_sprintf.cc27
-rw-r--r--base/strings/safe_sprintf.h1
-rw-r--r--base/strings/string16.h9
-rw-r--r--base/strings/string_number_conversions.cc178
-rw-r--r--base/strings/string_number_conversions.h34
-rw-r--r--base/strings/string_number_conversions_unittest.cc427
-rw-r--r--base/strings/string_piece.cc15
-rw-r--r--base/strings/string_piece.h25
-rw-r--r--base/strings/string_piece_unittest.cc2
-rw-r--r--base/strings/string_split.cc196
-rw-r--r--base/strings/string_split.h85
-rw-r--r--base/strings/string_split_unittest.cc172
-rw-r--r--base/strings/string_util.cc629
-rw-r--r--base/strings/string_util.h374
-rw-r--r--base/strings/string_util_posix.h17
-rw-r--r--base/strings/string_util_unittest.cc361
-rw-r--r--base/strings/string_util_win.h13
-rw-r--r--base/strings/stringprintf.cc3
-rw-r--r--base/strings/stringprintf.h33
-rw-r--r--base/strings/stringprintf_unittest.cc14
-rw-r--r--base/strings/sys_string_conversions.h8
-rw-r--r--base/strings/sys_string_conversions_mac.mm1
-rw-r--r--base/strings/sys_string_conversions_posix.cc2
-rw-r--r--base/strings/sys_string_conversions_unittest.cc5
-rw-r--r--base/strings/utf_string_conversion_utils.cc26
-rw-r--r--base/strings/utf_string_conversion_utils.h32
-rw-r--r--base/strings/utf_string_conversions.cc31
-rw-r--r--base/strings/utf_string_conversions.h12
-rw-r--r--base/strings/utf_string_conversions_unittest.cc44
-rw-r--r--base/sync_socket.h19
-rw-r--r--base/sync_socket_posix.cc2
-rw-r--r--base/sync_socket_unittest.cc4
-rw-r--r--base/synchronization/cancellation_flag.h3
-rw-r--r--base/synchronization/condition_variable.h10
-rw-r--r--base/synchronization/condition_variable_posix.cc29
-rw-r--r--base/synchronization/condition_variable_unittest.cc1
-rw-r--r--base/synchronization/lock.cc7
-rw-r--r--base/synchronization/lock.h11
-rw-r--r--base/synchronization/lock_impl.h5
-rw-r--r--base/synchronization/lock_unittest.cc1
-rw-r--r--base/synchronization/waitable_event.h5
-rw-r--r--base/synchronization/waitable_event_posix.cc4
-rw-r--r--base/synchronization/waitable_event_unittest.cc3
-rw-r--r--base/sys_byteorder.h33
-rw-r--r--base/sys_info.cc11
-rw-r--r--base/sys_info.h33
-rw-r--r--base/sys_info_chromeos.cc23
-rw-r--r--base/sys_info_internal.h2
-rw-r--r--base/sys_info_linux.cc24
-rw-r--r--base/sys_info_mac.cc23
-rw-r--r--base/sys_info_posix.cc14
-rw-r--r--base/sys_info_unittest.cc35
-rw-r--r--base/task/cancelable_task_tracker.cc6
-rw-r--r--base/task/cancelable_task_tracker.h6
-rw-r--r--base/task_runner.h5
-rw-r--r--base/task_runner_util.h2
-rw-r--r--base/task_runner_util_unittest.cc6
-rw-r--r--base/template_util.h8
-rw-r--r--base/template_util_unittest.cc132
-rw-r--r--base/test/BUILD.gn89
-rw-r--r--base/test/android/OWNERS3
-rw-r--r--base/test/android/java/src/org/chromium/base/ContentUriTestUtils.java48
-rw-r--r--base/test/android/java/src/org/chromium/base/TestUiThread.java49
-rw-r--r--base/test/android/javatests/src/org/chromium/base/test/BaseActivityInstrumentationTestCase.java118
-rw-r--r--base/test/android/javatests/src/org/chromium/base/test/BaseInstrumentationTestRunner.java133
-rw-r--r--base/test/android/javatests/src/org/chromium/base/test/util/AdvancedMockContext.java118
-rw-r--r--base/test/android/javatests/src/org/chromium/base/test/util/CommandLineFlags.java48
-rw-r--r--base/test/android/javatests/src/org/chromium/base/test/util/DisabledTest.java21
-rw-r--r--base/test/android/javatests/src/org/chromium/base/test/util/EnormousTest.java24
-rw-r--r--base/test/android/javatests/src/org/chromium/base/test/util/Feature.java29
-rw-r--r--base/test/android/javatests/src/org/chromium/base/test/util/HostDrivenTest.java22
-rw-r--r--base/test/android/javatests/src/org/chromium/base/test/util/InMemorySharedPreferences.java238
-rw-r--r--base/test/android/javatests/src/org/chromium/base/test/util/InstrumentationUtils.java32
-rw-r--r--base/test/android/javatests/src/org/chromium/base/test/util/IntegrationTest.java26
-rw-r--r--base/test/android/javatests/src/org/chromium/base/test/util/Manual.java21
-rw-r--r--base/test/android/javatests/src/org/chromium/base/test/util/MetricsUtils.java43
-rw-r--r--base/test/android/javatests/src/org/chromium/base/test/util/MinAndroidSdkLevel.java19
-rw-r--r--base/test/android/javatests/src/org/chromium/base/test/util/PerfTest.java88
-rw-r--r--base/test/android/javatests/src/org/chromium/base/test/util/Restriction.java37
-rw-r--r--base/test/android/javatests/src/org/chromium/base/test/util/ScalableTimeout.java28
-rw-r--r--base/test/android/javatests/src/org/chromium/base/test/util/TestFileUtil.java78
-rw-r--r--base/test/android/javatests/src/org/chromium/base/test/util/TestThread.java143
-rw-r--r--base/test/android/javatests/src/org/chromium/base/test/util/TimeoutScale.java22
-rw-r--r--base/test/android/javatests/src/org/chromium/base/test/util/UrlUtils.java73
-rwxr-xr-xbase/test/data/pe_image/pe_image_test_32.dllbin70656 -> 85504 bytes
-rwxr-xr-xbase/test/data/pe_image/pe_image_test_64.dllbin82432 -> 98816 bytes
-rw-r--r--base/test/expectations/OWNERS1
-rw-r--r--base/test/multiprocess_test.cc3
-rw-r--r--base/test/multiprocess_test.h2
-rw-r--r--base/test/scoped_locale.h2
-rw-r--r--base/test/sequenced_worker_pool_owner.cc8
-rw-r--r--base/test/sequenced_worker_pool_owner.h12
-rw-r--r--base/test/test_file_util.h5
-rw-r--r--base/test/test_file_util_posix.cc2
-rw-r--r--base/test/test_simple_task_runner.h2
-rw-r--r--base/test/test_switches.cc5
-rw-r--r--base/test/test_switches.h1
-rw-r--r--base/test/test_timeouts.cc1
-rw-r--r--base/test/test_timeouts.h2
-rw-r--r--base/test/trace_event_analyzer.cc23
-rw-r--r--base/test/trace_event_analyzer.h10
-rw-r--r--base/test/trace_event_analyzer_unittest.cc8
-rw-r--r--base/third_party/icu/icu_utf.cc65
-rw-r--r--base/third_party/icu/icu_utf.h163
-rw-r--r--base/third_party/nspr/prtime.cc8
-rw-r--r--base/thread_task_runner_handle.cc2
-rw-r--r--base/thread_task_runner_handle.h1
-rw-r--r--base/threading/non_thread_safe_unittest.cc2
-rw-r--r--base/threading/platform_thread.h56
-rw-r--r--base/threading/platform_thread_internal_posix.h20
-rw-r--r--base/threading/platform_thread_linux.cc23
-rw-r--r--base/threading/platform_thread_mac.mm11
-rw-r--r--base/threading/platform_thread_posix.cc121
-rw-r--r--base/threading/platform_thread_unittest.cc196
-rw-r--r--base/threading/post_task_and_reply_impl.cc3
-rw-r--r--base/threading/sequenced_worker_pool.cc171
-rw-r--r--base/threading/sequenced_worker_pool.h46
-rw-r--r--base/threading/simple_thread.h19
-rw-r--r--base/threading/thread.cc87
-rw-r--r--base/threading/thread.h54
-rw-r--r--base/threading/thread_checker.h12
-rw-r--r--base/threading/thread_checker_unittest.cc4
-rw-r--r--base/threading/thread_collision_warner.h2
-rw-r--r--base/threading/thread_collision_warner_unittest.cc1
-rw-r--r--base/threading/thread_id_name_manager.h7
-rw-r--r--base/threading/thread_id_name_manager_unittest.cc12
-rw-r--r--base/threading/thread_local.h3
-rw-r--r--base/threading/thread_local_posix.cc1
-rw-r--r--base/threading/thread_local_storage.cc13
-rw-r--r--base/threading/thread_local_storage.h12
-rw-r--r--base/threading/thread_local_storage_unittest.cc2
-rw-r--r--base/threading/thread_restrictions.cc4
-rw-r--r--base/threading/thread_restrictions.h42
-rw-r--r--base/threading/thread_unittest.cc55
-rw-r--r--base/threading/worker_pool.cc3
-rw-r--r--base/threading/worker_pool_posix.cc26
-rw-r--r--base/threading/worker_pool_posix.h2
-rw-r--r--base/threading/worker_pool_posix_unittest.cc8
-rw-r--r--base/threading/worker_pool_unittest.cc1
-rw-r--r--base/time/pr_time_unittest.cc2
-rw-r--r--base/time/time.cc59
-rw-r--r--base/time/time.h276
-rw-r--r--base/time/time_mac.cc37
-rw-r--r--base/time/time_posix.cc69
-rw-r--r--base/time/time_unittest.cc152
-rw-r--r--base/timer/hi_res_timer_manager.h2
-rw-r--r--base/timer/hi_res_timer_manager_unittest.cc5
-rw-r--r--base/timer/timer.h51
-rw-r--r--base/timer/timer_unittest.cc46
-rw-r--r--base/trace_event/BUILD.gn115
-rw-r--r--base/trace_event/OWNERS4
-rw-r--r--base/trace_event/common/trace_event_common.h1066
-rw-r--r--base/trace_event/etw_manifest/BUILD.gn47
-rw-r--r--base/trace_event/etw_manifest/BUILD/message_compiler.py16
-rw-r--r--base/trace_event/heap_profiler_allocation_context.cc68
-rw-r--r--base/trace_event/heap_profiler_allocation_context.h97
-rw-r--r--base/trace_event/heap_profiler_allocation_context_tracker.cc115
-rw-r--r--base/trace_event/heap_profiler_allocation_context_tracker.h73
-rw-r--r--base/trace_event/heap_profiler_allocation_context_tracker_unittest.cc225
-rw-r--r--base/trace_event/heap_profiler_stack_frame_deduplicator.cc115
-rw-r--r--base/trace_event/heap_profiler_stack_frame_deduplicator.h79
-rw-r--r--base/trace_event/heap_profiler_stack_frame_deduplicator_unittest.cc134
-rw-r--r--base/trace_event/heap_profiler_type_name_deduplicator.cc76
-rw-r--r--base/trace_event/heap_profiler_type_name_deduplicator.h46
-rw-r--r--base/trace_event/heap_profiler_type_name_deduplicator_unittest.cc71
-rw-r--r--base/trace_event/malloc_dump_provider.cc77
-rw-r--r--base/trace_event/malloc_dump_provider.h10
-rw-r--r--base/trace_event/memory_allocator_dump.cc8
-rw-r--r--base/trace_event/memory_allocator_dump.h35
-rw-r--r--base/trace_event/memory_allocator_dump_guid.cc14
-rw-r--r--base/trace_event/memory_allocator_dump_guid.h9
-rw-r--r--base/trace_event/memory_allocator_dump_unittest.cc25
-rw-r--r--base/trace_event/memory_dump_manager.cc770
-rw-r--r--base/trace_event/memory_dump_manager.h265
-rw-r--r--base/trace_event/memory_dump_manager_unittest.cc957
-rw-r--r--base/trace_event/memory_dump_provider.h36
-rw-r--r--base/trace_event/memory_dump_request_args.cc51
-rw-r--r--base/trace_event/memory_dump_request_args.h30
-rw-r--r--base/trace_event/memory_dump_session_state.cc7
-rw-r--r--base/trace_event/memory_dump_session_state.h28
-rw-r--r--base/trace_event/process_memory_dump.cc99
-rw-r--r--base/trace_event/process_memory_dump.h91
-rw-r--r--base/trace_event/process_memory_dump_unittest.cc28
-rw-r--r--base/trace_event/process_memory_maps.cc6
-rw-r--r--base/trace_event/process_memory_maps.h28
-rw-r--r--base/trace_event/process_memory_maps_dump_provider.cc143
-rw-r--r--base/trace_event/process_memory_maps_dump_provider.h11
-rw-r--r--base/trace_event/process_memory_maps_dump_provider_unittest.cc56
-rw-r--r--base/trace_event/process_memory_totals.cc12
-rw-r--r--base/trace_event/process_memory_totals.h24
-rw-r--r--base/trace_event/process_memory_totals_dump_provider.cc38
-rw-r--r--base/trace_event/process_memory_totals_dump_provider.h8
-rw-r--r--base/trace_event/process_memory_totals_dump_provider_unittest.cc13
-rw-r--r--base/trace_event/trace_buffer.cc400
-rw-r--r--base/trace_event/trace_buffer.h133
-rw-r--r--base/trace_event/trace_config.cc160
-rw-r--r--base/trace_event/trace_config.h44
-rw-r--r--base/trace_event/trace_config_memory_test_util.h76
-rw-r--r--base/trace_event/trace_config_unittest.cc46
-rw-r--r--base/trace_event/trace_event.gypi69
-rw-r--r--base/trace_event/trace_event.h1217
-rw-r--r--base/trace_event/trace_event_argument.cc70
-rw-r--r--base/trace_event/trace_event_argument.h28
-rw-r--r--base/trace_event/trace_event_argument_unittest.cc22
-rw-r--r--base/trace_event/trace_event_impl.cc2222
-rw-r--r--base/trace_event/trace_event_impl.h591
-rw-r--r--base/trace_event/trace_event_memory.cc436
-rw-r--r--base/trace_event/trace_event_memory.h171
-rw-r--r--base/trace_event/trace_event_memory_overhead.cc22
-rw-r--r--base/trace_event/trace_event_memory_overhead.h6
-rw-r--r--base/trace_event/trace_event_memory_unittest.cc236
-rw-r--r--base/trace_event/trace_event_synthetic_delay.cc44
-rw-r--r--base/trace_event/trace_event_synthetic_delay.h1
-rw-r--r--base/trace_event/trace_event_synthetic_delay_unittest.cc9
-rw-r--r--base/trace_event/trace_event_system_stats_monitor.h7
-rw-r--r--base/trace_event/trace_event_unittest.cc321
-rw-r--r--base/trace_event/trace_log.cc1741
-rw-r--r--base/trace_event/trace_log.h503
-rw-r--r--base/trace_event/trace_log_constants.cc (renamed from base/trace_event/trace_event_impl_constants.cc)2
-rw-r--r--base/trace_event/trace_sampling_thread.cc103
-rw-r--r--base/trace_event/trace_sampling_thread.h54
-rw-r--r--base/tracked_objects.cc129
-rw-r--r--base/tracked_objects.h103
-rw-r--r--base/tracked_objects_unittest.cc21
-rw-r--r--base/tuple.h40
-rw-r--r--base/values.cc56
-rw-r--r--base/values.h23
-rw-r--r--base/values_unittest.cc79
-rw-r--r--base/vlog.cc5
-rw-r--r--base/vlog.h2
-rw-r--r--base/vlog_unittest.cc1
-rw-r--r--base/win/OWNERS3
-rw-r--r--base/win/event_trace_consumer.h4
-rw-r--r--base/win/scoped_co_mem.h2
-rw-r--r--base/win/scoped_com_initializer.h2
-rw-r--r--base/win/scoped_comptr.h43
-rw-r--r--base/win/scoped_gdi_object.h62
-rw-r--r--base/win/scoped_hdc.h2
-rw-r--r--base/win/scoped_hglobal.h3
-rw-r--r--base/win/scoped_propvariant.h2
-rw-r--r--base/win/scoped_select_object.h2
-rw-r--r--components/timers/alarm_timer_chromeos.cc14
-rw-r--r--crypto/BUILD.gn27
-rw-r--r--crypto/OWNERS2
-rw-r--r--crypto/apple_keychain.h3
-rw-r--r--crypto/crypto.gyp7
-rw-r--r--crypto/crypto.gypi5
-rw-r--r--crypto/crypto_export.h8
-rw-r--r--crypto/crypto_unittests.isolate2
-rw-r--r--crypto/ec_private_key.h22
-rw-r--r--crypto/ec_signature_creator_impl.h12
-rw-r--r--crypto/nss_util_internal.h10
-rw-r--r--crypto/scoped_capi_types.h1
-rw-r--r--crypto/scoped_nss_types.h2
-rw-r--r--crypto/scoped_openssl_types.h3
-rw-r--r--crypto/secure_hash.h4
-rw-r--r--crypto/signature_creator.h12
-rw-r--r--crypto/signature_verifier.h31
-rw-r--r--crypto/symmetric_key.h5
-rw-r--r--dbus/BUILD.gn3
-rw-r--r--dbus/bus.cc4
-rw-r--r--dbus/bus.h4
-rw-r--r--dbus/dbus.gyp2
-rw-r--r--dbus/dbus_statistics.cc1
-rw-r--r--dbus/exported_object.cc7
-rw-r--r--dbus/file_descriptor.cc9
-rw-r--r--dbus/file_descriptor.h9
-rw-r--r--dbus/message.cc126
-rw-r--r--dbus/message.h74
-rw-r--r--dbus/mock_bus.h5
-rw-r--r--dbus/object_manager.cc21
-rw-r--r--dbus/object_manager.h5
-rw-r--r--dbus/object_proxy.cc9
-rw-r--r--dbus/object_proxy.h9
-rw-r--r--dbus/property.cc97
-rw-r--r--dbus/property.h247
-rw-r--r--dbus/string_util.cc12
-rw-r--r--dbus/test_proto.proto4
-rw-r--r--dbus/values_util.cc14
-rw-r--r--dbus/values_util.h6
-rw-r--r--sandbox/BUILD.gn6
-rw-r--r--sandbox/linux/BUILD.gn230
-rw-r--r--sandbox/linux/OWNERS1
-rw-r--r--sandbox/linux/bpf_dsl/DEPS2
-rw-r--r--sandbox/linux/bpf_dsl/bpf_dsl_impl.h20
-rw-r--r--sandbox/linux/bpf_dsl/cons.h1
-rw-r--r--sandbox/linux/bpf_dsl/seccomp_macros.h3
-rw-r--r--sandbox/linux/sandbox_linux.gypi126
-rw-r--r--sandbox/linux/sandbox_linux_nacl_nonsfi.gyp7
-rw-r--r--sandbox/linux/sandbox_linux_test_sources.gypi11
-rw-r--r--sandbox/linux/seccomp-bpf/bpf_tester_compatibility_delegate.h1
-rw-r--r--sandbox/linux/suid/common/sandbox.h2
-rw-r--r--sandbox/linux/suid/common/suid_unsafe_environment_variables.h9
-rw-r--r--sandbox/linux/suid/process_util.h1
-rw-r--r--sandbox/linux/suid/process_util_linux.c1
-rw-r--r--sandbox/linux/suid/sandbox.c23
-rw-r--r--sandbox/linux/system_headers/arm64_linux_ucontext.h1
-rw-r--r--sandbox/linux/system_headers/arm_linux_ucontext.h2
-rw-r--r--sandbox/linux/system_headers/i386_linux_ucontext.h3
-rw-r--r--sandbox/linux/system_headers/linux_signal.h129
-rw-r--r--sandbox/linux/system_headers/mips_linux_ucontext.h2
-rw-r--r--sandbox/linux/system_headers/x86_64_linux_ucontext.h2
-rw-r--r--sandbox/mac/BUILD.gn2
-rw-r--r--sandbox/mac/message_server.h5
-rw-r--r--sandbox/mac/sandbox_mac.gypi17
-rw-r--r--sandbox/mac/xpc_private_stubs.sig3
-rw-r--r--sandbox/mac/xpc_stubs.sig1
-rw-r--r--sandbox/mac/xpc_stubs_header.fragment47
-rw-r--r--sandbox/sandbox_export.h3
-rw-r--r--sandbox/sandbox_linux_unittests.isolate4
-rw-r--r--sandbox/win/BUILD.gn24
-rw-r--r--sandbox/win/OWNERS1
-rw-r--r--sandbox/win/sandbox_poc/pocdll/utils.h3
-rw-r--r--sandbox/win/sandbox_win.gypi65
-rw-r--r--sandbox/win/src/crosscall_client.h133
-rw-r--r--sandbox/win/src/crosscall_params.h77
-rw-r--r--sandbox/win/src/interception_internal.h2
-rw-r--r--sandbox/win/src/internal_types.h10
-rw-r--r--sandbox/win/src/nt_internals.h23
-rw-r--r--sandbox/win/src/policy_engine_params.h12
-rw-r--r--sandbox/win/src/sandbox_factory.h1
-rw-r--r--sandbox/win/src/sandbox_policy.h11
-rw-r--r--sandbox/win/src/sandbox_types.h15
-rw-r--r--sandbox/win/src/security_level.h4
-rw-r--r--sandbox/win/src/sidestep/preamble_patcher_with_stub.cpp2
748 files changed, 22261 insertions, 40279 deletions
diff --git a/Android.mk b/Android.mk
index e4a6c9db53..1596408499 100644
--- a/Android.mk
+++ b/Android.mk
@@ -36,10 +36,9 @@ libchromeCommonCIncludes := \
libchromeExportedCIncludes := $(LOCAL_PATH) $(TOP)/external/gtest/include
libchromeCommonSrc := \
- base/allocator/type_profiler_control.cc \
base/at_exit.cc \
- base/atomicops_internals_x86_gcc.cc \
base/base64.cc \
+ base/base64url.cc \
base/base_switches.cc \
base/bind_helpers.cc \
base/build_time.cc \
@@ -69,9 +68,11 @@ libchromeCommonSrc := \
base/files/scoped_temp_dir.cc \
base/guid.cc \
base/guid_posix.cc \
+ base/json/json_file_value_serializer.cc \
base/json/json_parser.cc \
base/json/json_reader.cc \
base/json/json_string_value_serializer.cc \
+ base/json/json_value_converter.cc \
base/json/json_writer.cc \
base/json/string_escape.cc \
base/lazy_instance.cc \
@@ -84,13 +85,13 @@ libchromeCommonSrc := \
base/memory/weak_ptr.cc \
base/message_loop/incoming_task_queue.cc \
base/message_loop/message_loop.cc \
- base/message_loop/message_loop_proxy.cc \
- base/message_loop/message_loop_proxy_impl.cc \
+ base/message_loop/message_loop_task_runner.cc \
base/message_loop/message_pump.cc \
base/message_loop/message_pump_default.cc \
base/message_loop/message_pump_libevent.cc \
base/metrics/bucket_ranges.cc \
base/metrics/field_trial.cc \
+ base/metrics/metrics_hashes.cc \
base/metrics/histogram_base.cc \
base/metrics/histogram.cc \
base/metrics/histogram_samples.cc \
@@ -122,6 +123,7 @@ libchromeCommonSrc := \
base/sequence_checker_impl.cc \
base/sequenced_task_runner.cc \
base/sha1_portable.cc \
+ base/strings/pattern.cc \
base/strings/safe_sprintf.cc \
base/strings/string16.cc \
base/strings/string_number_conversions.cc \
@@ -168,22 +170,29 @@ libchromeCommonSrc := \
base/time/time_posix.cc \
base/timer/elapsed_timer.cc \
base/timer/timer.cc \
+ base/trace_event/heap_profiler_allocation_context.cc \
+ base/trace_event/heap_profiler_allocation_context_tracker.cc \
+ base/trace_event/heap_profiler_stack_frame_deduplicator.cc \
+ base/trace_event/heap_profiler_type_name_deduplicator.cc \
base/trace_event/memory_allocator_dump.cc \
base/trace_event/memory_allocator_dump_guid.cc \
base/trace_event/memory_dump_manager.cc \
+ base/trace_event/memory_dump_request_args.cc \
base/trace_event/memory_dump_session_state.cc \
base/trace_event/process_memory_dump.cc \
base/trace_event/process_memory_maps.cc \
base/trace_event/process_memory_maps_dump_provider.cc \
base/trace_event/process_memory_totals.cc \
base/trace_event/process_memory_totals_dump_provider.cc \
+ base/trace_event/trace_buffer.cc \
base/trace_event/trace_config.cc \
base/trace_event/trace_event_argument.cc \
base/trace_event/trace_event_impl.cc \
- base/trace_event/trace_event_impl_constants.cc \
- base/trace_event/trace_event_memory.cc \
base/trace_event/trace_event_memory_overhead.cc \
base/trace_event/trace_event_synthetic_delay.cc \
+ base/trace_event/trace_log.cc \
+ base/trace_event/trace_log_constants.cc \
+ base/trace_event/trace_sampling_thread.cc \
base/tracked_objects.cc \
base/tracking_info.cc \
base/values.cc \
@@ -229,6 +238,7 @@ libchromeCommonUnittestSrc := \
base/at_exit_unittest.cc \
base/atomicops_unittest.cc \
base/base64_unittest.cc \
+ base/base64url_unittest.cc \
base/bind_unittest.cc \
base/bits_unittest.cc \
base/build_time_unittest.cc \
@@ -253,6 +263,9 @@ libchromeCommonUnittestSrc := \
base/guid_unittest.cc \
base/id_map_unittest.cc \
base/json/json_parser_unittest.cc \
+ base/json/json_reader_unittest.cc \
+ base/json/json_value_converter_unittest.cc \
+ base/json/json_value_serializer_unittest.cc \
base/json/json_writer_unittest.cc \
base/json/string_escape_unittest.cc \
base/lazy_instance_unittest.cc \
@@ -267,12 +280,12 @@ libchromeCommonUnittestSrc := \
base/memory/singleton_unittest.cc \
base/memory/weak_ptr_unittest.cc \
base/memory/weak_ptr_unittest.nc \
- base/message_loop/message_loop_proxy_impl_unittest.cc \
- base/message_loop/message_loop_proxy_unittest.cc \
base/message_loop/message_loop_test.cc \
+ base/message_loop/message_loop_task_runner_unittest.cc \
base/message_loop/message_loop_unittest.cc \
base/metrics/bucket_ranges_unittest.cc \
base/metrics/field_trial_unittest.cc \
+ base/metrics/metrics_hashes_unittest.cc \
base/metrics/histogram_base_unittest.cc \
base/metrics/histogram_macros_unittest.cc \
base/metrics/histogram_snapshot_manager_unittest.cc \
@@ -281,7 +294,6 @@ libchromeCommonUnittestSrc := \
base/metrics/sample_vector_unittest.cc \
base/metrics/sparse_histogram_unittest.cc \
base/metrics/statistics_recorder_unittest.cc \
- base/move_unittest.cc \
base/numerics/safe_numerics_unittest.cc \
base/observer_list_unittest.cc \
base/pickle_unittest.cc \
@@ -296,6 +308,7 @@ libchromeCommonUnittestSrc := \
base/sequence_checker_unittest \
base/sha1_unittest.cc \
base/stl_util_unittest.cc \
+ base/strings/pattern_unittest.cc \
base/strings/string16_unittest.cc \
base/strings/string_number_conversions_unittest.cc \
base/strings/string_piece_unittest.cc \
@@ -313,16 +326,19 @@ libchromeCommonUnittestSrc := \
base/task/cancelable_task_tracker_unittest.cc \
base/task_runner_util_unittest.cc \
base/template_util_unittest.cc \
+ base/test/multiprocess_test.cc \
base/test/multiprocess_test_android.cc \
base/test/opaque_ref_counted.cc \
base/test/scoped_locale.cc \
base/test/test_file_util.cc \
base/test/test_file_util_linux.cc \
base/test/test_file_util_posix.cc \
+ base/test/test_io_thread.cc \
base/test/test_pending_task.cc \
base/test/test_simple_task_runner.cc \
base/test/test_switches.cc \
base/test/test_timeouts.cc \
+ base/test/trace_event_analyzer.cc \
base/threading/non_thread_safe_unittest.cc \
base/threading/platform_thread_unittest.cc \
base/threading/simple_thread_unittest.cc \
@@ -338,6 +354,9 @@ libchromeCommonUnittestSrc := \
base/time/time_unittest.cc \
base/timer/hi_res_timer_manager_unittest.cc \
base/timer/timer_unittest.cc \
+ base/trace_event/heap_profiler_allocation_context_tracker_unittest.cc \
+ base/trace_event/heap_profiler_stack_frame_deduplicator_unittest.cc \
+ base/trace_event/heap_profiler_type_name_deduplicator_unittest.cc \
base/trace_event/memory_allocator_dump_unittest.cc \
base/trace_event/memory_dump_manager_unittest.cc \
base/trace_event/process_memory_dump_unittest.cc \
@@ -345,7 +364,6 @@ libchromeCommonUnittestSrc := \
base/trace_event/process_memory_totals_dump_provider_unittest.cc \
base/trace_event/trace_config_unittest.cc \
base/trace_event/trace_event_argument_unittest.cc \
- base/trace_event/trace_event_memory_unittest.cc \
base/trace_event/trace_event_synthetic_delay_unittest.cc \
base/trace_event/trace_event_unittest.cc \
base/tracked_objects_unittest.cc \
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 8a32ed63f9..5d8510f1b4 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -2,13 +2,42 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+# HOW TO WRITE CONDITIONALS IN THIS FILE
+# ======================================
+#
+# In many other places, one would write a conditional that expresses all the
+# cases when a source file is used or unused, and then either add or subtract
+# it from the sources list in that case
+#
+# Since base includes so many low-level things that vary widely and
+# unpredictably for the various build types, we prefer a slightly different
+# style. Instead, there are big per-platform blocks of inclusions and
+# exclusions. If a given file has an inclusion or exclusion rule that applies
+# for multiple conditions, perfer to duplicate it in both lists. This makes it
+# a bit easier to see which files apply in which cases rather than having a
+# huge sequence of random-looking conditionals.
+
+import("//build/buildflag_header.gni")
+import("//build/config/compiler/compiler.gni")
+import("//build/config/nacl/config.gni")
import("//build/config/ui.gni")
+import("//build/nocompile.gni")
import("//testing/test.gni")
if (is_android) {
import("//build/config/android/rules.gni")
}
+config("base_flags") {
+ if (is_clang) {
+ cflags = [
+ # Don't die on dtoa code that uses a char as an array index.
+ # This is required solely for base/third_party/dmg_fp/dtoa_wrapper.cc.
+ "-Wno-char-subscripts",
+ ]
+ }
+}
+
config("base_implementation") {
defines = [ "BASE_IMPLEMENTATION" ]
}
@@ -25,47 +54,74 @@ if (is_win) {
}
}
-source_set("base_paths") {
- sources = [
- "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",
- ]
-
- if (is_android || is_mac) {
- sources -= [ "base_paths_posix.cc" ]
+if (is_nacl_nonsfi) {
+ # Must be in a config because of how GN orders flags (otherwise -Wall will
+ # appear after this, and turn it back on).
+ config("nacl_nonsfi_warnings") {
+ # file_util_posix.cc contains a function which is not
+ # being used by nacl_helper_nonsfi.
+ cflags = [ "-Wno-unused-function" ]
}
+}
- if (is_nacl) {
- sources -= [
+if (is_nacl) {
+ # None of the files apply to nacl, and we can't make an empty static library.
+ group("base_paths") {
+ }
+} else {
+ static_library("base_paths") {
+ sources = [
"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",
]
- }
- configs += [ ":base_implementation" ]
+ if (is_android || is_mac || is_ios) {
+ sources -= [ "base_paths_posix.cc" ]
+ }
- deps = [
- "//base/memory",
- "//base/process",
- ]
+ configs += [ ":base_implementation" ]
+
+ visibility = [ ":base" ]
+ }
+}
- visibility = [ ":base" ]
+config("android_system_libs") {
+ libs = [ "log" ] # Used by logging.cc.
}
+# Base and everything it depends on should be a static library rather than
+# a source set. Base is more of a "library" in the classic sense in that many
+# small parts of it are used in many different contexts. This combined with a
+# few static initializers floating around means that dead code stripping
+# still leaves a lot of code behind that isn't always used. For example, this
+# saves more than 40K for a smaller target like chrome_elf.
+#
+# Use static libraries for the helper stuff as well like //base/debug since
+# those things refer back to base code, which will force base compilation units
+# to be linked in where they wouldn't have otherwise. This does not include
+# test code (test support and anything in the test directory) which should use
+# source_set as is recommended for GN targets).
component("base") {
+ # TODO(phosek) bug 570839: If field_trial.cc is in a static library,
+ # hacl_helper_nonsfi doesn't link properly on Linux in debug builds. The
+ # reasons for this seem to involve obscure toolchain bugs. This should be
+ # fixed and this target should always be a static_library in the
+ # non-component case.
+ component_never_use_source_set = !is_nacl_nonsfi
+
sources = [
+ "allocator/allocator_check.cc",
+ "allocator/allocator_check.h",
"allocator/allocator_extension.cc",
"allocator/allocator_extension.h",
- "allocator/type_profiler_control.cc",
- "allocator/type_profiler_control.h",
"android/animation_frame_time_histogram.cc",
"android/animation_frame_time_histogram.h",
"android/apk_assets.cc",
@@ -82,7 +138,10 @@ component("base") {
"android/command_line_android.h",
"android/content_uri_utils.cc",
"android/content_uri_utils.h",
+ "android/context_utils.cc",
+ "android/context_utils.h",
"android/cpu_features.cc",
+ "android/cxa_demangle_stub.cc",
"android/event_log.cc",
"android/event_log.h",
"android/field_trial_list.cc",
@@ -131,28 +190,22 @@ component("base") {
"android/thread_utils.h",
"android/trace_event_binding.cc",
"android/trace_event_binding.h",
- "async_socket_io_handler.h",
- "async_socket_io_handler_posix.cc",
- "async_socket_io_handler_win.cc",
"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_portable.h",
- "atomicops_internals_x86_gcc.cc",
- "atomicops_internals_x86_gcc.h",
"atomicops_internals_x86_msvc.h",
"auto_reset.h",
"barrier_closure.cc",
"barrier_closure.h",
"base64.cc",
"base64.h",
+ "base64url.cc",
+ "base64url.h",
"base_export.h",
"base_switches.h",
- "basictypes.h",
"big_endian.cc",
"big_endian.h",
"bind.h",
@@ -160,6 +213,7 @@ component("base") {
"bind_helpers.h",
"bind_internal.h",
"bind_internal_win.h",
+ "bit_cast.h",
"bits.h",
"build_time.cc",
"build_time.h",
@@ -177,17 +231,51 @@ component("base") {
"containers/linked_list.h",
"containers/mru_cache.h",
"containers/scoped_ptr_hash_map.h",
- "containers/scoped_ptr_map.h",
"containers/small_map.h",
"containers/stack_container.h",
"cpu.cc",
"cpu.h",
"critical_closure.h",
"critical_closure_internal_ios.mm",
+ "debug/alias.cc",
+ "debug/alias.h",
+ "debug/asan_invalid_access.cc",
+ "debug/asan_invalid_access.h",
+ "debug/close_handle_hook_win.cc",
+ "debug/close_handle_hook_win.h",
+ "debug/crash_logging.cc",
+ "debug/crash_logging.h",
+ "debug/debugger.cc",
+ "debug/debugger.h",
+ "debug/debugger_posix.cc",
+ "debug/debugger_win.cc",
+ "debug/dump_without_crashing.cc",
+ "debug/dump_without_crashing.h",
+ "debug/gdi_debug_util_win.cc",
+ "debug/gdi_debug_util_win.h",
+
+ # This file depends on files from the "debug/allocator" target,
+ # but this target does not depend on "debug/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_posix.cc",
+ "debug/stack_trace_win.cc",
+ "debug/task_annotator.cc",
+ "debug/task_annotator.h",
"deferred_sequenced_task_runner.cc",
"deferred_sequenced_task_runner.h",
"environment.cc",
"environment.h",
+ "feature_list.cc",
+ "feature_list.h",
"file_descriptor_posix.h",
"file_version_info.h",
"file_version_info_mac.h",
@@ -248,14 +336,32 @@ component("base") {
"hash.cc",
"hash.h",
"id_map.h",
+ "ios/crb_protocol_observers.h",
+ "ios/crb_protocol_observers.mm",
"ios/device_util.h",
"ios/device_util.mm",
"ios/ios_util.h",
"ios/ios_util.mm",
+ "ios/ns_error_util.h",
+ "ios/ns_error_util.mm",
"ios/scoped_critical_action.h",
"ios/scoped_critical_action.mm",
"ios/weak_nsobject.h",
"ios/weak_nsobject.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.cc",
+ "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",
"linux_util.cc",
@@ -271,6 +377,9 @@ component("base") {
"mac/bind_objc_block.h",
"mac/bundle_locations.h",
"mac/bundle_locations.mm",
+ "mac/call_with_eh_frame.cc",
+ "mac/call_with_eh_frame.h",
+ "mac/call_with_eh_frame_asm.S",
"mac/cocoa_protocols.h",
"mac/dispatch_source_mach.cc",
"mac/dispatch_source_mach.h",
@@ -305,8 +414,6 @@ component("base") {
"mac/scoped_mach_vm.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_objc_class_swizzler.h",
"mac/scoped_objc_class_swizzler.mm",
@@ -317,14 +424,55 @@ component("base") {
"macros.h",
"md5.cc",
"md5.h",
+ "memory/aligned_memory.cc",
+ "memory/aligned_memory.h",
+ "memory/discardable_memory.cc",
+ "memory/discardable_memory.h",
+ "memory/discardable_memory_allocator.cc",
+ "memory/discardable_memory_allocator.h",
+ "memory/discardable_shared_memory.cc",
+ "memory/discardable_shared_memory.h",
+ "memory/linked_ptr.h",
+ "memory/manual_constructor.h",
+ "memory/memory_pressure_listener.cc",
+ "memory/memory_pressure_listener.h",
+ "memory/memory_pressure_monitor.cc",
+ "memory/memory_pressure_monitor.h",
+ "memory/memory_pressure_monitor_chromeos.cc",
+ "memory/memory_pressure_monitor_chromeos.h",
+ "memory/memory_pressure_monitor_mac.cc",
+ "memory/memory_pressure_monitor_mac.h",
+ "memory/memory_pressure_monitor_win.cc",
+ "memory/memory_pressure_monitor_win.h",
+ "memory/ptr_util.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_policy.h",
+ "memory/scoped_ptr.h",
+ "memory/scoped_vector.h",
+ "memory/shared_memory.h",
+ "memory/shared_memory_android.cc",
+ "memory/shared_memory_handle.h",
+ "memory/shared_memory_handle_mac.cc",
+ "memory/shared_memory_handle_win.cc",
+ "memory/shared_memory_mac.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_loop_task_runner.cc",
+ "message_loop/message_loop_task_runner.h",
"message_loop/message_pump.cc",
"message_loop/message_pump.h",
"message_loop/message_pump_android.cc",
@@ -341,6 +489,35 @@ component("base") {
"message_loop/message_pump_mac.mm",
"message_loop/message_pump_win.cc",
"message_loop/message_pump_win.h",
+ "metrics/bucket_ranges.cc",
+ "metrics/bucket_ranges.h",
+ "metrics/field_trial.cc",
+ "metrics/field_trial.h",
+ "metrics/histogram.cc",
+ "metrics/histogram.h",
+ "metrics/histogram_base.cc",
+ "metrics/histogram_base.h",
+ "metrics/histogram_delta_serialization.cc",
+ "metrics/histogram_delta_serialization.h",
+ "metrics/histogram_flattener.h",
+ "metrics/histogram_macros.h",
+ "metrics/histogram_samples.cc",
+ "metrics/histogram_samples.h",
+ "metrics/histogram_snapshot_manager.cc",
+ "metrics/histogram_snapshot_manager.h",
+ "metrics/metrics_hashes.cc",
+ "metrics/metrics_hashes.h",
+ "metrics/sample_map.cc",
+ "metrics/sample_map.h",
+ "metrics/sample_vector.cc",
+ "metrics/sample_vector.h",
+ "metrics/sparse_histogram.cc",
+ "metrics/sparse_histogram.h",
+ "metrics/statistics_recorder.cc",
+ "metrics/statistics_recorder.h",
+ "metrics/user_metrics.cc",
+ "metrics/user_metrics.h",
+ "metrics/user_metrics_action.h",
"move.h",
"native_library.h",
"native_library_ios.mm",
@@ -367,7 +544,6 @@ component("base") {
"pending_task.h",
"pickle.cc",
"pickle.h",
- "port.h",
"posix/eintr_wrapper.h",
"posix/file_descriptor_shuffle.cc",
"posix/global_descriptors.cc",
@@ -390,18 +566,75 @@ component("base") {
"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.cc",
+ "process/launch.h",
+ "process/launch_ios.cc",
+ "process/launch_mac.cc",
+ "process/launch_posix.cc",
+ "process/launch_win.cc",
+ "process/memory.cc",
+ "process/memory.h",
+ "process/memory_linux.cc",
+ "process/memory_mac.mm",
+ "process/memory_win.cc",
+ "process/port_provider_mac.cc",
+ "process/port_provider_mac.h",
+ "process/process.h",
+ "process/process_handle.cc",
+
+ #"process/process_handle_freebsd.cc", # Unused in Chromium build.
+ "process/process_handle_linux.cc",
+ "process/process_handle_mac.cc",
+
+ #"process/process_handle_openbsd.cc", # Unused in Chromium build.
+ "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", # Unused in Chromium build.
+ "process/process_iterator_linux.cc",
+ "process/process_iterator_mac.cc",
+
+ #"process/process_iterator_openbsd.cc", # Unused in Chromium build.
+ "process/process_iterator_win.cc",
+ "process/process_linux.cc",
+ "process/process_metrics.cc",
+ "process/process_metrics.h",
+
+ #"process/process_metrics_freebsd.cc", # Unused in Chromium build.
+ "process/process_metrics_ios.cc",
+ "process/process_metrics_linux.cc",
+ "process/process_metrics_mac.cc",
+
+ #"process/process_metrics_openbsd.cc", # Unused in Chromium build.
+ "process/process_metrics_posix.cc",
+ "process/process_metrics_win.cc",
+ "process/process_posix.cc",
+ "process/process_win.cc",
"profiler/alternate_timer.cc",
"profiler/alternate_timer.h",
"profiler/native_stack_sampler.cc",
"profiler/native_stack_sampler.h",
+ "profiler/native_stack_sampler_posix.cc",
+ "profiler/native_stack_sampler_win.cc",
"profiler/scoped_profile.cc",
"profiler/scoped_profile.h",
"profiler/scoped_tracker.cc",
"profiler/scoped_tracker.h",
"profiler/stack_sampling_profiler.cc",
"profiler/stack_sampling_profiler.h",
- "profiler/stack_sampling_profiler_posix.cc",
- "profiler/stack_sampling_profiler_win.cc",
"profiler/tracked_time.cc",
"profiler/tracked_time.h",
"rand_util.cc",
@@ -430,6 +663,8 @@ component("base") {
"strings/latin1_string_conversions.h",
"strings/nullable_string16.cc",
"strings/nullable_string16.h",
+ "strings/pattern.cc",
+ "strings/pattern.h",
"strings/safe_sprintf.cc",
"strings/safe_sprintf.h",
"strings/string16.cc",
@@ -486,11 +721,13 @@ component("base") {
"sys_info.h",
"sys_info_android.cc",
"sys_info_chromeos.cc",
- "sys_info_freebsd.cc",
+
+ #"sys_info_freebsd.cc", # Unused in Chromium build.
"sys_info_ios.mm",
"sys_info_linux.cc",
"sys_info_mac.cc",
- "sys_info_openbsd.cc",
+
+ #"sys_info_openbsd.cc", # Unused in Chromium build.
"sys_info_posix.cc",
"sys_info_win.cc",
"system_monitor/system_monitor.cc",
@@ -524,6 +761,8 @@ component("base") {
"threading/platform_thread_win.cc",
"threading/post_task_and_reply_impl.cc",
"threading/post_task_and_reply_impl.h",
+ "threading/sequenced_task_runner_handle.cc",
+ "threading/sequenced_task_runner_handle.h",
"threading/sequenced_worker_pool.cc",
"threading/sequenced_worker_pool.h",
"threading/simple_thread.cc",
@@ -576,6 +815,70 @@ component("base") {
"timer/mock_timer.h",
"timer/timer.cc",
"timer/timer.h",
+ "trace_event/common/trace_event_common.h",
+ "trace_event/heap_profiler_allocation_context.cc",
+ "trace_event/heap_profiler_allocation_context.h",
+ "trace_event/heap_profiler_allocation_context_tracker.cc",
+ "trace_event/heap_profiler_allocation_context_tracker.h",
+ "trace_event/heap_profiler_allocation_register.cc",
+ "trace_event/heap_profiler_allocation_register.h",
+ "trace_event/heap_profiler_allocation_register_posix.cc",
+ "trace_event/heap_profiler_allocation_register_win.cc",
+ "trace_event/heap_profiler_heap_dump_writer.cc",
+ "trace_event/heap_profiler_heap_dump_writer.h",
+ "trace_event/heap_profiler_stack_frame_deduplicator.cc",
+ "trace_event/heap_profiler_stack_frame_deduplicator.h",
+ "trace_event/heap_profiler_type_name_deduplicator.cc",
+ "trace_event/heap_profiler_type_name_deduplicator.h",
+ "trace_event/java_heap_dump_provider_android.cc",
+ "trace_event/java_heap_dump_provider_android.h",
+ "trace_event/memory_allocator_dump.cc",
+ "trace_event/memory_allocator_dump.h",
+ "trace_event/memory_allocator_dump_guid.cc",
+ "trace_event/memory_allocator_dump_guid.h",
+ "trace_event/memory_dump_manager.cc",
+ "trace_event/memory_dump_manager.h",
+ "trace_event/memory_dump_provider.h",
+ "trace_event/memory_dump_request_args.cc",
+ "trace_event/memory_dump_request_args.h",
+ "trace_event/memory_dump_session_state.cc",
+ "trace_event/memory_dump_session_state.h",
+ "trace_event/process_memory_dump.cc",
+ "trace_event/process_memory_dump.h",
+ "trace_event/process_memory_maps.cc",
+ "trace_event/process_memory_maps.h",
+ "trace_event/process_memory_maps_dump_provider.h",
+ "trace_event/process_memory_totals.cc",
+ "trace_event/process_memory_totals.h",
+ "trace_event/process_memory_totals_dump_provider.cc",
+ "trace_event/process_memory_totals_dump_provider.h",
+ "trace_event/trace_buffer.cc",
+ "trace_event/trace_buffer.h",
+ "trace_event/trace_config.cc",
+ "trace_event/trace_config.h",
+ "trace_event/trace_event.h",
+ "trace_event/trace_event_android.cc",
+ "trace_event/trace_event_argument.cc",
+ "trace_event/trace_event_argument.h",
+ "trace_event/trace_event_etw_export_win.cc",
+ "trace_event/trace_event_etw_export_win.h",
+ "trace_event/trace_event_impl.cc",
+ "trace_event/trace_event_impl.h",
+ "trace_event/trace_event_memory_overhead.cc",
+ "trace_event/trace_event_memory_overhead.h",
+ "trace_event/trace_event_synthetic_delay.cc",
+ "trace_event/trace_event_synthetic_delay.h",
+ "trace_event/trace_event_system_stats_monitor.cc",
+ "trace_event/trace_event_system_stats_monitor.h",
+ "trace_event/trace_log.cc",
+ "trace_event/trace_log.h",
+ "trace_event/trace_log_constants.cc",
+ "trace_event/trace_sampling_thread.cc",
+ "trace_event/trace_sampling_thread.h",
+ "trace_event/tracing_agent.cc",
+ "trace_event/tracing_agent.h",
+ "trace_event/winheap_dump_provider_win.cc",
+ "trace_event/winheap_dump_provider_win.h",
"tracked_objects.cc",
"tracked_objects.h",
"tracking_info.cc",
@@ -604,10 +907,10 @@ component("base") {
"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/process_startup_helper.cc",
+ "win/process_startup_helper.h",
"win/registry.cc",
"win/registry.h",
"win/resource_util.cc",
@@ -640,98 +943,151 @@ component("base") {
"win/wrapped_window_proc.h",
]
- sources -= [
- "sys_info_freebsd.cc",
- "sys_info_openbsd.cc",
- ]
+ defines = []
+ data = []
- configs += [ ":base_implementation" ]
+ configs += [
+ ":base_flags",
+ ":base_implementation",
+ "//base/allocator:allocator_shim_define", # for allocator_check.cc.
+ "//build/config:precompiled_headers",
+ ]
deps = [
- ":base_static",
- "//base/allocator:allocator_extension_thunks",
"//base/third_party/dynamic_annotations",
"//third_party/modp_b64",
]
public_deps = [
":base_paths",
- "//base/debug",
- "//base/json",
- "//base/memory",
- "//base/metrics",
- "//base/process",
- "//base/trace_event",
+ ":base_static",
+ ":debugging_flags",
]
# Allow more direct string conversions on platforms with native utf8
# strings
if (is_mac || is_ios || is_chromeos) {
- defines = [ "SYSTEM_NATIVE_UTF8" ]
+ defines += [ "SYSTEM_NATIVE_UTF8" ]
}
+ # Android.
if (is_android) {
- sources -= [ "power_monitor/power_monitor_device_source_posix.cc" ]
+ sources -= [
+ "debug/stack_trace_posix.cc",
+ "power_monitor/power_monitor_device_source_posix.cc",
+ ]
# Android uses some Linux sources, put those back.
set_sources_assignment_filter([])
sources += [
+ "debug/proc_maps_linux.cc",
"files/file_path_watcher_linux.cc",
"posix/unix_domain_socket_linux.cc",
+ "process/internal_linux.cc",
+ "process/memory_linux.cc",
+ "process/process_handle_linux.cc",
+ "process/process_iterator_linux.cc",
+ "process/process_metrics_linux.cc",
"sys_info_linux.cc",
+ "trace_event/malloc_dump_provider.cc",
+ "trace_event/malloc_dump_provider.h",
+ "trace_event/process_memory_maps_dump_provider.cc",
]
set_sources_assignment_filter(sources_assignment_filter)
deps += [
":base_jni_headers",
- "//third_party/ashmem",
"//third_party/android_tools:cpu_features",
+ "//third_party/ashmem",
]
- # logging.cc uses the Android logging library.
- libs = [ "log" ]
+ # Needs to be a public config so that dependent targets link against it as
+ # well when doing a component build.
+ public_configs = [ ":android_system_libs" ]
}
+ # Chromeos.
if (is_chromeos) {
sources -= [ "power_monitor/power_monitor_device_source_posix.cc" ]
}
+ # NaCl.
if (is_nacl) {
# We reset sources_assignment_filter in order to explicitly include
# the linux file (which would otherwise be filtered out).
set_sources_assignment_filter([])
sources += [
"files/file_path_watcher_stub.cc",
+ "process/process_metrics_nacl.cc",
"sync_socket_nacl.cc",
"threading/platform_thread_linux.cc",
]
set_sources_assignment_filter(sources_assignment_filter)
sources -= [
- "allocator/type_profiler_control.cc",
- "allocator/type_profiler_control.h",
- "async_socket_io_handler_posix.cc",
"cpu.cc",
+ "debug/crash_logging.cc",
+ "debug/crash_logging.h",
+ "debug/stack_trace.cc",
+ "debug/stack_trace_posix.cc",
"files/file_enumerator_posix.cc",
"files/file_proxy.cc",
- "files/file_util.cc",
- "files/file_util_posix.cc",
"files/file_util_proxy.cc",
"files/important_file_writer.cc",
"files/important_file_writer.h",
"files/scoped_temp_dir.cc",
- "message_loop/message_pump_libevent.cc",
+ "memory/discardable_memory.cc",
+ "memory/discardable_memory.h",
+ "memory/discardable_memory_allocator.cc",
+ "memory/discardable_memory_allocator.h",
+ "memory/discardable_shared_memory.cc",
+ "memory/discardable_shared_memory.h",
+ "memory/shared_memory_posix.cc",
"native_library_posix.cc",
"path_service.cc",
- "rand_util_posix.cc",
+ "process/kill.cc",
+ "process/kill.h",
+ "process/memory.cc",
+ "process/memory.h",
+ "process/process_iterator.cc",
+ "process/process_iterator.h",
+ "process/process_metrics.cc",
+ "process/process_metrics_posix.cc",
+ "process/process_posix.cc",
"scoped_native_library.cc",
"sync_socket_posix.cc",
"sys_info.cc",
"sys_info_posix.cc",
+ "trace_event/process_memory_totals_dump_provider.cc",
+ "trace_event/trace_event_system_stats_monitor.cc",
]
+
+ if (is_nacl_nonsfi) {
+ set_sources_assignment_filter([])
+ sources += [ "posix/unix_domain_socket_linux.cc" ]
+ set_sources_assignment_filter(sources_assignment_filter)
+ sources -= [ "rand_util_nacl.cc" ]
+ configs += [ ":nacl_nonsfi_warnings" ]
+ } else {
+ sources -= [
+ "files/file_util.cc",
+ "files/file_util.h",
+ "files/file_util_posix.cc",
+ "json/json_file_value_serializer.cc",
+ "json/json_file_value_serializer.h",
+ "message_loop/message_pump_libevent.cc",
+ "message_loop/message_pump_libevent.h",
+ "process/kill_posix.cc",
+ "process/launch.cc",
+ "process/launch.h",
+ "process/launch_posix.cc",
+ "rand_util_posix.cc",
+ ]
+ }
} else {
# Remove NaCl stuff.
sources -= [
+ "memory/shared_memory_nacl.cc",
"os_compat_nacl.cc",
"os_compat_nacl.h",
"rand_util_nacl.cc",
@@ -740,6 +1096,11 @@ component("base") {
# Windows.
if (is_win) {
+ sources += [
+ "profiler/win32_stack_frame_unwinder.cc",
+ "profiler/win32_stack_frame_unwinder.h",
+ ]
+
sources -= [
"message_loop/message_pump_libevent.cc",
"strings/string16.cc",
@@ -749,6 +1110,32 @@ component("base") {
"sha1_win.cc",
]
+ # Required for base/stack_trace_win.cc to symbolize correctly.
+ data += [ "$root_build_dir/dbghelp.dll" ]
+
+ deps += [ "//base/trace_event/etw_manifest:chrome_events_win" ]
+
+ if (is_component_build) {
+ # Copy the VS runtime DLLs into the isolate so that they don't have to be
+ # preinstalled on the target machine. The debug runtimes have a "d" at
+ # the end.
+ if (is_debug) {
+ vcrt_suffix = "d"
+ } else {
+ vcrt_suffix = ""
+ }
+
+ # These runtime files are copied to the output directory by the
+ # vs_toolchain script that runs as part of toolchain configuration.
+ data += [
+ "$root_out_dir/msvcp120${vcrt_suffix}.dll",
+ "$root_out_dir/msvcr120${vcrt_suffix}.dll",
+ ]
+ if (is_asan) {
+ data += [ "//third_party/llvm-build/Release+Asserts/lib/clang/3.8.0/lib/windows/clang_rt.asan_dynamic-i386.dll" ]
+ }
+ }
+
# TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
@@ -759,20 +1146,34 @@ component("base") {
"setupapi.lib",
]
all_dependent_configs = [ ":base_win_linker_flags" ]
- } else if (!is_nacl) {
+ } else if (!is_nacl || is_nacl_nonsfi) {
# Non-Windows.
- deps += [ "//third_party/libevent" ]
+ deps += [ "//base/third_party/libevent" ]
}
- # Mac.
+ # Desktop Mac.
if (is_mac) {
+ sources += [
+ "trace_event/malloc_dump_provider.cc",
+ "trace_event/malloc_dump_provider.h",
+ ]
+ }
+
+ # Mac or iOS.
+ if (is_mac || is_ios) {
sources -= [
+ "memory/shared_memory_posix.cc",
"native_library_posix.cc",
"strings/sys_string_conversions_posix.cc",
"threading/platform_thread_internal_posix.cc",
]
+
+ if (is_asan) {
+ # TODO(GYP) hook up asan on Mac. GYP has this extra dylib:
+ #data += [ "$root_out_dir/libclang_rt.asan_osx_dynamic.dylib" ]
+ }
} else {
- # Non-Mac.
+ # Non-Mac/ios.
sources -= [
"files/file_path_watcher_fsevents.cc",
"files/file_path_watcher_fsevents.h",
@@ -783,18 +1184,32 @@ component("base") {
# Linux.
if (is_linux) {
+ sources += [
+ "trace_event/malloc_dump_provider.cc",
+ "trace_event/malloc_dump_provider.h",
+ "trace_event/process_memory_maps_dump_provider.cc",
+ ]
+
+ if (is_asan || is_lsan || is_msan || is_tsan) {
+ # For llvm-sanitizer.
+ data += [ "//third_party/llvm-build/Release+Asserts/lib/libstdc++.so.6" ]
+ }
+
# TODO(brettw) this will need to be parameterized at some point.
linux_configs = []
if (use_glib) {
linux_configs += [ "//build/config/linux:glib" ]
}
+ defines += [ "USE_SYMBOLIZE" ]
+
configs += linux_configs
all_dependent_configs = linux_configs
# These dependencies are not required on Android, and in the case
# of xdg_mime must be excluded due to licensing restrictions.
deps += [
+ "//base/third_party/symbolize",
"//base/third_party/xdg_mime",
"//base/third_party/xdg_user_dirs",
]
@@ -815,6 +1230,74 @@ component("base") {
}
}
+ # iOS
+ if (is_ios) {
+ set_sources_assignment_filter([])
+
+ sources -= [
+ "files/file_path_watcher.cc",
+ "files/file_path_watcher.h",
+ "files/file_path_watcher_fsevents.cc",
+ "files/file_path_watcher_fsevents.h",
+ "files/file_path_watcher_kqueue.cc",
+ "files/file_path_watcher_kqueue.h",
+ "memory/discardable_shared_memory.cc",
+ "memory/discardable_shared_memory.h",
+ "message_loop/message_pump_libevent.cc",
+ "message_loop/message_pump_libevent.h",
+ "process/kill.cc",
+ "process/kill.h",
+ "process/kill_posix.cc",
+ "process/launch.cc",
+ "process/launch.h",
+ "process/launch_posix.cc",
+ "process/memory.cc",
+ "process/memory.h",
+ "process/process_iterator.cc",
+ "process/process_iterator.h",
+ "process/process_metrics_posix.cc",
+ "process/process_posix.cc",
+ "sync_socket.h",
+ "sync_socket_posix.cc",
+ ]
+ sources += [
+ "base_paths_mac.h",
+ "base_paths_mac.mm",
+ "file_version_info_mac.h",
+ "file_version_info_mac.mm",
+ "files/file_util_mac.mm",
+ "mac/bundle_locations.h",
+ "mac/bundle_locations.mm",
+ "mac/call_with_eh_frame.cc",
+ "mac/call_with_eh_frame.h",
+ "mac/foundation_util.h",
+ "mac/foundation_util.mm",
+ "mac/mac_logging.cc",
+ "mac/mac_logging.h",
+ "mac/mach_logging.cc",
+ "mac/mach_logging.h",
+ "mac/objc_property_releaser.h",
+ "mac/objc_property_releaser.mm",
+ "mac/scoped_mach_port.cc",
+ "mac/scoped_mach_port.h",
+ "mac/scoped_mach_vm.cc",
+ "mac/scoped_mach_vm.h",
+ "mac/scoped_nsautorelease_pool.h",
+ "mac/scoped_nsautorelease_pool.mm",
+ "mac/scoped_nsobject.h",
+ "mac/scoped_objc_class_swizzler.h",
+ "mac/scoped_objc_class_swizzler.mm",
+ "message_loop/message_pump_mac.h",
+ "message_loop/message_pump_mac.mm",
+ "process/memory_stubs.cc",
+ "strings/sys_string_conversions_mac.mm",
+ "threading/platform_thread_mac.mm",
+ "time/time_mac.cc",
+ ]
+
+ set_sources_assignment_filter(sources_assignment_filter)
+ }
+
if (!use_glib) {
sources -= [
"message_loop/message_pump_glib.cc",
@@ -822,19 +1305,35 @@ component("base") {
]
}
+ if (is_asan || is_lsan || is_msan || is_tsan) {
+ data += [ "//tools/valgrind/asan/" ]
+ if (is_win) {
+ data +=
+ [ "//third_party/llvm-build/Release+Asserts/bin/llvm-symbolizer.exe" ]
+ } else {
+ data += [ "//third_party/llvm-build/Release+Asserts/bin/llvm-symbolizer" ]
+ }
+ }
+
configs += [ "//build/config/compiler:wexit_time_destructors" ]
- if (is_android && !is_debug) {
- configs -= [ "//build/config/compiler:optimize" ]
+ if (!is_debug) {
+ configs -= [ "//build/config/compiler:default_optimization" ]
configs += [ "//build/config/compiler:optimize_max" ]
}
allow_circular_includes_from = public_deps
}
+buildflag_header("debugging_flags") {
+ header = "debugging_flags.h"
+ header_dir = "base/debug"
+ flags = [ "ENABLE_PROFILING=$enable_profiling" ]
+}
+
# 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.
-source_set("base_static") {
+static_library("base_static") {
sources = [
"base_switches.cc",
"base_switches.h",
@@ -842,8 +1341,8 @@ source_set("base_static") {
"win/pe_image.h",
]
- if (is_android && !is_debug) {
- configs -= [ "//build/config/compiler:optimize" ]
+ if (!is_debug) {
+ configs -= [ "//build/config/compiler:default_optimization" ]
configs += [ "//build/config/compiler:optimize_max" ]
}
}
@@ -852,6 +1351,8 @@ component("i18n") {
output_name = "base_i18n"
sources = [
"i18n/base_i18n_export.h",
+ "i18n/base_i18n_switches.cc",
+ "i18n/base_i18n_switches.h",
"i18n/bidi_line_iterator.cc",
"i18n/bidi_line_iterator.h",
"i18n/break_iterator.cc",
@@ -870,6 +1371,8 @@ component("i18n") {
"i18n/icu_string_conversions.h",
"i18n/icu_util.cc",
"i18n/icu_util.h",
+ "i18n/message_formatter.cc",
+ "i18n/message_formatter.h",
"i18n/number_formatting.cc",
"i18n/number_formatting.h",
"i18n/rtl.cc",
@@ -889,14 +1392,16 @@ component("i18n") {
]
defines = [ "BASE_I18N_IMPLEMENTATION" ]
configs += [ "//build/config/compiler:wexit_time_destructors" ]
+ public_deps = [
+ "//third_party/icu",
+ ]
deps = [
":base",
"//base/third_party/dynamic_annotations",
- "//third_party/icu",
]
- if (is_android && !is_debug) {
- configs -= [ "//build/config/compiler:optimize" ]
+ if (!is_debug) {
+ configs -= [ "//build/config/compiler:default_optimization" ]
configs += [ "//build/config/compiler:optimize_max" ]
}
@@ -904,7 +1409,7 @@ component("i18n") {
configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
}
-if (is_win || (is_linux && !is_chromeos)) {
+if (is_ios || is_android || is_win || (is_linux && !is_chromeos)) {
# TODO(GYP): Figure out which of these work and are needed on other platforms.
test("base_perftests") {
sources = [
@@ -917,8 +1422,8 @@ if (is_win || (is_linux && !is_chromeos)) {
":base",
"//base/test:test_support",
"//base/test:test_support_perf",
- "//testing/perf",
"//testing/gtest",
+ "//testing/perf",
]
if (is_android) {
@@ -946,6 +1451,7 @@ if (is_win || (is_linux && !is_chromeos)) {
]
deps = [
":base",
+ "//build/config/sanitizers:deps",
"//third_party/icu:icuuc",
]
}
@@ -956,6 +1462,7 @@ if (is_win || (is_linux && !is_chromeos)) {
]
deps = [
":base",
+ "//build/config/sanitizers:deps",
]
}
}
@@ -963,23 +1470,18 @@ if (is_win || (is_linux && !is_chromeos)) {
component("prefs") {
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_filter.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",
@@ -998,8 +1500,17 @@ component("prefs") {
"prefs/scoped_user_pref_update.h",
"prefs/value_map_pref_store.cc",
"prefs/value_map_pref_store.h",
- "prefs/writeable_pref_store.h",
]
+ if (!is_ios) {
+ sources += [
+ "prefs/base_prefs_export.h",
+ "prefs/persistent_pref_store.h",
+ "prefs/pref_filter.h",
+ "prefs/pref_notifier.h",
+ "prefs/pref_observer.h",
+ "prefs/writeable_pref_store.h",
+ ]
+ }
defines = [ "BASE_PREFS_IMPLEMENTATION" ]
@@ -1007,8 +1518,8 @@ component("prefs") {
":base",
]
- if (is_android && !is_debug) {
- configs -= [ "//build/config/compiler:optimize" ]
+ if (!is_debug) {
+ configs -= [ "//build/config/compiler:default_optimization" ]
configs += [ "//build/config/compiler:optimize_max" ]
}
}
@@ -1065,11 +1576,36 @@ if (is_win) {
"cfgmgr32.lib",
"shell32.lib",
]
+ deps = [
+ "//build/config/sanitizers:deps",
+ ]
}
+
+ if (target_cpu == "x64") {
+ # Must be a shared library so that it can be unloaded during testing.
+ shared_library("base_profiler_test_support_library") {
+ sources = [
+ "profiler/test_support_library.cc",
+ ]
+ deps = [
+ "//build/config/sanitizers:deps",
+ ]
+ }
+ }
+}
+
+# TODO(GYP): Delete this after we've converted everything to GN.
+# The _run targets exist only for compatibility w/ GYP.
+group("base_unittests_run") {
+ testonly = true
+ deps = [
+ ":base_unittests",
+ ]
}
test("base_unittests") {
sources = [
+ "allocator/tcmalloc_unittest.cc",
"android/application_status_listener_unittest.cc",
"android/content_uri_utils_unittest.cc",
"android/jni_android_unittest.cc",
@@ -1079,21 +1615,18 @@ test("base_unittests") {
"android/path_utils_unittest.cc",
"android/scoped_java_ref_unittest.cc",
"android/sys_utils_unittest.cc",
- "async_socket_io_handler_unittest.cc",
"at_exit_unittest.cc",
"atomicops_unittest.cc",
"barrier_closure_unittest.cc",
"base64_unittest.cc",
+ "base64url_unittest.cc",
"big_endian_unittest.cc",
"bind_unittest.cc",
- "bind_unittest.nc",
"bits_unittest.cc",
"build_time_unittest.cc",
"callback_helpers_unittest.cc",
"callback_list_unittest.cc",
- "callback_list_unittest.nc",
"callback_unittest.cc",
- "callback_unittest.nc",
"cancelable_callback_unittest.cc",
"command_line_unittest.cc",
"containers/adapters_unittest.cc",
@@ -1101,7 +1634,6 @@ test("base_unittests") {
"containers/linked_list_unittest.cc",
"containers/mru_cache_unittest.cc",
"containers/scoped_ptr_hash_map_unittest.cc",
- "containers/scoped_ptr_map_unittest.cc",
"containers/small_map_unittest.cc",
"containers/stack_container_unittest.cc",
"cpu_unittest.cc",
@@ -1115,6 +1647,7 @@ test("base_unittests") {
"environment_unittest.cc",
"file_version_info_unittest.cc",
"files/dir_reader_posix_unittest.cc",
+ "files/file_locking_unittest.cc",
"files/file_path_unittest.cc",
"files/file_path_watcher_unittest.cc",
"files/file_proxy_unittest.cc",
@@ -1122,6 +1655,7 @@ test("base_unittests") {
"files/file_util_proxy_unittest.cc",
"files/file_util_unittest.cc",
"files/important_file_writer_unittest.cc",
+ "files/memory_mapped_file_unittest.cc",
"files/scoped_temp_dir_unittest.cc",
"gmock_unittest.cc",
"guid_unittest.cc",
@@ -1131,6 +1665,7 @@ test("base_unittests") {
"i18n/char_iterator_unittest.cc",
"i18n/file_util_icu_unittest.cc",
"i18n/icu_string_conversions_unittest.cc",
+ "i18n/message_formatter_unittest.cc",
"i18n/number_formatting_unittest.cc",
"i18n/rtl_unittest.cc",
"i18n/streaming_utf8_validator_unittest.cc",
@@ -1149,6 +1684,7 @@ test("base_unittests") {
"lazy_instance_unittest.cc",
"logging_unittest.cc",
"mac/bind_objc_block_unittest.mm",
+ "mac/call_with_eh_frame_unittest.mm",
"mac/dispatch_source_mach_unittest.cc",
"mac/foundation_util_unittest.mm",
"mac/libdispatch_task_runner_unittest.cc",
@@ -1163,17 +1699,16 @@ test("base_unittests") {
"memory/linked_ptr_unittest.cc",
"memory/memory_pressure_monitor_chromeos_unittest.cc",
"memory/memory_pressure_monitor_win_unittest.cc",
+ "memory/ptr_util_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_mac_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_task_runner_unittest.cc",
"message_loop/message_loop_unittest.cc",
"message_loop/message_pump_glib_unittest.cc",
"message_loop/message_pump_io_ios_unittest.cc",
@@ -1181,13 +1716,15 @@ test("base_unittests") {
"metrics/field_trial_unittest.cc",
"metrics/histogram_base_unittest.cc",
"metrics/histogram_delta_serialization_unittest.cc",
+ "metrics/histogram_macros_unittest.cc",
"metrics/histogram_snapshot_manager_unittest.cc",
"metrics/histogram_unittest.cc",
+ "metrics/metrics_hashes_unittest.cc",
"metrics/sample_map_unittest.cc",
"metrics/sample_vector_unittest.cc",
"metrics/sparse_histogram_unittest.cc",
"metrics/statistics_recorder_unittest.cc",
- "move_unittest.cc",
+ "native_library_unittest.cc",
"numerics/safe_numerics_unittest.cc",
"observer_list_unittest.cc",
"os_compat_android_unittest.cc",
@@ -1213,7 +1750,6 @@ test("base_unittests") {
"process/process_metrics_unittest_ios.cc",
"process/process_unittest.cc",
"process/process_util_unittest.cc",
- "process/process_util_unittest_ios.cc",
"profiler/stack_sampling_profiler_unittest.cc",
"profiler/tracked_time_unittest.cc",
"rand_util_unittest.cc",
@@ -1225,6 +1761,7 @@ test("base_unittests") {
"sha1_unittest.cc",
"stl_util_unittest.cc",
"strings/nullable_string16_unittest.cc",
+ "strings/pattern_unittest.cc",
"strings/safe_sprintf_unittest.cc",
"strings/string16_unittest.cc",
"strings/string_number_conversions_unittest.cc",
@@ -1250,14 +1787,16 @@ test("base_unittests") {
"task/cancelable_task_tracker_unittest.cc",
"task_runner_util_unittest.cc",
"template_util_unittest.cc",
- "test/expectations/expectation_unittest.cc",
- "test/expectations/parser_unittest.cc",
"test/histogram_tester_unittest.cc",
+ "test/icu_test_util.cc",
+ "test/icu_test_util.h",
+ "test/test_pending_task_unittest.cc",
"test/test_reg_util_win_unittest.cc",
"test/trace_event_analyzer_unittest.cc",
"test/user_action_tester_unittest.cc",
"threading/non_thread_safe_unittest.cc",
"threading/platform_thread_unittest.cc",
+ "threading/sequenced_task_runner_handle_unittest.cc",
"threading/sequenced_worker_pool_unittest.cc",
"threading/simple_thread_unittest.cc",
"threading/thread_checker_unittest.cc",
@@ -1276,6 +1815,23 @@ test("base_unittests") {
"timer/mock_timer_unittest.cc",
"timer/timer_unittest.cc",
"tools_sanity_unittest.cc",
+ "trace_event/heap_profiler_allocation_context_tracker_unittest.cc",
+ "trace_event/heap_profiler_allocation_register_unittest.cc",
+ "trace_event/heap_profiler_heap_dump_writer_unittest.cc",
+ "trace_event/heap_profiler_stack_frame_deduplicator_unittest.cc",
+ "trace_event/heap_profiler_type_name_deduplicator_unittest.cc",
+ "trace_event/java_heap_dump_provider_android_unittest.cc",
+ "trace_event/memory_allocator_dump_unittest.cc",
+ "trace_event/memory_dump_manager_unittest.cc",
+ "trace_event/process_memory_dump_unittest.cc",
+ "trace_event/process_memory_totals_dump_provider_unittest.cc",
+ "trace_event/trace_config_memory_test_util.h",
+ "trace_event/trace_config_unittest.cc",
+ "trace_event/trace_event_argument_unittest.cc",
+ "trace_event/trace_event_synthetic_delay_unittest.cc",
+ "trace_event/trace_event_system_stats_monitor_unittest.cc",
+ "trace_event/trace_event_unittest.cc",
+ "trace_event/winheap_dump_provider_win_unittest.cc",
"tracked_objects_unittest.cc",
"tuple_unittest.cc",
"values_unittest.cc",
@@ -1294,6 +1850,7 @@ test("base_unittests") {
"win/registry_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",
@@ -1312,7 +1869,6 @@ test("base_unittests") {
"//base/test:run_all_unittests",
"//base/test:test_support",
"//base/third_party/dynamic_annotations",
- "//base/trace_event:trace_event_unittests",
"//testing/gmock",
"//testing/gtest",
"//third_party/icu",
@@ -1320,9 +1876,6 @@ test("base_unittests") {
data = [
"test/data/",
-
- # TODO(dpranke): Remove when icu declares this directly.
- "$root_out_dir/icudtl.dat",
]
# Allow more direct string conversions on platforms with native utf8
@@ -1332,20 +1885,27 @@ test("base_unittests") {
}
if (is_android) {
- apk_deps = [
+ deps += [
":base_java",
":base_java_unittest_support",
+ "//base/android/jni_generator:jni_generator_tests",
]
+
+ # TODO(brettw) I think this should not be here, we should not be using
+ # isolate files.
isolate_file = "base_unittests.isolate"
}
if (is_ios) {
sources -= [
+ "files/file_locking_unittest.cc",
+ "files/file_path_watcher_unittest.cc",
+ "memory/discardable_shared_memory_unittest.cc",
+ "memory/shared_memory_unittest.cc",
"process/memory_unittest.cc",
- "process/memory_unittest_mac.h",
- "process/memory_unittest_mac.mm",
"process/process_unittest.cc",
"process/process_util_unittest.cc",
+ "sync_socket_unittest.cc",
]
# Pull in specific Mac files for iOS (which have been filtered out by file
@@ -1356,7 +1916,7 @@ test("base_unittests") {
"mac/foundation_util_unittest.mm",
"mac/objc_property_releaser_unittest.mm",
"mac/scoped_nsobject_unittest.mm",
- "sys_string_conversions_mac_unittest.mm",
+ "strings/sys_string_conversions_mac_unittest.mm",
]
set_sources_assignment_filter(sources_assignment_filter)
@@ -1366,31 +1926,76 @@ test("base_unittests") {
if (is_linux) {
sources -= [ "file_version_info_unittest.cc" ]
sources += [ "nix/xdg_util_unittest.cc" ]
+
deps += [ "//base/test:malloc_wrapper" ]
if (use_glib) {
configs += [ "//build/config/linux:glib" ]
}
+
+ if (!is_component_build) {
+ # Set rpath to find libmalloc_wrapper.so even in a non-component build.
+ configs += [ "//build/config/gcc:rpath_for_built_shared_libraries" ]
+ }
+ }
+
+ if (is_linux || is_android) {
+ sources += [ "trace_event/process_memory_maps_dump_provider_unittest.cc" ]
}
if (!is_linux || use_ozone) {
sources -= [ "message_loop/message_pump_glib_unittest.cc" ]
}
- if (is_posix || is_ios) {
+ if (is_posix && !is_ios) {
sources += [ "message_loop/message_pump_libevent_unittest.cc" ]
- deps += [ "//third_party/libevent" ]
+ deps += [ "//base/third_party/libevent" ]
}
if (is_android) {
deps += [ "//testing/android/native_test:native_test_native_code" ]
set_sources_assignment_filter([])
- sources += [ "debug/proc_maps_linux_unittest.cc" ]
+ sources += [
+ "debug/proc_maps_linux_unittest.cc",
+ "trace_event/trace_event_android_unittest.cc",
+ ]
set_sources_assignment_filter(sources_assignment_filter)
}
+ if (is_win && target_cpu == "x64") {
+ sources += [ "profiler/win32_stack_frame_unwinder_unittest.cc" ]
+ deps += [ ":base_profiler_test_support_library" ]
+ }
+
# TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
+
+ # Symbols for crashes when running tests on swarming.
+ if (symbol_level > 0) {
+ if (is_win) {
+ data += [ "$root_out_dir/base_unittests.exe.pdb" ]
+ } else if (is_mac) {
+ data += [ "$root_out_dir/base_unittests.dSYM/" ]
+ }
+ }
+}
+
+if (enable_nocompile_tests) {
+ nocompile_test("base_nocompile_tests") {
+ sources = [
+ "bind_unittest.nc",
+ "callback_list_unittest.nc",
+ "callback_unittest.nc",
+ "memory/scoped_ptr_unittest.nc",
+ "memory/weak_ptr_unittest.nc",
+ ]
+
+ deps = [
+ ":base",
+ "//base/test:run_all_unittests",
+ "//testing/gtest",
+ ]
+ }
}
if (is_android) {
@@ -1403,6 +2008,7 @@ if (is_android) {
"android/java/src/org/chromium/base/BuildInfo.java",
"android/java/src/org/chromium/base/CommandLine.java",
"android/java/src/org/chromium/base/ContentUriUtils.java",
+ "android/java/src/org/chromium/base/ContextUtils.java",
"android/java/src/org/chromium/base/CpuFeatures.java",
"android/java/src/org/chromium/base/EventLog.java",
"android/java/src/org/chromium/base/FieldTrialList.java",
@@ -1423,7 +2029,7 @@ if (is_android) {
"android/java/src/org/chromium/base/metrics/RecordUserAction.java",
]
- deps = [
+ public_deps = [
":android_runtime_jni_headers",
]
@@ -1440,10 +2046,12 @@ if (is_android) {
android_library("base_java") {
srcjar_deps = [
":base_android_java_enums_srcjar",
+ ":base_multidex_gen",
":base_native_libraries_gen",
]
deps = [
+ "//third_party/android_tools:android_support_multidex_java",
"//third_party/jsr-305:jsr_305_javalib",
]
@@ -1475,12 +2083,30 @@ if (is_android) {
DEPRECATED_java_in_dir = "test/android/javatests/src"
}
+ # TODO(jbudorick): Remove this once we roll to robolectric 3.0 and pull
+ # in the multidex shadow library. crbug.com/522043
+ # GYP: //base.gyp:base_junit_test_support
+ java_library("base_junit_test_support") {
+ testonly = true
+ java_files = [ "test/android/junit/src/org/chromium/base/test/shadows/ShadowMultiDex.java" ]
+ deps = [
+ "//third_party/android_tools:android_support_multidex_java",
+ "//third_party/robolectric:android-all-4.3_r2-robolectric-0",
+ "//third_party/robolectric:robolectric_java",
+ ]
+ }
+
# GYP: //base.gyp:base_junit_tests
junit_binary("base_junit_tests") {
- java_files = [ "android/junit/src/org/chromium/base/LogTest.java" ]
+ java_files = [
+ "android/junit/src/org/chromium/base/BaseChromiumApplicationTest.java",
+ "android/junit/src/org/chromium/base/LogTest.java",
+ "test/android/junit/src/org/chromium/base/test/util/DisableIfTest.java",
+ ]
deps = [
":base_java",
":base_java_test_support",
+ ":base_junit_test_support",
]
}
@@ -1495,12 +2121,17 @@ if (is_android) {
"android/library_loader/library_loader_hooks.h",
"memory/memory_pressure_listener.h",
]
- outputs = [
- "org/chromium/base/ApplicationState.java",
- "org/chromium/base/library_loader/LibraryLoadFromApkStatusCodes.java",
- "org/chromium/base/library_loader/LibraryProcessType.java",
- "org/chromium/base/MemoryPressureLevel.java",
+ }
+
+ # GYP: //base/base.gyp:base_multidex_gen
+ java_cpp_template("base_multidex_gen") {
+ sources = [
+ "android/java/templates/ChromiumMultiDex.template",
]
+ if (is_debug) {
+ defines = [ "MULTIDEX_CONFIGURATION_Debug" ]
+ }
+ package_name = "org/chromium/base/multidex"
}
# GYP: //base/base.gyp:base_native_libraries_gen
diff --git a/base/DEPS b/base/DEPS
index c632e35d83..c0e95a00f6 100644
--- a/base/DEPS
+++ b/base/DEPS
@@ -2,9 +2,7 @@ include_rules = [
"+jni",
"+third_party/ashmem",
"+third_party/apple_apsl",
- "+third_party/libevent",
- "+third_party/dmg_fp",
- "+third_party/mach_override",
+ "+third_party/lss",
"+third_party/modp_b64",
"+third_party/tcmalloc",
diff --git a/base/OWNERS b/base/OWNERS
index 9890491e47..4d4a2391a4 100644
--- a/base/OWNERS
+++ b/base/OWNERS
@@ -1,13 +1,8 @@
mark@chromium.org
-darin@chromium.org
thakis@chromium.org
danakj@chromium.org
-rvargas@chromium.org
thestig@chromium.org
-# On extended leave.
-willchan@chromium.org
-
# Chromium is a very mature project, most things that are generally useful are
# already here, and that things not here aren't generally useful.
#
@@ -21,11 +16,17 @@ willchan@chromium.org
# writing the stuff you want to log in a regular logging statement, even
# if it makes your calling code longer. Just add it to your own code.
-per-file *.isolate=csharp@chromium.org
per-file *.isolate=maruel@chromium.org
+per-file *.isolate=tandrii@chromium.org
+per-file *.isolate=vadimsh@chromium.org
per-file security_unittest.cc=jln@chromium.org
# For Android-specific changes:
per-file *android*=nyquist@chromium.org
per-file *android*=rmcilroy@chromium.org
+per-file *android*=torne@chromium.org
per-file *android*=yfriedman@chromium.org
+
+# For FeatureList API:
+per-file feature_list*=asvitkine@chromium.org
+per-file feature_list*=isherman@chromium.org
diff --git a/base/allocator/BUILD.gn b/base/allocator/BUILD.gn
index a07a356e5d..9d09a357af 100644
--- a/base/allocator/BUILD.gn
+++ b/base/allocator/BUILD.gn
@@ -3,23 +3,76 @@
# found in the LICENSE file.
import("//build/config/allocator.gni")
+import("//build/config/compiler/compiler.gni")
+
+if (is_win) {
+ import("//build/config/win/visual_studio_version.gni")
+}
+
+declare_args() {
+ # 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).
+ enable_debugallocation = is_debug
+}
# Only executables and not libraries should depend on the allocator target;
# only the application (the final executable) knows what allocator makes sense.
# This "allocator" meta-target will forward to the default allocator according
# to the build settings.
group("allocator") {
+ public_deps = []
if (use_allocator == "tcmalloc") {
- deps = [
- ":tcmalloc",
+ public_deps += [ ":tcmalloc" ]
+ }
+
+ # This condition expresses the win_use_allocator_shim in the GYP build.
+ if (is_win && !is_component_build && visual_studio_version != "2015") {
+ public_deps += [ ":allocator_shim" ]
+ }
+}
+
+# This config defines ALLOCATOR_SHIM in the same conditions that the allocator
+# shim will be used by the allocator target.
+#
+# TODO(brettw) this is only used in one place and is kind of mess, because it
+# assumes that the library using it will eventually be linked with
+# //base/allocator in the default way. Clean this up and delete this.
+config("allocator_shim_define") {
+ if (is_win && !is_component_build && visual_studio_version != "2015") {
+ defines = [ "ALLOCATOR_SHIM" ]
+ }
+}
+
+config("tcmalloc_flags") {
+ if (enable_debugallocation) {
+ defines = [
+ # Use debugallocation for Debug builds to catch problems early
+ # and cleanly, http://crbug.com/30715 .
+ "TCMALLOC_FOR_DEBUGALLOCATION",
+ ]
+ }
+ if (is_clang) {
+ cflags = [
+ # tcmalloc initializes some fields in the wrong order.
+ "-Wno-reorder",
+
+ # tcmalloc contains some unused local template specializations.
+ "-Wno-unused-function",
+
+ # tcmalloc uses COMPILE_ASSERT without static_assert but with
+ # typedefs.
+ "-Wno-unused-local-typedefs",
+
+ # for magic2_ in debugallocation.cc (only built in Debug builds)
+ # typedefs.
+ "-Wno-unused-private-field",
]
}
}
# This config and libc modification are only used on Windows.
if (is_win) {
- import("//build/config/win/visual_studio_version.gni")
-
config("nocmt") {
ldflags = [
"/NODEFAULTLIB:libcmt",
@@ -28,16 +81,38 @@ if (is_win) {
libs = [ rebase_path("$target_gen_dir/allocator/libcmt.lib") ]
}
- action("prep_libc") {
- script = "prep_libc.py"
- outputs = [
- "$target_gen_dir/allocator/libcmt.lib",
- ]
- args = [
- visual_studio_path + "/vc/lib",
- rebase_path("$target_gen_dir/allocator"),
- current_cpu,
- ]
+ if (!is_component_build && visual_studio_version != "2015") {
+ action("prep_libc") {
+ script = "prep_libc.py"
+ outputs = [
+ "$target_gen_dir/allocator/libcmt.lib",
+ ]
+ args = [
+ visual_studio_path + "/vc/lib",
+ rebase_path("$target_gen_dir/allocator"),
+ current_cpu,
+
+ # The environment file in the build directory. This is required because
+ # the Windows toolchain setup saves the VC paths and such so that
+ # running "mc.exe" will work with the configured toolchain. This file
+ # is in the root build dir.
+ "environment.$current_cpu",
+ ]
+ }
+
+ source_set("allocator_shim") {
+ sources = [
+ "allocator_shim_win.cc",
+ ]
+ configs -= [ "//build/config/compiler:chromium_code" ]
+ configs += [ "//build/config/compiler:no_chromium_code" ]
+
+ public_configs = [ ":nocmt" ]
+ deps = [
+ ":prep_libc",
+ "//base",
+ ]
+ }
}
}
@@ -52,7 +127,7 @@ if (use_allocator == "tcmalloc") {
check_includes = false
sources = [
- # Generated for our configuration from tcmalloc"s build
+ # Generated for our configuration from tcmalloc's build
# and checked in.
"$tcmalloc_dir/src/config.h",
"$tcmalloc_dir/src/config_android.h",
@@ -63,6 +138,16 @@ if (use_allocator == "tcmalloc") {
"$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-arm-generic.h",
+ "$tcmalloc_dir/src/base/atomicops-internals-arm-v6plus.h",
+ "$tcmalloc_dir/src/base/atomicops-internals-linuxppc.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/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.
@@ -81,8 +166,6 @@ if (use_allocator == "tcmalloc") {
"$tcmalloc_dir/src/base/synchronization_profiling.h",
"$tcmalloc_dir/src/base/sysinfo.cc",
"$tcmalloc_dir/src/base/sysinfo.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",
@@ -92,8 +175,6 @@ if (use_allocator == "tcmalloc") {
# #included by debugallocation_shim.cc
#"$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/heap-profile-table.cc",
@@ -111,11 +192,6 @@ if (use_allocator == "tcmalloc") {
"$tcmalloc_dir/src/memory_region_map.h",
"$tcmalloc_dir/src/page_heap.cc",
"$tcmalloc_dir/src/page_heap.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",
@@ -138,7 +214,6 @@ if (use_allocator == "tcmalloc") {
"$tcmalloc_dir/src/thread_cache.h",
"$tcmalloc_dir/src/windows/port.cc",
"$tcmalloc_dir/src/windows/port.h",
- "allocator_shim.cc",
"debugallocation_shim.cc",
# These are both #included by allocator_shim for maximal linking.
@@ -156,28 +231,15 @@ if (use_allocator == "tcmalloc") {
]
configs -= [ "//build/config/compiler:chromium_code" ]
- configs += [ "//build/config/compiler:no_chromium_code" ]
+ configs += [
+ "//build/config/compiler:no_chromium_code",
+ ":tcmalloc_flags",
+ ]
deps = []
- if (is_win) {
- 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",
-
- # cpuprofiler
+ if (enable_profiling) {
+ sources += [
"$tcmalloc_dir/src/base/thread_lister.c",
"$tcmalloc_dir/src/base/thread_lister.h",
"$tcmalloc_dir/src/profile-handler.cc",
@@ -186,17 +248,7 @@ if (use_allocator == "tcmalloc") {
"$tcmalloc_dir/src/profiledata.h",
"$tcmalloc_dir/src/profiler.cc",
]
- defines += [ "PERFTOOLS_DLL_DECL=" ]
-
- configs -= [
- # Tcmalloc defines this itself, and we don't want duplicate definition
- # warnings.
- "//build/config/win:nominmax",
- ]
-
- public_configs = [ ":nocmt" ]
-
- deps += [ ":prep_libc" ]
+ defines += [ "ENABLE_PROFILING=1" ]
}
if (is_linux || is_android) {
@@ -204,9 +256,6 @@ if (use_allocator == "tcmalloc") {
"$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",
]
# We enable all warnings by default, but upstream disables a few.
@@ -234,26 +283,10 @@ if (use_allocator == "tcmalloc") {
# Make sure the allocation library is optimized as much as possible when
# we"re in release mode.
if (!is_debug) {
- configs -= [ "//build/config/compiler:optimize" ]
+ configs -= [ "//build/config/compiler:default_optimization" ]
configs += [ "//build/config/compiler:optimize_max" ]
}
deps += [ "//base/third_party/dynamic_annotations" ]
-
- if (is_win) {
- ldflags = [ "/ignore:4006:4221" ]
- }
}
-} # !is_android
-
-source_set("allocator_extension_thunks") {
- visibility = [ "//base/*" ]
- sources = [
- "allocator_extension_thunks.cc",
- "allocator_extension_thunks.h",
- ]
- if (is_android && !is_debug) {
- configs -= [ "//build/config/compiler:optimize" ]
- configs += [ "//build/config/compiler:optimize_max" ]
- }
-}
+} # use_allocator == "tcmalloc"
diff --git a/base/allocator/README b/base/allocator/README
index ec8a707f41..8a5595fb26 100644
--- a/base/allocator/README
+++ b/base/allocator/README
@@ -7,7 +7,6 @@ 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
@@ -23,11 +22,10 @@ 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 tcmalloc library originates outside of Chromium and exists in
+../../third_party/tcmalloc (currently, the actual location is 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.
@@ -54,6 +52,5 @@ 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
index d426c9c3f1..45a95bbdc2 100644
--- a/base/allocator/allocator.gyp
+++ b/base/allocator/allocator.gyp
@@ -16,6 +16,10 @@
'variables': {
'tcmalloc_dir': '../../third_party/tcmalloc/chromium',
'use_vtable_verify%': 0,
+ # 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,
},
'targets': [
# Only executables and not libraries should depend on the
@@ -23,70 +27,64 @@
# knows what allocator makes sense.
{
'target_name': 'allocator',
+ # TODO(primiano): This should be type: none for the noop cases (an empty
+ # static lib can confuse some gyp generators). Fix it once the refactoring
+ # (crbug.com/564618) bring this file to a saner state (fewer conditions).
'type': 'static_library',
- 'direct_dependent_settings': {
- 'configurations': {
- 'Common_Base': {
- 'msvs_settings': {
- 'VCLinkerTool': {
- 'IgnoreDefaultLibraryNames': ['libcmtd.lib', 'libcmt.lib'],
- 'AdditionalDependencies': [
- '<(SHARED_INTERMEDIATE_DIR)/allocator/libcmt.lib'
- ],
- },
+ 'conditions': [
+ ['OS=="win" and win_use_allocator_shim==1', {
+ 'msvs_settings': {
+ # TODO(sgk): merge this with build/common.gypi settings
+ 'VCLibrarianTool': {
+ 'AdditionalOptions': ['/ignore:4006,4221'],
+ },
+ 'VCLinkerTool': {
+ 'AdditionalOptions': ['/ignore:4006'],
},
},
- },
- 'conditions': [
- ['OS=="win"', {
- 'defines': [
- 'PERFTOOLS_DLL_DECL=',
- ],
- }],
- ],
- },
- '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',
+ 'dependencies': [
+ 'libcmt',
+ ],
+ 'include_dirs': [
+ '../..',
+ ],
+ 'sources': [
+ 'allocator_shim_win.cc',
+ ],
+ '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,
+ 'direct_dependent_settings': {
+ 'configurations': {
+ 'Common_Base': {
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'IgnoreDefaultLibraryNames': ['libcmtd.lib', 'libcmt.lib'],
+ 'AdditionalDependencies': [
+ '<(SHARED_INTERMEDIATE_DIR)/allocator/libcmt.lib'
+ ],
+ },
+ },
+ },
+ },
},
- 'conditions': [
- ['disable_debugallocation==0', {
- 'defines': [
- # Use debugallocation for Debug builds to catch problems early
- # and cleanly, http://crbug.com/30715 .
- 'TCMALLOC_FOR_DEBUGALLOCATION',
- ],
- }],
- ],
- },
- },
- 'conditions': [
+ }], # OS=="win"
['use_allocator=="tcmalloc"', {
# Disable the heap checker in tcmalloc.
'defines': [
'NO_HEAP_CHECK',
],
+ 'dependencies': [
+ '../third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+ ],
+ # The order of this include_dirs matters, as tc-malloc has its own
+ # base/ mini-fork. Do not factor these out of this conditions section.
'include_dirs': [
'.',
'<(tcmalloc_dir)/src/base',
@@ -114,7 +112,6 @@
'<(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
@@ -153,8 +150,6 @@
'<(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',
@@ -240,7 +235,6 @@
'<(tcmalloc_dir)/src/base/atomicops-internals-x86-msvc.h',
'<(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',
@@ -289,72 +283,80 @@
# Included by debugallocation_shim.cc.
'<(tcmalloc_dir)/src/debugallocation.cc',
'<(tcmalloc_dir)/src/tcmalloc.cc',
- ]
- },{
- 'include_dirs': [
- '.',
- '../..',
- ],
- }],
- ['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"', {
- 'dependencies': [
- 'libcmt',
- ],
- 'sources': [
- 'allocator_shim_win.cc',
- ],
- }],
- ['profiling!=1', {
- 'sources!': [
- # cpuprofiler
- '<(tcmalloc_dir)/src/base/thread_lister.c',
- '<(tcmalloc_dir)/src/base/thread_lister.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',
- ],
- }],
- ['OS=="linux" or OS=="freebsd" or OS=="solaris" or OS=="android"', {
- 'sources!': [
- '<(tcmalloc_dir)/src/system-alloc.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',
+ 'variables': {
+ 'clang_warning_flags': [
+ # tcmalloc initializes some fields in the wrong order.
+ '-Wno-reorder',
+ # tcmalloc contains some unused local template specializations.
+ '-Wno-unused-function',
+ # tcmalloc uses COMPILE_ASSERT without static_assert but with
+ # typedefs.
+ '-Wno-unused-local-typedefs',
+ # for magic2_ in debugallocation.cc (only built in Debug builds)
+ # typedefs.
+ '-Wno-unused-private-field',
+ ],
+ },
+ 'conditions': [
+ ['OS=="linux" or OS=="freebsd" or OS=="solaris" or OS=="android"', {
+ 'sources!': [
+ '<(tcmalloc_dir)/src/system-alloc.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',
+ ],
+ },
+ }],
+ ['profiling!=1', {
+ 'sources!': [
+ # cpuprofiler
+ '<(tcmalloc_dir)/src/base/thread_lister.c',
+ '<(tcmalloc_dir)/src/base/thread_lister.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',
+ ],
+ }],
],
- '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',
- ]},
- }],
- [ 'use_vtable_verify==1', {
+ 'configurations': {
+ 'Debug_Base': {
+ 'conditions': [
+ ['disable_debugallocation==0', {
+ 'defines': [
+ # Use debugallocation for Debug builds to catch problems
+ # early and cleanly, http://crbug.com/30715 .
+ 'TCMALLOC_FOR_DEBUGALLOCATION',
+ ],
+ }],
+ ],
+ },
+ },
+ }], # use_allocator=="tcmalloc
+ # For CrOS builds with vtable verification. According to the author of
+ # crrev.com/10854031 this is used in conjuction with some other CrOS
+ # build flag, to enable verification of any allocator that uses virtual
+ # function calls.
+ ['use_vtable_verify==1', {
'cflags': [
'-fvtable-verify=preinit',
],
@@ -366,38 +368,11 @@
}],
],
}],
- ],
- },
- {
- # 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 of 'allocator' target.
+ }, # 'allocator' target.
+ ], # targets.
'conditions': [
- ['OS=="win"', {
+ ['OS=="win" and component!="shared_library"', {
'targets': [
{
'target_name': 'libcmt',
@@ -421,151 +396,6 @@
},
],
},
- {
- 'target_name': 'allocator_unittests',
- 'type': 'executable',
- 'dependencies': [
- 'allocator',
- 'allocator_extension_thunks',
- '../../testing/gtest.gyp:gtest',
- ],
- 'include_dirs': [
- '.',
- '../..',
- ],
- 'sources': [
- '../profiler/alternate_timer.cc',
- '../profiler/alternate_timer.h',
- 'allocator_unittest.cc',
- ],
- },
- ],
- }],
- ['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': [
- '<(tcmalloc_dir)/src/gperftools/type_profiler_map.h',
- '<(tcmalloc_dir)/src/type_profiler_map.cc',
- 'type_profiler_tcmalloc.cc',
- 'type_profiler_tcmalloc.h',
- ],
- },
- {
- '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_unittest.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': [
- '<(tcmalloc_dir)/src/gperftools/type_profiler_map.h',
- '<(tcmalloc_dir)/src/type_profiler_map.cc',
- 'type_profiler_map_unittest.cc',
- ],
- },
- ],
- }],
- ['use_allocator=="tcmalloc"', {
- 'targets': [
- {
- 'target_name': 'tcmalloc_unittest',
- 'type': 'executable',
- 'sources': [
- 'tcmalloc_unittest.cc',
- ],
- 'include_dirs': [
- '<(tcmalloc_dir)/src',
- '../..',
- ],
- 'dependencies': [
- '../../testing/gtest.gyp:gtest',
- 'allocator',
- ],
- },
],
}],
],
diff --git a/base/allocator/allocator_extension.h b/base/allocator/allocator_extension.h
new file mode 100644
index 0000000000..3be2cea00c
--- /dev/null
+++ b/base/allocator/allocator_extension.h
@@ -0,0 +1,47 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <stddef.h> // for size_t
+
+#include "base/base_export.h"
+#include "build/build_config.h"
+
+namespace base {
+namespace allocator {
+
+typedef void (*ReleaseFreeMemoryFunction)();
+typedef bool (*GetNumericPropertyFunction)(const char* name, size_t* value);
+
+// Request that the allocator release any free memory it knows about to the
+// system.
+BASE_EXPORT void ReleaseFreeMemory();
+
+// Get the named property's |value|. Returns true if the property is known.
+// Returns false if the property is not a valid property name for the current
+// allocator implementation.
+// |name| or |value| cannot be NULL
+BASE_EXPORT bool GetNumericProperty(const char* name, size_t* value);
+
+// 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 SetReleaseFreeMemoryFunction(
+ ReleaseFreeMemoryFunction release_free_memory_function);
+
+BASE_EXPORT void SetGetNumericPropertyFunction(
+ GetNumericPropertyFunction get_numeric_property_function);
+
+} // namespace allocator
+} // namespace base
+
+#endif // BASE_ALLOCATOR_ALLOCATOR_EXTENSION_H_
diff --git a/base/allocator/prep_libc.py b/base/allocator/prep_libc.py
index 079297b462..a88d3bd025 100755
--- a/base/allocator/prep_libc.py
+++ b/base/allocator/prep_libc.py
@@ -7,24 +7,34 @@
# This script takes libcmt.lib for VS2013 and removes the allocation related
# functions from it.
#
-# Usage: prep_libc.py <VCLibDir> <OutputDir> <arch>
+# Usage: prep_libc.py <VCLibDir> <OutputDir> <arch> [<environment_file>]
#
# 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 one of: 'ia32', 'x86' or 'x64'. ia32 and x86 are synonyms.
+#
+# If the environment_file argument is set, the environment variables in the
+# given file will be used to execute the VC tools. This file is in the same
+# format as the environment block passed to CreateProcess.
import os
import shutil
import subprocess
import sys
-def run(command):
+def run(command, env_dict):
"""Run |command|. If any lines that match an error condition then
- terminate."""
+ terminate.
+
+ The env_dict, will be used for the environment. None can be used to get the
+ default environment."""
error = 'cannot find member object'
+ # Need shell=True to search the path in env_dict for the executable.
popen = subprocess.Popen(
- command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+ command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True,
+ env=env_dict)
out, _ = popen.communicate()
for line in out.splitlines():
print line
@@ -41,6 +51,13 @@ def main():
bindir = 'SELF_64_amd64'
objdir = 'amd64'
vs_install_dir = os.path.join(vs_install_dir, 'amd64')
+
+ if len(sys.argv) == 5:
+ env_pairs = open(sys.argv[4]).read()[:-2].split('\0')
+ env_dict = dict([item.split('=', 1) for item in env_pairs])
+ else:
+ env_dict = None # Use the default environment.
+
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'),
@@ -57,11 +74,11 @@ def main():
for obj in cobjfiles:
cmd = ('lib /nologo /ignore:4006,4221 /remove:%s%s.obj %s' %
(cvspath, obj, output_lib))
- run(cmd)
+ run(cmd, env_dict)
for obj in cppobjfiles:
cmd = ('lib /nologo /ignore:4006,4221 /remove:%s%s.obj %s' %
(cppvspath, obj, output_lib))
- run(cmd)
+ run(cmd, env_dict)
if __name__ == "__main__":
sys.exit(main())
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/android/OWNERS b/base/android/OWNERS
deleted file mode 100644
index 778fb75262..0000000000
--- a/base/android/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-nyquist@chromium.org
-rmcilroy@chromium.org
-yfriedman@chromium.org
diff --git a/base/android/java/src/org/chromium/base/ActivityState.java b/base/android/java/src/org/chromium/base/ActivityState.java
deleted file mode 100644
index 98aff62671..0000000000
--- a/base/android/java/src/org/chromium/base/ActivityState.java
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2014 The Chromium 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 set of states that represent the last state change of an Activity.
- */
-public interface ActivityState {
- /**
- * Represents Activity#onCreate().
- */
- public final int CREATED = 1;
-
- /**
- * Represents Activity#onStart().
- */
- public final int STARTED = 2;
-
- /**
- * Represents Activity#onResume().
- */
- public final int RESUMED = 3;
-
- /**
- * Represents Activity#onPause().
- */
- public final int PAUSED = 4;
-
- /**
- * Represents Activity#onStop().
- */
- public final int STOPPED = 5;
-
- /**
- * Represents Activity#onDestroy(). This is also used when the state of an Activity is unknown.
- */
- public final int DESTROYED = 6;
-}
diff --git a/base/android/java/src/org/chromium/base/AnimationFrameTimeHistogram.java b/base/android/java/src/org/chromium/base/AnimationFrameTimeHistogram.java
deleted file mode 100644
index ad5cdd815b..0000000000
--- a/base/android/java/src/org/chromium/base/AnimationFrameTimeHistogram.java
+++ /dev/null
@@ -1,145 +0,0 @@
-// Copyright 2015 The Chromium 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.animation.Animator;
-import android.animation.Animator.AnimatorListener;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.TimeAnimator;
-import android.animation.TimeAnimator.TimeListener;
-import android.util.Log;
-
-/**
- * Record Android animation frame rate and save it to UMA histogram. This is mainly for monitoring
- * any jankiness of short Chrome Android animations. It is limited to few seconds of recording.
- */
-public class AnimationFrameTimeHistogram {
- private static final String TAG = "AnimationFrameTimeHistogram";
- private static final int MAX_FRAME_TIME_NUM = 600; // 10 sec on 60 fps.
-
- private final Recorder mRecorder = new Recorder();
- private final String mHistogramName;
-
- /**
- * @param histogramName The histogram name that the recorded frame times will be saved.
- * This must be also defined in histograms.xml
- * @return An AnimatorListener instance that records frame time histogram on start and end
- * automatically.
- */
- public static AnimatorListener getAnimatorRecorder(final String histogramName) {
- return new AnimatorListenerAdapter() {
- private final AnimationFrameTimeHistogram mAnimationFrameTimeHistogram =
- new AnimationFrameTimeHistogram(histogramName);
-
- @Override
- public void onAnimationStart(Animator animation) {
- mAnimationFrameTimeHistogram.startRecording();
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- mAnimationFrameTimeHistogram.endRecording();
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
- mAnimationFrameTimeHistogram.endRecording();
- }
- };
- }
-
- /**
- * @param histogramName The histogram name that the recorded frame times will be saved.
- * This must be also defined in histograms.xml
- */
- public AnimationFrameTimeHistogram(String histogramName) {
- mHistogramName = histogramName;
- }
-
- /**
- * Start recording frame times. The recording can fail if it exceeds a few seconds.
- */
- public void startRecording() {
- mRecorder.startRecording();
- }
-
- /**
- * End recording and save it to histogram. It won't save histogram if the recording wasn't
- * successful.
- */
- public void endRecording() {
- if (mRecorder.endRecording()) {
- nativeSaveHistogram(mHistogramName,
- mRecorder.getFrameTimesMs(), mRecorder.getFrameTimesCount());
- }
- mRecorder.cleanUp();
- }
-
- /**
- * Record Android animation frame rate and return the result.
- */
- private static class Recorder implements TimeListener {
- // TODO(kkimlabs): If we can use in the future, migrate to Choreographer for minimal
- // workload.
- private final TimeAnimator mAnimator = new TimeAnimator();
- private long[] mFrameTimesMs;
- private int mFrameTimesCount;
-
- private Recorder() {
- mAnimator.setTimeListener(this);
- }
-
- private void startRecording() {
- assert !mAnimator.isRunning();
- mFrameTimesCount = 0;
- mFrameTimesMs = new long[MAX_FRAME_TIME_NUM];
- mAnimator.start();
- }
-
- /**
- * @return Whether the recording was successful. If successful, the result is available via
- * getFrameTimesNs and getFrameTimesCount.
- */
- private boolean endRecording() {
- boolean succeeded = mAnimator.isStarted();
- mAnimator.end();
- return succeeded;
- }
-
- private long[] getFrameTimesMs() {
- return mFrameTimesMs;
- }
-
- private int getFrameTimesCount() {
- return mFrameTimesCount;
- }
-
- /**
- * Deallocates the temporary buffer to record frame times. Must be called after ending
- * the recording and getting the result.
- */
- private void cleanUp() {
- mFrameTimesMs = null;
- }
-
- @Override
- public void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime) {
- if (mFrameTimesCount == mFrameTimesMs.length) {
- mAnimator.end();
- cleanUp();
- Log.w(TAG, "Animation frame time recording reached the maximum number. It's either"
- + "the animation took too long or recording end is not called.");
- return;
- }
-
- // deltaTime is 0 for the first frame.
- if (deltaTime > 0) {
- mFrameTimesMs[mFrameTimesCount++] = deltaTime;
- }
- }
- }
-
- private native void nativeSaveHistogram(String histogramName, long[] frameTimesMs, int count);
-}
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 b3eff94e81..0000000000
--- a/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java
+++ /dev/null
@@ -1,418 +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.annotation.TargetApi;
-import android.app.Activity;
-import android.app.ActivityManager;
-import android.app.PendingIntent;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.content.res.Resources.NotFoundException;
-import android.graphics.Bitmap;
-import android.graphics.Color;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-import android.os.PowerManager;
-import android.provider.Settings;
-import android.view.View;
-import android.view.ViewGroup.MarginLayoutParams;
-import android.view.Window;
-import android.view.WindowManager;
-import android.widget.TextView;
-
-/**
- * Utility class to use new APIs that were added after ICS (API level 14).
- */
-@TargetApi(Build.VERSION_CODES.LOLLIPOP)
-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 Configuration#getLayoutDirection()
- */
- public static int getLayoutDirection(Configuration configuration) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
- return configuration.getLayoutDirection();
- } else {
- // All layouts are LTR before JB MR1.
- return View.LAYOUT_DIRECTION_LTR;
- }
- }
-
- /**
- * @return True if the running version of the Android supports printing.
- */
- public static boolean isPrintingSupported() {
- return Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
- }
-
- /**
- * @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.View#setTextAlignment(int)
- */
- public static void setTextAlignment(View view, int textAlignment) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
- view.setTextAlignment(textAlignment);
- } else {
- // Do nothing. RTL text isn't supported before JB MR1.
- }
- }
-
- /**
- * @see android.view.View#setTextDirection(int)
- */
- public static void setTextDirection(View view, int textDirection) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
- view.setTextDirection(textDirection);
- } else {
- // Do nothing. RTL text isn'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#setPaddingRelative(int, int, int, int)
- */
- public static void setPaddingRelative(View view, int start, int top, int end, int bottom) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
- view.setPaddingRelative(start, top, end, bottom);
- } else {
- // Before JB MR1, all layouts are left-to-right, so start == left, etc.
- view.setPadding(start, top, end, bottom);
- }
- }
-
- /**
- * @see android.view.View#getPaddingStart()
- */
- public static int getPaddingStart(View view) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
- return view.getPaddingStart();
- } else {
- // Before JB MR1, all layouts are left-to-right, so start == left.
- return view.getPaddingLeft();
- }
- }
-
- /**
- * @see android.view.View#getPaddingEnd()
- */
- public static int getPaddingEnd(View view) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
- return view.getPaddingEnd();
- } else {
- // Before JB MR1, all layouts are left-to-right, so end == right.
- return view.getPaddingRight();
- }
- }
-
- /**
- * @see android.widget.TextView#setCompoundDrawablesRelative(Drawable, Drawable, Drawable,
- * Drawable)
- */
- public static void setCompoundDrawablesRelative(TextView textView, Drawable start, Drawable top,
- Drawable end, Drawable bottom) {
- if (Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN_MR1) {
- // On JB MR1, due to a platform bug, setCompoundDrawablesRelative() is a no-op if the
- // view has ever been measured. As a workaround, use setCompoundDrawables() directly.
- // See: http://crbug.com/368196 and http://crbug.com/361709
- boolean isRtl = isLayoutRtl(textView);
- textView.setCompoundDrawables(isRtl ? end : start, top, isRtl ? start : end, bottom);
- } else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR1) {
- textView.setCompoundDrawablesRelative(start, top, end, bottom);
- } else {
- textView.setCompoundDrawables(start, top, end, bottom);
- }
- }
-
- /**
- * @see android.widget.TextView#setCompoundDrawablesRelativeWithIntrinsicBounds(Drawable,
- * Drawable, Drawable, Drawable)
- */
- public static void setCompoundDrawablesRelativeWithIntrinsicBounds(TextView textView,
- Drawable start, Drawable top, Drawable end, Drawable bottom) {
- if (Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN_MR1) {
- // Work around the platform bug described in setCompoundDrawablesRelative() above.
- boolean isRtl = isLayoutRtl(textView);
- textView.setCompoundDrawablesWithIntrinsicBounds(isRtl ? end : start, top,
- isRtl ? start : end, bottom);
- } else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR1) {
- textView.setCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom);
- } else {
- textView.setCompoundDrawablesWithIntrinsicBounds(start, top, end, bottom);
- }
- }
-
- /**
- * @see android.widget.TextView#setCompoundDrawablesRelativeWithIntrinsicBounds(int, int, int,
- * int)
- */
- public static void setCompoundDrawablesRelativeWithIntrinsicBounds(TextView textView,
- int start, int top, int end, int bottom) {
- if (Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN_MR1) {
- // Work around the platform bug described in setCompoundDrawablesRelative() above.
- boolean isRtl = isLayoutRtl(textView);
- textView.setCompoundDrawablesWithIntrinsicBounds(isRtl ? end : start, top,
- isRtl ? start : end, bottom);
- } else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR1) {
- textView.setCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom);
- } else {
- textView.setCompoundDrawablesWithIntrinsicBounds(start, top, end, bottom);
- }
- }
-
- // These methods have a new name, and the old name is deprecated.
-
- /**
- * @see android.app.PendingIntent#getCreatorPackage()
- */
- @SuppressWarnings("deprecation")
- public static String getCreatorPackage(PendingIntent intent) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
- return intent.getCreatorPackage();
- } else {
- return intent.getTargetPackage();
- }
- }
-
- /**
- * @see android.provider.Settings.Global#DEVICE_PROVISIONED
- */
- @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
- public static boolean isDeviceProvisioned(Context context) {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) return true;
- if (context == null) return true;
- if (context.getContentResolver() == null) return true;
- return Settings.Global.getInt(
- context.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0) != 0;
- }
-
- /**
- * @see android.app.Activity#finishAndRemoveTask()
- */
- public static void finishAndRemoveTask(Activity activity) {
- if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
- activity.finishAndRemoveTask();
- } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP) {
- // crbug.com/395772 : Fallback for Activity.finishAndRemoveTask() failing.
- new FinishAndRemoveTaskWithRetry(activity).run();
- } else {
- activity.finish();
- }
- }
-
- private static class FinishAndRemoveTaskWithRetry implements Runnable {
- private static final long RETRY_DELAY_MS = 500;
- private static final long MAX_TRY_COUNT = 3;
- private final Activity mActivity;
- private int mTryCount;
-
- FinishAndRemoveTaskWithRetry(Activity activity) {
- mActivity = activity;
- }
-
- @Override
- public void run() {
- mActivity.finishAndRemoveTask();
- mTryCount++;
- if (!mActivity.isFinishing()) {
- if (mTryCount < MAX_TRY_COUNT) {
- ThreadUtils.postOnUiThreadDelayed(this, RETRY_DELAY_MS);
- } else {
- mActivity.finish();
- }
- }
- }
- }
-
- /**
- * @return Whether the screen of the device is interactive.
- */
- @SuppressWarnings("deprecation")
- public static boolean isInteractive(Context context) {
- PowerManager manager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
- return manager.isInteractive();
- } else {
- return manager.isScreenOn();
- }
- }
-
- @SuppressWarnings("deprecation")
- public static int getActivityNewDocumentFlag() {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- return Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
- } else {
- return Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET;
- }
- }
-
- /**
- * @see android.provider.Settings.Secure#SKIP_FIRST_USE_HINTS
- */
- public static boolean shouldSkipFirstUseHints(ContentResolver contentResolver) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- return Settings.Secure.getInt(
- contentResolver, Settings.Secure.SKIP_FIRST_USE_HINTS, 0) != 0;
- } else {
- return false;
- }
- }
-
- /**
- * @param activity Activity that should get the task description update.
- * @param title Title of the activity.
- * @param icon Icon of the activity.
- * @param color Color of the activity.
- */
- public static void setTaskDescription(Activity activity, String title, Bitmap icon, int color) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- ActivityManager.TaskDescription description =
- new ActivityManager.TaskDescription(title, icon, color);
- activity.setTaskDescription(description);
- }
- }
-
- /**
- * @see android.view.Window#setStatusBarColor(int color).
- * TODO(ianwen): remove this method after downstream rolling.
- */
- public static void setStatusBarColor(Activity activity, int statusBarColor) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- // If both system bars are black, we can remove these from our layout,
- // removing or shrinking the SurfaceFlinger overlay required for our views.
- Window window = activity.getWindow();
- if (statusBarColor == Color.BLACK && window.getNavigationBarColor() == Color.BLACK) {
- window.clearFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
- } else {
- window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
- }
- window.setStatusBarColor(statusBarColor);
- }
- }
-
- /**
- * @see android.view.Window#setStatusBarColor(int color).
- */
- public static void setStatusBarColor(Window window, int statusBarColor) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- // If both system bars are black, we can remove these from our layout,
- // removing or shrinking the SurfaceFlinger overlay required for our views.
- if (statusBarColor == Color.BLACK && window.getNavigationBarColor() == Color.BLACK) {
- window.clearFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
- } else {
- window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
- }
- window.setStatusBarColor(statusBarColor);
- }
- }
-
- /**
- * @see android.content.res.Resources#getDrawable(int id).
- */
- @SuppressWarnings("deprecation")
- public static Drawable getDrawable(Resources res, int id) throws NotFoundException {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- return res.getDrawable(id, null);
- } else {
- return res.getDrawable(id);
- }
- }
-
- /**
- * @see android.content.res.Resources#getDrawableForDensity(int id, int density).
- */
- @SuppressWarnings("deprecation")
- public static Drawable getDrawableForDensity(Resources res, int id, int density) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- return res.getDrawableForDensity(id, density, null);
- } else {
- return res.getDrawableForDensity(id, density);
- }
- }
-
- /**
- * @see android.app.Activity#finishAfterTransition().
- */
- public static void finishAfterTransition(Activity activity) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- activity.finishAfterTransition();
- } else {
- activity.finish();
- }
- }
-}
diff --git a/base/android/java/src/org/chromium/base/ApkAssets.java b/base/android/java/src/org/chromium/base/ApkAssets.java
deleted file mode 100644
index 329660f621..0000000000
--- a/base/android/java/src/org/chromium/base/ApkAssets.java
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2014 The Chromium 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.res.AssetFileDescriptor;
-import android.content.res.AssetManager;
-import android.util.Log;
-
-import java.io.IOException;
-
-/**
- * A utility class to retrieve references to uncompressed assets insides the apk. A reference is
- * defined as tuple (file descriptor, offset, size) enabling direct mapping without deflation.
- * This can be used even within the renderer process, since it just dup's the apk's fd.
- */
-@JNINamespace("base::android")
-public class ApkAssets {
- private static final String LOGTAG = "ApkAssets";
-
- @CalledByNative
- public static long[] open(Context context, String fileName) {
- AssetFileDescriptor afd = null;
- try {
- AssetManager manager = context.getAssets();
- afd = manager.openNonAssetFd(fileName);
- return new long[] { afd.getParcelFileDescriptor().detachFd(),
- afd.getStartOffset(),
- afd.getLength() };
- } catch (IOException e) {
- Log.e(LOGTAG, "Error while loading asset " + fileName + ": " + e);
- return new long[] {-1, -1, -1};
- } finally {
- try {
- if (afd != null) {
- afd.close();
- }
- } catch (IOException e2) {
- Log.e(LOGTAG, "Unable to close AssetFileDescriptor", e2);
- }
- }
- }
-}
diff --git a/base/android/java/src/org/chromium/base/ApplicationStatus.java b/base/android/java/src/org/chromium/base/ApplicationStatus.java
deleted file mode 100644
index 8c36b61bd6..0000000000
--- a/base/android/java/src/org/chromium/base/ApplicationStatus.java
+++ /dev/null
@@ -1,448 +0,0 @@
-// Copyright 2014 The Chromium 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.app.Application;
-import android.app.Application.ActivityLifecycleCallbacks;
-import android.content.Context;
-import android.os.Bundle;
-
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * Provides information about the current activity's status, and a way
- * to register / unregister listeners for state changes.
- */
-@JNINamespace("base::android")
-public class ApplicationStatus {
- private static class ActivityInfo {
- private int mStatus = ActivityState.DESTROYED;
- private ObserverList<ActivityStateListener> mListeners =
- new ObserverList<ActivityStateListener>();
-
- /**
- * @return The current {@link ActivityState} of the activity.
- */
- public int getStatus() {
- return mStatus;
- }
-
- /**
- * @param status The new {@link ActivityState} of the activity.
- */
- public void setStatus(int status) {
- mStatus = status;
- }
-
- /**
- * @return A list of {@link ActivityStateListener}s listening to this activity.
- */
- public ObserverList<ActivityStateListener> getListeners() {
- return mListeners;
- }
- }
-
- private static Application sApplication;
-
- private static Object sCachedApplicationStateLock = new Object();
- private static Integer sCachedApplicationState;
-
- /** Last activity that was shown (or null if none or it was destroyed). */
- private static Activity sActivity;
-
- /** A lazily initialized listener that forwards application state changes to native. */
- private static ApplicationStateListener sNativeApplicationStateListener;
-
- /**
- * A map of which observers listen to state changes from which {@link Activity}.
- */
- private static final Map<Activity, ActivityInfo> sActivityInfo =
- new ConcurrentHashMap<Activity, ActivityInfo>();
-
- /**
- * A list of observers to be notified when any {@link Activity} has a state change.
- */
- private static final ObserverList<ActivityStateListener> sGeneralActivityStateListeners =
- new ObserverList<ActivityStateListener>();
-
- /**
- * A list of observers to be notified when the visibility state of this {@link Application}
- * changes. See {@link #getStateForApplication()}.
- */
- private static final ObserverList<ApplicationStateListener> sApplicationStateListeners =
- new ObserverList<ApplicationStateListener>();
-
- /**
- * Interface to be implemented by listeners.
- */
- public interface ApplicationStateListener {
- /**
- * Called when the application's state changes.
- * @param newState The application state.
- */
- public void onApplicationStateChange(int newState);
- }
-
- /**
- * Interface to be implemented by listeners.
- */
- public interface ActivityStateListener {
- /**
- * Called when the activity's state changes.
- * @param activity The activity that had a state change.
- * @param newState New activity state.
- */
- public void onActivityStateChange(Activity activity, int newState);
- }
-
- private ApplicationStatus() {}
-
- /**
- * Initializes the activity status for a specified application.
- *
- * @param application The application whose status you wish to monitor.
- */
- public static void initialize(BaseChromiumApplication application) {
- sApplication = application;
-
- application.registerWindowFocusChangedListener(
- new BaseChromiumApplication.WindowFocusChangedListener() {
- @Override
- public void onWindowFocusChanged(Activity activity, boolean hasFocus) {
- if (!hasFocus || activity == sActivity) return;
-
- int state = getStateForActivity(activity);
-
- if (state != ActivityState.DESTROYED && state != ActivityState.STOPPED) {
- sActivity = activity;
- }
-
- // TODO(dtrainor): Notify of active activity change?
- }
- });
-
- application.registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
- @Override
- public void onActivityCreated(final Activity activity, Bundle savedInstanceState) {
- onStateChange(activity, ActivityState.CREATED);
- }
-
- @Override
- public void onActivityDestroyed(Activity activity) {
- onStateChange(activity, ActivityState.DESTROYED);
- }
-
- @Override
- public void onActivityPaused(Activity activity) {
- onStateChange(activity, ActivityState.PAUSED);
- }
-
- @Override
- public void onActivityResumed(Activity activity) {
- onStateChange(activity, ActivityState.RESUMED);
- }
-
- @Override
- public void onActivitySaveInstanceState(Activity activity, Bundle outState) {}
-
- @Override
- public void onActivityStarted(Activity activity) {
- onStateChange(activity, ActivityState.STARTED);
- }
-
- @Override
- public void onActivityStopped(Activity activity) {
- onStateChange(activity, ActivityState.STOPPED);
- }
- });
- }
-
- /**
- * Must be called by the main activity when it changes state.
- *
- * @param activity Current activity.
- * @param newState New state value.
- */
- private static void onStateChange(Activity activity, int newState) {
- if (activity == null) throw new IllegalArgumentException("null activity is not supported");
-
- if (sActivity == null
- || newState == ActivityState.CREATED
- || newState == ActivityState.RESUMED
- || newState == ActivityState.STARTED) {
- sActivity = activity;
- }
-
- int oldApplicationState = getStateForApplication();
-
- if (newState == ActivityState.CREATED) {
- assert !sActivityInfo.containsKey(activity);
- sActivityInfo.put(activity, new ActivityInfo());
- }
-
- // Invalidate the cached application state.
- synchronized (sCachedApplicationStateLock) {
- sCachedApplicationState = null;
- }
-
- ActivityInfo info = sActivityInfo.get(activity);
- info.setStatus(newState);
-
- // Notify all state observers that are specifically listening to this activity.
- for (ActivityStateListener listener : info.getListeners()) {
- listener.onActivityStateChange(activity, newState);
- }
-
- // Notify all state observers that are listening globally for all activity state
- // changes.
- for (ActivityStateListener listener : sGeneralActivityStateListeners) {
- listener.onActivityStateChange(activity, newState);
- }
-
- int applicationState = getStateForApplication();
- if (applicationState != oldApplicationState) {
- for (ApplicationStateListener listener : sApplicationStateListeners) {
- listener.onApplicationStateChange(applicationState);
- }
- }
-
- if (newState == ActivityState.DESTROYED) {
- sActivityInfo.remove(activity);
- if (activity == sActivity) sActivity = null;
- }
- }
-
- /**
- * Testing method to update the state of the specified activity.
- */
- @VisibleForTesting
- public static void onStateChangeForTesting(Activity activity, int newState) {
- onStateChange(activity, newState);
- }
-
- /**
- * @return The most recent focused {@link Activity} tracked by this class. Being focused means
- * out of all the activities tracked here, it has most recently gained window focus.
- */
- public static Activity getLastTrackedFocusedActivity() {
- return sActivity;
- }
-
- /**
- * @return A {@link List} of all non-destroyed {@link Activity}s.
- */
- public static List<WeakReference<Activity>> getRunningActivities() {
- List<WeakReference<Activity>> activities = new ArrayList<WeakReference<Activity>>();
- for (Activity activity : sActivityInfo.keySet()) {
- activities.add(new WeakReference<Activity>(activity));
- }
- return activities;
- }
-
- /**
- * @return The {@link Context} for the {@link Application}.
- */
- public static Context getApplicationContext() {
- return sApplication != null ? sApplication.getApplicationContext() : null;
- }
-
- /**
- * Query the state for a given activity. If the activity is not being tracked, this will
- * return {@link ActivityState#DESTROYED}.
- *
- * <p>
- * Please note that Chrome can have multiple activities running simultaneously. Please also
- * look at {@link #getStateForApplication()} for more details.
- *
- * <p>
- * When relying on this method, be familiar with the expected life cycle state
- * transitions:
- * <a href="http://developer.android.com/guide/components/activities.html#Lifecycle">
- * Activity Lifecycle
- * </a>
- *
- * <p>
- * During activity transitions (activity B launching in front of activity A), A will completely
- * paused before the creation of activity B begins.
- *
- * <p>
- * A basic flow for activity A starting, followed by activity B being opened and then closed:
- * <ul>
- * <li> -- Starting Activity A --
- * <li> Activity A - ActivityState.CREATED
- * <li> Activity A - ActivityState.STARTED
- * <li> Activity A - ActivityState.RESUMED
- * <li> -- Starting Activity B --
- * <li> Activity A - ActivityState.PAUSED
- * <li> Activity B - ActivityState.CREATED
- * <li> Activity B - ActivityState.STARTED
- * <li> Activity B - ActivityState.RESUMED
- * <li> Activity A - ActivityState.STOPPED
- * <li> -- Closing Activity B, Activity A regaining focus --
- * <li> Activity B - ActivityState.PAUSED
- * <li> Activity A - ActivityState.STARTED
- * <li> Activity A - ActivityState.RESUMED
- * <li> Activity B - ActivityState.STOPPED
- * <li> Activity B - ActivityState.DESTROYED
- * </ul>
- *
- * @param activity The activity whose state is to be returned.
- * @return The state of the specified activity (see {@link ActivityState}).
- */
- public static int getStateForActivity(Activity activity) {
- ActivityInfo info = sActivityInfo.get(activity);
- return info != null ? info.getStatus() : ActivityState.DESTROYED;
- }
-
- /**
- * @return The state of the application (see {@link ApplicationState}).
- */
- public static int getStateForApplication() {
- synchronized (sCachedApplicationStateLock) {
- if (sCachedApplicationState == null) {
- sCachedApplicationState = determineApplicationState();
- }
- return sCachedApplicationState.intValue();
- }
- }
-
- /**
- * Checks whether or not any Activity in this Application is visible to the user. Note that
- * this includes the PAUSED state, which can happen when the Activity is temporarily covered
- * by another Activity's Fragment (e.g.).
- * @return Whether any Activity under this Application is visible.
- */
- public static boolean hasVisibleActivities() {
- int state = getStateForApplication();
- return state == ApplicationState.HAS_RUNNING_ACTIVITIES
- || state == ApplicationState.HAS_PAUSED_ACTIVITIES;
- }
-
- /**
- * Checks to see if there are any active Activity instances being watched by ApplicationStatus.
- * @return True if all Activities have been destroyed.
- */
- public static boolean isEveryActivityDestroyed() {
- return sActivityInfo.isEmpty();
- }
-
- /**
- * Registers the given listener to receive state changes for all activities.
- * @param listener Listener to receive state changes.
- */
- public static void registerStateListenerForAllActivities(ActivityStateListener listener) {
- sGeneralActivityStateListeners.addObserver(listener);
- }
-
- /**
- * Registers the given listener to receive state changes for {@code activity}. After a call to
- * {@link ActivityStateListener#onActivityStateChange(Activity, int)} with
- * {@link ActivityState#DESTROYED} all listeners associated with that particular
- * {@link Activity} are removed.
- * @param listener Listener to receive state changes.
- * @param activity Activity to track or {@code null} to track all activities.
- */
- public static void registerStateListenerForActivity(ActivityStateListener listener,
- Activity activity) {
- assert activity != null;
-
- ActivityInfo info = sActivityInfo.get(activity);
- assert info != null && info.getStatus() != ActivityState.DESTROYED;
- info.getListeners().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 unregisterActivityStateListener(ActivityStateListener listener) {
- sGeneralActivityStateListeners.removeObserver(listener);
-
- // Loop through all observer lists for all activities and remove the listener.
- for (ActivityInfo info : sActivityInfo.values()) {
- info.getListeners().removeObserver(listener);
- }
- }
-
- /**
- * Registers the given listener to receive state changes for the application.
- * @param listener Listener to receive state state changes.
- */
- public static void registerApplicationStateListener(ApplicationStateListener listener) {
- sApplicationStateListeners.addObserver(listener);
- }
-
- /**
- * Unregisters the given listener from receiving state changes.
- * @param listener Listener that doesn't want to receive state changes.
- */
- public static void unregisterApplicationStateListener(ApplicationStateListener listener) {
- sApplicationStateListeners.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 registerThreadSafeNativeApplicationStateListener() {
- ThreadUtils.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- if (sNativeApplicationStateListener != null) return;
-
- sNativeApplicationStateListener = new ApplicationStateListener() {
- @Override
- public void onApplicationStateChange(int newState) {
- nativeOnApplicationStateChange(newState);
- }
- };
- registerApplicationStateListener(sNativeApplicationStateListener);
- }
- });
- }
-
- /**
- * Determines the current application state as defined by {@link ApplicationState}. This will
- * loop over all the activities and check their state to determine what the general application
- * state should be.
- * @return HAS_RUNNING_ACTIVITIES if any activity is not paused, stopped, or destroyed.
- * HAS_PAUSED_ACTIVITIES if none are running and one is paused.
- * HAS_STOPPED_ACTIVITIES if none are running/paused and one is stopped.
- * HAS_DESTROYED_ACTIVITIES if none are running/paused/stopped.
- */
- private static int determineApplicationState() {
- boolean hasPausedActivity = false;
- boolean hasStoppedActivity = false;
-
- for (ActivityInfo info : sActivityInfo.values()) {
- int state = info.getStatus();
- if (state != ActivityState.PAUSED
- && state != ActivityState.STOPPED
- && state != ActivityState.DESTROYED) {
- return ApplicationState.HAS_RUNNING_ACTIVITIES;
- } else if (state == ActivityState.PAUSED) {
- hasPausedActivity = true;
- } else if (state == ActivityState.STOPPED) {
- hasStoppedActivity = true;
- }
- }
-
- if (hasPausedActivity) return ApplicationState.HAS_PAUSED_ACTIVITIES;
- if (hasStoppedActivity) return ApplicationState.HAS_STOPPED_ACTIVITIES;
- return ApplicationState.HAS_DESTROYED_ACTIVITIES;
- }
-
- // Called to notify the native side of state changes.
- // IMPORTANT: This is always called on the main thread!
- private static native void nativeOnApplicationStateChange(int newState);
-}
diff --git a/base/android/java/src/org/chromium/base/BaseChromiumApplication.java b/base/android/java/src/org/chromium/base/BaseChromiumApplication.java
deleted file mode 100644
index d7c7b05ea5..0000000000
--- a/base/android/java/src/org/chromium/base/BaseChromiumApplication.java
+++ /dev/null
@@ -1,170 +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.Activity;
-import android.app.Application;
-import android.content.Context;
-import android.os.Bundle;
-import android.view.KeyEvent;
-import android.view.Window;
-
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
-
-/**
- * Basic application functionality that should be shared among all browser applications.
- */
-public class BaseChromiumApplication extends Application {
- /**
- * Interface to be implemented by listeners for window focus events.
- */
- public interface WindowFocusChangedListener {
- /**
- * Called when the window focus changes for {@code activity}.
- * @param activity The {@link Activity} that has a window focus changed event.
- * @param hasFocus Whether or not {@code activity} gained or lost focus.
- */
- public void onWindowFocusChanged(Activity activity, boolean hasFocus);
- }
-
- private ObserverList<WindowFocusChangedListener> mWindowFocusListeners =
- new ObserverList<WindowFocusChangedListener>();
-
- /**
- * Intercepts calls to an existing Window.Callback. Most invocations are passed on directly
- * to the composed Window.Callback but enables intercepting/manipulating others.
- *
- * This is used to relay window focus changes throughout the app and remedy a bug in the
- * appcompat library.
- */
- private class WindowCallbackProxy implements InvocationHandler {
- private final Window.Callback mCallback;
- private final Activity mActivity;
-
- public WindowCallbackProxy(Activity activity, Window.Callback callback) {
- mCallback = callback;
- mActivity = activity;
- }
-
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- if (method.getName().equals("onWindowFocusChanged") && args.length == 1
- && args[0] instanceof Boolean) {
- onWindowFocusChanged((boolean) args[0]);
- return null;
- } else if (method.getName().equals("dispatchKeyEvent") && args.length == 1
- && args[0] instanceof KeyEvent) {
- return dispatchKeyEvent((KeyEvent) args[0]);
- } else {
- try {
- return method.invoke(mCallback, args);
- } catch (InvocationTargetException e) {
- // Special-case for when a method is not defined on the underlying
- // Window.Callback object. Because we're using a Proxy to forward all method
- // calls, this breaks the Android framework's handling for apps built against
- // an older SDK. The framework expects an AbstractMethodError but due to
- // reflection it becomes wrapped inside an InvocationTargetException. Undo the
- // wrapping to signal the framework accordingly.
- if (e.getCause() instanceof AbstractMethodError) {
- throw e.getCause();
- }
- throw e;
- }
- }
- }
-
- public void onWindowFocusChanged(boolean hasFocus) {
- mCallback.onWindowFocusChanged(hasFocus);
-
- for (WindowFocusChangedListener listener : mWindowFocusListeners) {
- listener.onWindowFocusChanged(mActivity, hasFocus);
- }
- }
-
- public boolean dispatchKeyEvent(KeyEvent event) {
- // TODO(aurimas): remove this once AppCompatDelegateImpl no longer steals
- // KEYCODE_MENU. (see b/20529185)
- if (event.getKeyCode() == KeyEvent.KEYCODE_MENU && mActivity.dispatchKeyEvent(event)) {
- return true;
- }
- return mCallback.dispatchKeyEvent(event);
- }
- }
- @Override
- public void onCreate() {
- super.onCreate();
- ApplicationStatus.initialize(this);
- registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
- @Override
- public void onActivityCreated(final Activity activity, Bundle savedInstanceState) {
- Window.Callback callback = activity.getWindow().getCallback();
- activity.getWindow().setCallback((Window.Callback) Proxy.newProxyInstance(
- Window.Callback.class.getClassLoader(), new Class[] {Window.Callback.class},
- new WindowCallbackProxy(activity, callback)));
- }
-
- @Override
- public void onActivityDestroyed(Activity activity) {
- assert Proxy.isProxyClass(activity.getWindow().getCallback().getClass());
- }
-
- @Override
- public void onActivityPaused(Activity activity) {
- assert Proxy.isProxyClass(activity.getWindow().getCallback().getClass());
- }
-
- @Override
- public void onActivityResumed(Activity activity) {
- assert Proxy.isProxyClass(activity.getWindow().getCallback().getClass());
- }
-
- @Override
- public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
- assert Proxy.isProxyClass(activity.getWindow().getCallback().getClass());
- }
-
- @Override
- public void onActivityStarted(Activity activity) {
- assert Proxy.isProxyClass(activity.getWindow().getCallback().getClass());
- }
-
- @Override
- public void onActivityStopped(Activity activity) {
- assert Proxy.isProxyClass(activity.getWindow().getCallback().getClass());
- }
- });
- }
-
- /**
- * Registers a listener to receive window focus updates on activities in this application.
- * @param listener Listener to receive window focus events.
- */
- public void registerWindowFocusChangedListener(WindowFocusChangedListener listener) {
- mWindowFocusListeners.addObserver(listener);
- }
-
- /**
- * Unregisters a listener from receiving window focus updates on activities in this application.
- * @param listener Listener that doesn't want to receive window focus events.
- */
- public void unregisterWindowFocusChangedListener(WindowFocusChangedListener listener) {
- mWindowFocusListeners.removeObserver(listener);
- }
-
- /** Initializes the {@link CommandLine}. */
- public void initCommandLine() {}
-
- /**
- * This must only be called for contexts whose application is a subclass of
- * {@link BaseChromiumApplication}.
- */
- @VisibleForTesting
- public static void initCommandLine(Context context) {
- ((BaseChromiumApplication) context.getApplicationContext()).initCommandLine();
- };
-}
diff --git a/base/android/java/src/org/chromium/base/BaseSwitches.java b/base/android/java/src/org/chromium/base/BaseSwitches.java
deleted file mode 100644
index ad73e15e89..0000000000
--- a/base/android/java/src/org/chromium/base/BaseSwitches.java
+++ /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.
-
-package org.chromium.base;
-
-/**
- * Contains all of the command line switches that are specific to the base/
- * portion of Chromium on Android.
- */
-public abstract class BaseSwitches {
- // Block onCreate() of Chrome until a Java debugger is attached.
- public static final String WAIT_FOR_JAVA_DEBUGGER = "wait-for-java-debugger";
-
- // Block ChildProcessMain thread of render process service until a Java debugger is attached.
- public static final String RENDERER_WAIT_FOR_JAVA_DEBUGGER = "renderer-wait-for-java-debugger";
-
- // Force low-end device mode when set.
- public static final String ENABLE_LOW_END_DEVICE_MODE = "enable-low-end-device-mode";
-
- // Force disabling of low-end device mode when set.
- public static final String DISABLE_LOW_END_DEVICE_MODE = "disable-low-end-device-mode";
-
- // Adds additional thread idle time information into the trace event output.
- public static final String ENABLE_IDLE_TRACING = "enable-idle-tracing";
-
- // Default country code to be used for search engine localization.
- public static final String DEFAULT_COUNTRY_CODE_AT_INSTALL = "default-country-code";
-
- // Prevent instantiation.
- private BaseSwitches() {}
-}
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 54f611d509..0000000000
--- a/base/android/java/src/org/chromium/base/BuildInfo.java
+++ /dev/null
@@ -1,125 +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.
-
-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;
-
-/**
- * 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 getDeviceManufacturer() {
- return Build.MANUFACTURER;
- }
-
- @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 String getBuildType() {
- return Build.TYPE;
- }
-
- @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 3e6315e7af..0000000000
--- a/base/android/java/src/org/chromium/base/CalledByNative.java
+++ /dev/null
@@ -1,23 +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.
-
-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/CollectionUtil.java b/base/android/java/src/org/chromium/base/CollectionUtil.java
deleted file mode 100644
index 4a4c7540a5..0000000000
--- a/base/android/java/src/org/chromium/base/CollectionUtil.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 java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-
-/**
- * Functions used for easier initialization of Java collections. Inspired by
- * functionality in com.google.common.collect in Guava but cherry-picked to
- * bare-minimum functionality to avoid bloat. (http://crbug.com/272790 provides
- * further details)
- */
-public final class CollectionUtil {
- private CollectionUtil() {}
-
- @SafeVarargs
- public static <E> HashSet<E> newHashSet(E... elements) {
- HashSet<E> set = new HashSet<E>(elements.length);
- Collections.addAll(set, elements);
- return set;
- }
-
- @SafeVarargs
- public static <E> ArrayList<E> newArrayList(E... elements) {
- ArrayList<E> list = new ArrayList<E>(elements.length);
- Collections.addAll(list, elements);
- return list;
- }
-
- public static <E> ArrayList<E> newArrayList(Iterable<E> iterable) {
- ArrayList<E> list = new ArrayList<E>();
- for (E element : iterable) {
- list.add(element);
- }
- return list;
- }
-} \ No newline at end of file
diff --git a/base/android/java/src/org/chromium/base/CommandLine.java b/base/android/java/src/org/chromium/base/CommandLine.java
deleted file mode 100644
index 9f5407921a..0000000000
--- a/base/android/java/src/org/chromium/base/CommandLine.java
+++ /dev/null
@@ -1,383 +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.text.TextUtils;
-import android.util.Log;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.concurrent.atomic.AtomicReference;
-
-/**
- * Java mirror of base/command_line.h.
- * Android applications don't have command line arguments. Instead, they're "simulated" by reading a
- * file at a specific location early during startup. Applications each define their own files, e.g.,
- * ContentShellApplication.COMMAND_LINE_FILE or ChromeShellApplication.COMMAND_LINE_FILE.
-**/
-public abstract class CommandLine {
- // Public abstract interface, implemented in derived classes.
- // All these methods reflect their native-side counterparts.
- /**
- * Returns true if this command line contains the given switch.
- * (Switch names ARE case-sensitive).
- */
- @VisibleForTesting
- public abstract boolean hasSwitch(String switchString);
-
- /**
- * Return the value associated with the given switch, or null.
- * @param switchString The switch key to lookup. It should NOT start with '--' !
- * @return switch value, or null if the switch is not set or set to empty.
- */
- public abstract String getSwitchValue(String switchString);
-
- /**
- * Return the value associated with the given switch, or {@code defaultValue} if the switch
- * was not specified.
- * @param switchString The switch key to lookup. It should NOT start with '--' !
- * @param defaultValue The default value to return if the switch isn't set.
- * @return Switch value, or {@code defaultValue} if the switch is not set or set to empty.
- */
- public String getSwitchValue(String switchString, String defaultValue) {
- String value = getSwitchValue(switchString);
- return TextUtils.isEmpty(value) ? defaultValue : value;
- }
-
- /**
- * Append a switch to the command line. There is no guarantee
- * this action happens before the switch is needed.
- * @param switchString the switch to add. It should NOT start with '--' !
- */
- @VisibleForTesting
- public abstract void appendSwitch(String switchString);
-
- /**
- * Append a switch and value to the command line. There is no
- * guarantee this action happens before the switch is needed.
- * @param switchString the switch to add. It should NOT start with '--' !
- * @param value the value for this switch.
- * For example, --foo=bar becomes 'foo', 'bar'.
- */
- public abstract void appendSwitchWithValue(String switchString, String value);
-
- /**
- * Append switch/value items in "command line" format (excluding argv[0] program name).
- * E.g. { '--gofast', '--username=fred' }
- * @param array an array of switch or switch/value items in command line format.
- * Unlike the other append routines, these switches SHOULD start with '--' .
- * Unlike init(), this does not include the program name in array[0].
- */
- public abstract void appendSwitchesAndArguments(String[] array);
-
- /**
- * Determine if the command line is bound to the native (JNI) implementation.
- * @return true if the underlying implementation is delegating to the native command line.
- */
- public boolean isNativeImplementation() {
- return false;
- }
-
- private static final AtomicReference<CommandLine> sCommandLine =
- new AtomicReference<CommandLine>();
-
- /**
- * @returns true if the command line has already been initialized.
- */
- public static boolean isInitialized() {
- return sCommandLine.get() != null;
- }
-
- // Equivalent to CommandLine::ForCurrentProcess in C++.
- @VisibleForTesting
- public static CommandLine getInstance() {
- CommandLine commandLine = sCommandLine.get();
- assert commandLine != null;
- return commandLine;
- }
-
- /**
- * Initialize the singleton instance, must be called exactly once (either directly or
- * via one of the convenience wrappers below) before using the static singleton instance.
- * @param args command line flags in 'argv' format: args[0] is the program name.
- */
- public static void init(String[] args) {
- setInstance(new JavaCommandLine(args));
- }
-
- /**
- * Initialize the command line from the command-line file.
- *
- * @param file The fully qualified command line file.
- */
- public static void initFromFile(String file) {
- // Arbitrary clamp of 8k on the amount of file we read in.
- char[] buffer = readUtf8FileFully(file, 8 * 1024);
- init(buffer == null ? null : tokenizeQuotedAruments(buffer));
- }
-
- /**
- * Resets both the java proxy and the native command lines. This allows the entire
- * command line initialization to be re-run including the call to onJniLoaded.
- */
- @VisibleForTesting
- public static void reset() {
- setInstance(null);
- }
-
- /**
- * Public for testing (TODO: why are the tests in a different package?)
- * Parse command line flags from a flat buffer, supporting double-quote enclosed strings
- * containing whitespace. argv elements are derived by splitting the buffer on whitepace;
- * double quote characters may enclose tokens containing whitespace; a double-quote literal
- * may be escaped with back-slash. (Otherwise backslash is taken as a literal).
- * @param buffer A command line in command line file format as described above.
- * @return the tokenized arguments, suitable for passing to init().
- */
- public static String[] tokenizeQuotedAruments(char[] buffer) {
- ArrayList<String> args = new ArrayList<String>();
- StringBuilder arg = null;
- final char noQuote = '\0';
- final char singleQuote = '\'';
- final char doubleQuote = '"';
- char currentQuote = noQuote;
- for (char c : buffer) {
- // Detect start or end of quote block.
- if ((currentQuote == noQuote && (c == singleQuote || c == doubleQuote))
- || c == currentQuote) {
- if (arg != null && arg.length() > 0 && arg.charAt(arg.length() - 1) == '\\') {
- // Last char was a backslash; pop it, and treat c as a literal.
- arg.setCharAt(arg.length() - 1, c);
- } else {
- currentQuote = currentQuote == noQuote ? c : noQuote;
- }
- } else if (currentQuote == noQuote && Character.isWhitespace(c)) {
- if (arg != null) {
- args.add(arg.toString());
- arg = null;
- }
- } else {
- if (arg == null) arg = new StringBuilder();
- arg.append(c);
- }
- }
- if (arg != null) {
- if (currentQuote != noQuote) {
- Log.w(TAG, "Unterminated quoted string: " + arg);
- }
- args.add(arg.toString());
- }
- return args.toArray(new String[args.size()]);
- }
-
- private static final String TAG = "CommandLine";
- private static final String SWITCH_PREFIX = "--";
- private static final String SWITCH_TERMINATOR = SWITCH_PREFIX;
- private static final String SWITCH_VALUE_SEPARATOR = "=";
-
- public static void enableNativeProxy() {
- // Make a best-effort to ensure we make a clean (atomic) switch over from the old to
- // the new command line implementation. If another thread is modifying the command line
- // when this happens, all bets are off. (As per the native CommandLine).
- sCommandLine.set(new NativeCommandLine());
- }
-
- public static String[] getJavaSwitchesOrNull() {
- CommandLine commandLine = sCommandLine.get();
- if (commandLine != null) {
- assert !commandLine.isNativeImplementation();
- return ((JavaCommandLine) commandLine).getCommandLineArguments();
- }
- return null;
- }
-
- private static void setInstance(CommandLine commandLine) {
- CommandLine oldCommandLine = sCommandLine.getAndSet(commandLine);
- if (oldCommandLine != null && oldCommandLine.isNativeImplementation()) {
- nativeReset();
- }
- }
-
- /**
- * @param fileName the file to read in.
- * @param sizeLimit cap on the file size.
- * @return Array of chars read from the file, or null if the file cannot be read
- * or if its length exceeds |sizeLimit|.
- */
- private static char[] readUtf8FileFully(String fileName, int sizeLimit) {
- Reader reader = null;
- File f = new File(fileName);
- long fileLength = f.length();
-
- if (fileLength == 0) {
- return null;
- }
-
- if (fileLength > sizeLimit) {
- Log.w(TAG, "File " + fileName + " length " + fileLength + " exceeds limit "
- + sizeLimit);
- return null;
- }
-
- try {
- char[] buffer = new char[(int) fileLength];
- 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;
- } catch (FileNotFoundException e) {
- return null;
- } catch (IOException e) {
- return null;
- } finally {
- try {
- if (reader != null) reader.close();
- } catch (IOException e) {
- Log.e(TAG, "Unable to close file reader.", e);
- }
- }
- }
-
- private CommandLine() {}
-
- private static class JavaCommandLine extends CommandLine {
- private HashMap<String, String> mSwitches = new HashMap<String, String>();
- private ArrayList<String> mArgs = new ArrayList<String>();
-
- // The arguments begin at index 1, since index 0 contains the executable name.
- private int mArgsBegin = 1;
-
- JavaCommandLine(String[] args) {
- if (args == null || args.length == 0 || args[0] == null) {
- mArgs.add("");
- } else {
- mArgs.add(args[0]);
- appendSwitchesInternal(args, 1);
- }
- // Invariant: we always have the argv[0] program name element.
- assert mArgs.size() > 0;
- }
-
- /**
- * Returns the switches and arguments passed into the program, with switches and their
- * values coming before all of the arguments.
- */
- private String[] getCommandLineArguments() {
- return mArgs.toArray(new String[mArgs.size()]);
- }
-
- @Override
- public boolean hasSwitch(String switchString) {
- return mSwitches.containsKey(switchString);
- }
-
- @Override
- public String getSwitchValue(String switchString) {
- // This is slightly round about, but needed for consistency with the NativeCommandLine
- // version which does not distinguish empty values from key not present.
- String value = mSwitches.get(switchString);
- return value == null || value.isEmpty() ? null : value;
- }
-
- @Override
- public void appendSwitch(String switchString) {
- appendSwitchWithValue(switchString, null);
- }
-
- /**
- * Appends a switch to the current list.
- * @param switchString the switch to add. It should NOT start with '--' !
- * @param value the value for this switch.
- */
- @Override
- public void appendSwitchWithValue(String switchString, String value) {
- mSwitches.put(switchString, value == null ? "" : value);
-
- // Append the switch and update the switches/arguments divider mArgsBegin.
- String combinedSwitchString = SWITCH_PREFIX + switchString;
- if (value != null && !value.isEmpty()) {
- combinedSwitchString += SWITCH_VALUE_SEPARATOR + value;
- }
-
- mArgs.add(mArgsBegin++, combinedSwitchString);
- }
-
- @Override
- public void appendSwitchesAndArguments(String[] array) {
- appendSwitchesInternal(array, 0);
- }
-
- // Add the specified arguments, but skipping the first |skipCount| elements.
- private void appendSwitchesInternal(String[] array, int skipCount) {
- boolean parseSwitches = true;
- for (String arg : array) {
- if (skipCount > 0) {
- --skipCount;
- continue;
- }
-
- if (arg.equals(SWITCH_TERMINATOR)) {
- parseSwitches = false;
- }
-
- if (parseSwitches && arg.startsWith(SWITCH_PREFIX)) {
- String[] parts = arg.split(SWITCH_VALUE_SEPARATOR, 2);
- String value = parts.length > 1 ? parts[1] : null;
- appendSwitchWithValue(parts[0].substring(SWITCH_PREFIX.length()), value);
- } else {
- mArgs.add(arg);
- }
- }
- }
- }
-
- private static class NativeCommandLine extends CommandLine {
- @Override
- public boolean hasSwitch(String switchString) {
- return nativeHasSwitch(switchString);
- }
-
- @Override
- public String getSwitchValue(String switchString) {
- return nativeGetSwitchValue(switchString);
- }
-
- @Override
- public void appendSwitch(String switchString) {
- nativeAppendSwitch(switchString);
- }
-
- @Override
- public void appendSwitchWithValue(String switchString, String value) {
- nativeAppendSwitchWithValue(switchString, value);
- }
-
- @Override
- public void appendSwitchesAndArguments(String[] array) {
- nativeAppendSwitchesAndArguments(array);
- }
-
- @Override
- public boolean isNativeImplementation() {
- return true;
- }
- }
-
- private static native void nativeReset();
- private static native boolean nativeHasSwitch(String switchString);
- private static native String nativeGetSwitchValue(String switchString);
- private static native void nativeAppendSwitch(String switchString);
- private static native void nativeAppendSwitchWithValue(String switchString, String value);
- private static native void nativeAppendSwitchesAndArguments(String[] array);
-}
diff --git a/base/android/java/src/org/chromium/base/ContentUriUtils.java b/base/android/java/src/org/chromium/base/ContentUriUtils.java
deleted file mode 100644
index ef527e1cfa..0000000000
--- a/base/android/java/src/org/chromium/base/ContentUriUtils.java
+++ /dev/null
@@ -1,150 +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.ContentResolver;
-import android.content.Context;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.ParcelFileDescriptor;
-import android.util.Log;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-
-/**
- * This class provides methods to access content URI schemes.
- */
-public abstract class ContentUriUtils {
- private static final String TAG = "ContentUriUtils";
- private static FileProviderUtil sFileProviderUtil;
-
- /**
- * Provides functionality to translate a file into a content URI for use
- * with a content provider.
- */
- public interface FileProviderUtil {
- /**
- * Generate a content URI from the given file.
- * @param context Application context.
- * @param file The file to be translated.
- */
- Uri getContentUriFromFile(Context context, File file);
- }
-
- // Prevent instantiation.
- private ContentUriUtils() {}
-
- public static void setFileProviderUtil(FileProviderUtil util) {
- sFileProviderUtil = util;
- }
-
- public static Uri getContentUriFromFile(Context context, File file) {
- ThreadUtils.assertOnUiThread();
- if (sFileProviderUtil != null) {
- return sFileProviderUtil.getContentUriFromFile(context, file);
- }
- return null;
- }
-
- /**
- * Opens the content URI for reading, and returns the file descriptor to
- * the caller. The caller is responsible for closing the file desciptor.
- *
- * @param context {@link Context} in interest
- * @param uriString the content URI to open
- * @return file desciptor upon sucess, or -1 otherwise.
- */
- @CalledByNative
- public static int openContentUriForRead(Context context, String uriString) {
- ParcelFileDescriptor pfd = getParcelFileDescriptor(context, uriString);
- if (pfd != null) {
- return pfd.detachFd();
- }
- return -1;
- }
-
- /**
- * Check whether a content URI exists.
- *
- * @param context {@link Context} in interest.
- * @param uriString the content URI to query.
- * @return true if the URI exists, or false otherwise.
- */
- @CalledByNative
- public static boolean contentUriExists(Context context, String uriString) {
- return getParcelFileDescriptor(context, uriString) != null;
- }
-
- /**
- * Retrieve the MIME type for the content URI.
- *
- * @param context {@link Context} in interest.
- * @param uriString the content URI to look up.
- * @return MIME type or null if the input params are empty or invalid.
- */
- @CalledByNative
- public static String getMimeType(Context context, String uriString) {
- ContentResolver resolver = context.getContentResolver();
- if (resolver == null) return null;
- Uri uri = Uri.parse(uriString);
- return resolver.getType(uri);
- }
-
- /**
- * Helper method to open a content URI and returns the ParcelFileDescriptor.
- *
- * @param context {@link Context} in interest.
- * @param uriString the content URI to open.
- * @return ParcelFileDescriptor of the content URI, or NULL if the file does not exist.
- */
- private static ParcelFileDescriptor getParcelFileDescriptor(Context context, String uriString) {
- ContentResolver resolver = context.getContentResolver();
- Uri uri = Uri.parse(uriString);
-
- ParcelFileDescriptor pfd = null;
- try {
- pfd = resolver.openFileDescriptor(uri, "r");
- } catch (FileNotFoundException e) {
- Log.w(TAG, "Cannot find content uri: " + uriString, e);
- } catch (SecurityException e) {
- Log.w(TAG, "Cannot open content uri: " + uriString, e);
- } catch (IllegalArgumentException e) {
- Log.w(TAG, "Unknown content uri: " + uriString, e);
- }
- return pfd;
- }
-
- /**
- * Method to resolve the display name of a content URI.
- *
- * @param uri the content URI to be resolved.
- * @param contentResolver the content resolver to query.
- * @param columnField the column field to query.
- * @return the display name of the @code uri if present in the database
- * or an empty string otherwise.
- */
- public static String getDisplayName(
- Uri uri, ContentResolver contentResolver, String columnField) {
- if (contentResolver == null || uri == null) return "";
- Cursor cursor = null;
- try {
- cursor = contentResolver.query(uri, null, null, null, null);
-
- if (cursor != null && cursor.getCount() >= 1) {
- cursor.moveToFirst();
- int index = cursor.getColumnIndex(columnField);
- if (index > -1) return cursor.getString(index);
- }
- } catch (NullPointerException e) {
- // Some android models don't handle the provider call correctly.
- // see crbug.com/345393
- return "";
- } finally {
- if (cursor != null) cursor.close();
- }
- return "";
- }
-}
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 0e8a7abcdb..0000000000
--- a/base/android/java/src/org/chromium/base/CpuFeatures.java
+++ /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.
-
-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/EventLog.java b/base/android/java/src/org/chromium/base/EventLog.java
deleted file mode 100644
index 894de15bc7..0000000000
--- a/base/android/java/src/org/chromium/base/EventLog.java
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2014 The Chromium 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 interface to Android's EventLog to be used by native code.
- */
-@JNINamespace("base::android")
-public class EventLog {
-
- @CalledByNative
- public static void writeEvent(int tag, int value) {
- android.util.EventLog.writeEvent(tag, value);
- }
-}
diff --git a/base/android/java/src/org/chromium/base/FieldTrialList.java b/base/android/java/src/org/chromium/base/FieldTrialList.java
deleted file mode 100644
index 5fc9a1ff73..0000000000
--- a/base/android/java/src/org/chromium/base/FieldTrialList.java
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2014 The Chromium 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;
-
-/**
- * Helper to get field trial information.
- */
-public class FieldTrialList {
-
- private FieldTrialList() {}
-
- /**
- * @param trialName The name of the trial to get the group for.
- * @return The group name chosen for the named trial, or the empty string if the trial does
- * not exist.
- */
- public static String findFullName(String trialName) {
- return nativeFindFullName(trialName);
- }
-
- /**
- * @param trialName The name of the trial to get the group for.
- * @return Whether the trial exists or not.
- */
- public static boolean trialExists(String trialName) {
- return nativeTrialExists(trialName);
- }
-
- private static native String nativeFindFullName(String trialName);
- private static native boolean nativeTrialExists(String trialName);
-}
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 3921cea1a8..0000000000
--- a/base/android/java/src/org/chromium/base/ImportantFileWriterAndroid.java
+++ /dev/null
@@ -1,29 +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;
-
-/**
- * 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/JNIAdditionalImport.java b/base/android/java/src/org/chromium/base/JNIAdditionalImport.java
deleted file mode 100644
index 499d158ad8..0000000000
--- a/base/android/java/src/org/chromium/base/JNIAdditionalImport.java
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2014 The Chromium 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;
-
-/**
- * JNIAdditionalImport is used by the JNI generator to qualify inner types used on JNI methods. Must
- * be used when an inner class is used from a class within the same package. Example:
- *
- * <pre>
- * @JNIAdditionImport(Foo.class)
- * public class Bar {
- * @CalledByNative static void doSomethingWithInner(Foo.Inner inner) {
- * ...
- * }
- * }
- * <pre>
- * <p>
- * Notes:
- * 1) Foo must be in the same package as Bar
- * 2) For classes in different packages, they should be imported as:
- * import other.package.Foo;
- * and this annotation should not be used.
- */
-@Target(ElementType.TYPE)
-@Retention(RetentionPolicy.CLASS)
-public @interface JNIAdditionalImport {
- Class<?>[] value();
-}
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 5ad7a42fd8..0000000000
--- a/base/android/java/src/org/chromium/base/JNINamespace.java
+++ /dev/null
@@ -1,20 +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.
-
-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/JNIUtils.java b/base/android/java/src/org/chromium/base/JNIUtils.java
deleted file mode 100644
index 6f6cd54fb8..0000000000
--- a/base/android/java/src/org/chromium/base/JNIUtils.java
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2014 The Chromium 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 JNI-related methods to the native library.
- */
-public class JNIUtils {
- /**
- * This returns a ClassLoader that is capable of loading Chromium Java code. Such a ClassLoader
- * is needed for the few cases where the JNI mechanism is unable to automatically determine the
- * appropriate ClassLoader instance.
- */
- @CalledByNative
- public static Object getClassLoader() {
- return JNIUtils.class.getClassLoader();
- }
-}
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 3153a9bdd9..0000000000
--- a/base/android/java/src/org/chromium/base/JavaHandlerThread.java
+++ /dev/null
@@ -1,56 +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.annotation.TargetApi;
-import android.os.Build;
-import android.os.Handler;
-import android.os.HandlerThread;
-
-/**
- * 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 long nativeThread, final long nativeEvent) {
- mThread.start();
- new Handler(mThread.getLooper()).post(new Runnable() {
- @Override
- public void run() {
- nativeInitializeThread(nativeThread, nativeEvent);
- }
- });
- }
-
- @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
- @CalledByNative
- private void stop(final long nativeThread, final long nativeEvent) {
- final boolean quitSafely = Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2;
- new Handler(mThread.getLooper()).post(new Runnable() {
- @Override
- public void run() {
- nativeStopThread(nativeThread, nativeEvent);
- if (!quitSafely) mThread.quit();
- }
- });
- if (quitSafely) mThread.quitSafely();
- }
-
- private native void nativeInitializeThread(long nativeJavaHandlerThread, long nativeEvent);
- private native void nativeStopThread(long nativeJavaHandlerThread, long nativeEvent);
-}
diff --git a/base/android/java/src/org/chromium/base/LocaleUtils.java b/base/android/java/src/org/chromium/base/LocaleUtils.java
deleted file mode 100644
index 82b2c8fc66..0000000000
--- a/base/android/java/src/org/chromium/base/LocaleUtils.java
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2014 The Chromium 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.util.Locale;
-
-/**
- * This class provides the locale related methods.
- */
-public class LocaleUtils {
- /**
- * Guards this class from being instantiated.
- */
- private LocaleUtils() {
- }
-
- /**
- * @return the default locale, translating Android deprecated
- * language codes into the modern ones used by Chromium.
- */
- @CalledByNative
- public static String getDefaultLocale() {
- Locale locale = Locale.getDefault();
- String language = locale.getLanguage();
- String country = locale.getCountry();
-
- // Android uses deprecated lanuages codes for Hebrew and Indonesian but Chromium uses the
- // updated codes. Also, Android uses "tl" while Chromium uses "fil" for Tagalog/Filipino.
- // So apply a mapping.
- // See http://developer.android.com/reference/java/util/Locale.html
- if ("iw".equals(language)) {
- language = "he";
- } else if ("in".equals(language)) {
- language = "id";
- } else if ("tl".equals(language)) {
- language = "fil";
- }
- return country.isEmpty() ? language : language + "-" + country;
- }
-
- /**
- * Get the default country code set during install.
- * @return country code.
- */
- @CalledByNative
- private static String getDefaultCountryCode() {
- CommandLine commandLine = CommandLine.getInstance();
- return commandLine.hasSwitch(BaseSwitches.DEFAULT_COUNTRY_CODE_AT_INSTALL)
- ? commandLine.getSwitchValue(BaseSwitches.DEFAULT_COUNTRY_CODE_AT_INSTALL)
- : Locale.getDefault().getCountry();
- }
-
-}
diff --git a/base/android/java/src/org/chromium/base/Log.java b/base/android/java/src/org/chromium/base/Log.java
deleted file mode 100644
index 4a1a00de3b..0000000000
--- a/base/android/java/src/org/chromium/base/Log.java
+++ /dev/null
@@ -1,353 +0,0 @@
-// Copyright 2015 The Chromium 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.text.TextUtils;
-
-import org.chromium.base.annotations.NoSideEffects;
-
-import java.util.Locale;
-
-/**
- * Utility class for Logging.
- *
- * <p>
- * Defines logging access points for each feature. They format and forward the logs to
- * {@link android.util.Log}, allowing to standardize the output, to make it easy to identify
- * the origin of logs, and enable or disable logging in different parts of the code.
- * </p>
- * <p>
- * @see usage documentation: <a href="README_logging.md">README_logging.md</a>.
- * </p>
- */
-public class Log {
- /** Convenience property, same as {@link android.util.Log#ASSERT}. */
- public static final int ASSERT = android.util.Log.ASSERT;
-
- /** Convenience property, same as {@link android.util.Log#DEBUG}. */
- public static final int DEBUG = android.util.Log.DEBUG;
-
- /** Convenience property, same as {@link android.util.Log#ERROR}. */
- public static final int ERROR = android.util.Log.ERROR;
-
- /** Convenience property, same as {@link android.util.Log#INFO}. */
- public static final int INFO = android.util.Log.INFO;
-
- /** Convenience property, same as {@link android.util.Log#VERBOSE}. */
- public static final int VERBOSE = android.util.Log.VERBOSE;
-
- /** Convenience property, same as {@link android.util.Log#WARN}. */
- public static final int WARN = android.util.Log.WARN;
-
- private Log() {
- // Static only access
- }
-
- /** Returns a formatted log message, using the supplied format and arguments.*/
- private static String formatLog(String messageTemplate, Object... params) {
- if (params != null && params.length != 0) {
- messageTemplate = String.format(Locale.US, messageTemplate, params);
- }
-
- return messageTemplate;
- }
-
- /**
- * Returns a formatted log message, using the supplied format and arguments.
- * The message will be prepended with the filename and line number of the call.
- */
- private static String formatLogWithStack(String messageTemplate, Object... params) {
- return "[" + getCallOrigin() + "] " + formatLog(messageTemplate, params);
- }
-
- /**
- * Returns a full tag for the provided group tag. Full tags longer than 23 characters
- * will cause a runtime exception.
- *
- * @param groupTag {@code null} and empty string are allowed.
- *
- * @see android.util.Log#isLoggable(String, int)
- * @throws IllegalArgumentException if the tag is too long.
- * @deprecated Directly use a string (e.g. "cr.Tag") in your class. See http://crbug.com/485772
- */
- @Deprecated
- public static String makeTag(String groupTag) {
- if (TextUtils.isEmpty(groupTag)) return "cr";
- String tag = "cr." + groupTag;
- if (tag.length() > 23) {
- throw new IllegalArgumentException(
- "The full tag (" + tag + ") is longer than 23 characters.");
- }
- return tag;
- }
-
- /** Convenience function, forwards to {@link android.util.Log#isLoggable(String, int)}. */
- public static boolean isLoggable(String tag, int level) {
- return android.util.Log.isLoggable(tag, level);
- }
-
- /**
- * Sends a {@link android.util.Log#VERBOSE} log message.
- *
- * For optimization purposes, only the fixed parameters versions are visible. If you need more
- * than 7 parameters, consider building your log message using a function annotated with
- * {@link NoSideEffects}.
- *
- * @param tag Used to identify the source of a log message.
- * @param messageTemplate The message you would like logged. It is to be specified as a format
- * string.
- * @param args Arguments referenced by the format specifiers in the format string. If the last
- * one is a {@link Throwable}, its trace will be printed.
- */
- private static void verbose(String tag, String messageTemplate, Object... args) {
- if (Log.isLoggable(tag, Log.VERBOSE)) {
- String message = formatLogWithStack(messageTemplate, args);
- Throwable tr = getThrowableToLog(args);
- if (tr != null) {
- android.util.Log.v(tag, message, tr);
- } else {
- android.util.Log.v(tag, message);
- }
- }
- }
-
- /** Sends a {@link android.util.Log#VERBOSE} log message. 0 arg version. */
- public static void v(String tag, String message) {
- verbose(tag, message);
- }
-
- /** Sends a {@link android.util.Log#VERBOSE} log message. 1 arg version. */
- public static void v(String tag, String messageTemplate, Object arg1) {
- verbose(tag, messageTemplate, arg1);
- }
-
- /** Sends a {@link android.util.Log#VERBOSE} log message. 2 args version */
- public static void v(String tag, String messageTemplate, Object arg1, Object arg2) {
- verbose(tag, messageTemplate, arg1, arg2);
- }
-
- /** Sends a {@link android.util.Log#VERBOSE} log message. 3 args version */
- public static void v(
- String tag, String messageTemplate, Object arg1, Object arg2, Object arg3) {
- verbose(tag, messageTemplate, arg1, arg2, arg3);
- }
-
- /** Sends a {@link android.util.Log#VERBOSE} log message. 4 args version */
- public static void v(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
- Object arg4) {
- verbose(tag, messageTemplate, arg1, arg2, arg3, arg4);
- }
-
- /** Sends a {@link android.util.Log#VERBOSE} log message. 5 args version */
- public static void v(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
- Object arg4, Object arg5) {
- verbose(tag, messageTemplate, arg1, arg2, arg3, arg4, arg5);
- }
-
- /** Sends a {@link android.util.Log#VERBOSE} log message. 6 args version */
- public static void v(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
- Object arg4, Object arg5, Object arg6) {
- verbose(tag, messageTemplate, arg1, arg2, arg3, arg4, arg5, arg6);
- }
-
- /** Sends a {@link android.util.Log#VERBOSE} log message. 7 args version */
- public static void v(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
- Object arg4, Object arg5, Object arg6, Object arg7) {
- verbose(tag, messageTemplate, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
- }
-
- /**
- * Sends a {@link android.util.Log#DEBUG} log message.
- *
- * For optimization purposes, only the fixed parameters versions are visible. If you need more
- * than 7 parameters, consider building your log message using a function annotated with
- * {@link NoSideEffects}.
- *
- * @param tag Used to identify the source of a log message.
- * @param messageTemplate The message you would like logged. It is to be specified as a format
- * string.
- * @param args Arguments referenced by the format specifiers in the format string. If the last
- * one is a {@link Throwable}, its trace will be printed.
- */
- private static void debug(String tag, String messageTemplate, Object... args) {
- if (isLoggable(tag, Log.DEBUG)) {
- String message = formatLogWithStack(messageTemplate, args);
- Throwable tr = getThrowableToLog(args);
- if (tr != null) {
- android.util.Log.d(tag, message, tr);
- } else {
- android.util.Log.d(tag, message);
- }
- }
- }
-
- /** Sends a {@link android.util.Log#DEBUG} log message. 0 arg version. */
- public static void d(String tag, String message) {
- debug(tag, message);
- }
-
- /** Sends a {@link android.util.Log#DEBUG} log message. 1 arg version. */
- public static void d(String tag, String messageTemplate, Object arg1) {
- debug(tag, messageTemplate, arg1);
- }
- /** Sends a {@link android.util.Log#DEBUG} log message. 2 args version */
- public static void d(String tag, String messageTemplate, Object arg1, Object arg2) {
- debug(tag, messageTemplate, arg1, arg2);
- }
- /** Sends a {@link android.util.Log#DEBUG} log message. 3 args version */
- public static void d(
- String tag, String messageTemplate, Object arg1, Object arg2, Object arg3) {
- debug(tag, messageTemplate, arg1, arg2, arg3);
- }
-
- /** Sends a {@link android.util.Log#DEBUG} log message. 4 args version */
- public static void d(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
- Object arg4) {
- debug(tag, messageTemplate, arg1, arg2, arg3, arg4);
- }
-
- /** Sends a {@link android.util.Log#DEBUG} log message. 5 args version */
- public static void d(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
- Object arg4, Object arg5) {
- debug(tag, messageTemplate, arg1, arg2, arg3, arg4, arg5);
- }
-
- /** Sends a {@link android.util.Log#DEBUG} log message. 6 args version */
- public static void d(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
- Object arg4, Object arg5, Object arg6) {
- debug(tag, messageTemplate, arg1, arg2, arg3, arg4, arg5, arg6);
- }
-
- /** Sends a {@link android.util.Log#DEBUG} log message. 7 args version */
- public static void d(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
- Object arg4, Object arg5, Object arg6, Object arg7) {
- debug(tag, messageTemplate, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
- }
-
- /**
- * Sends an {@link android.util.Log#INFO} log message.
- *
- * @param tag Used to identify the source of a log message.
- * @param messageTemplate The message you would like logged. It is to be specified as a format
- * string.
- * @param args Arguments referenced by the format specifiers in the format string. If the last
- * one is a {@link Throwable}, its trace will be printed.
- */
- @VisibleForTesting
- public static void i(String tag, String messageTemplate, Object... args) {
- if (Log.isLoggable(tag, Log.INFO)) {
- String message = formatLog(messageTemplate, args);
- Throwable tr = getThrowableToLog(args);
- if (tr != null) {
- android.util.Log.i(tag, message, tr);
- } else {
- android.util.Log.i(tag, message);
- }
- }
- }
-
- /**
- * Sends a {@link android.util.Log#WARN} log message.
- *
- * @param tag Used to identify the source of a log message.
- * @param messageTemplate The message you would like logged. It is to be specified as a format
- * string.
- * @param args Arguments referenced by the format specifiers in the format string. If the last
- * one is a {@link Throwable}, its trace will be printed.
- */
- @VisibleForTesting
- public static void w(String tag, String messageTemplate, Object... args) {
- if (Log.isLoggable(tag, Log.WARN)) {
- String message = formatLog(messageTemplate, args);
- Throwable tr = getThrowableToLog(args);
- if (tr != null) {
- android.util.Log.w(tag, message, tr);
- } else {
- android.util.Log.w(tag, message);
- }
- }
- }
-
- /**
- * Sends an {@link android.util.Log#ERROR} log message.
- *
- * @param tag Used to identify the source of a log message.
- * @param messageTemplate The message you would like logged. It is to be specified as a format
- * string.
- * @param args Arguments referenced by the format specifiers in the format string. If the last
- * one is a {@link Throwable}, its trace will be printed.
- */
- @VisibleForTesting
- public static void e(String tag, String messageTemplate, Object... args) {
- if (Log.isLoggable(tag, Log.ERROR)) {
- String message = formatLog(messageTemplate, args);
- Throwable tr = getThrowableToLog(args);
- if (tr != null) {
- android.util.Log.e(tag, message, tr);
- } else {
- android.util.Log.e(tag, message);
- }
- }
- }
-
- /**
- * What a Terrible Failure: Used for conditions that should never happen, and logged at
- * the {@link android.util.Log#ASSERT} level. Depending on the configuration, it might
- * terminate the process.
- *
- * @see android.util.Log#wtf(String, String, Throwable)
- *
- * @param tag Used to identify the source of a log message.
- * @param messageTemplate The message you would like logged. It is to be specified as a format
- * string.
- * @param args Arguments referenced by the format specifiers in the format string. If the last
- * one is a {@link Throwable}, its trace will be printed.
- */
- @VisibleForTesting
- public static void wtf(String tag, String messageTemplate, Object... args) {
- if (Log.isLoggable(tag, Log.ASSERT)) {
- String message = formatLog(messageTemplate, args);
- Throwable tr = getThrowableToLog(args);
- if (tr != null) {
- android.util.Log.wtf(tag, message, tr);
- } else {
- android.util.Log.wtf(tag, message);
- }
- }
- }
-
- private static Throwable getThrowableToLog(Object[] args) {
- if (args == null || args.length == 0) return null;
-
- Object lastArg = args[args.length - 1];
-
- if (!(lastArg instanceof Throwable)) return null;
- return (Throwable) lastArg;
- }
-
- /** Returns a string form of the origin of the log call, to be used as secondary tag.*/
- private static String getCallOrigin() {
- StackTraceElement[] st = Thread.currentThread().getStackTrace();
-
- // The call stack should look like:
- // n [a variable number of calls depending on the vm used]
- // +0 getCallOrigin()
- // +1 privateLogFunction: verbose or debug
- // +2 formatLogWithStack()
- // +3 logFunction: v or d
- // +4 caller
-
- int callerStackIndex;
- String logClassName = Log.class.getName();
- for (callerStackIndex = 0; callerStackIndex < st.length; callerStackIndex++) {
- if (st[callerStackIndex].getClassName().equals(logClassName)) {
- callerStackIndex += 4;
- break;
- }
- }
-
- return st[callerStackIndex].getFileName() + ":" + st[callerStackIndex].getLineNumber();
- }
-}
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 7979287b4d..0000000000
--- a/base/android/java/src/org/chromium/base/MemoryPressureListener.java
+++ /dev/null
@@ -1,114 +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.Activity;
-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 for levels that are considered actionable.
- */
-public class MemoryPressureListener {
- /**
- * Sending an intent with this action to Chrome will cause it to issue a call to onLowMemory
- * thus simulating a low memory situations.
- */
- private static final String ACTION_LOW_MEMORY = "org.chromium.base.ACTION_LOW_MEMORY";
-
- /**
- * Sending an intent with this action to Chrome will cause it to issue a call to onTrimMemory
- * thus simulating a low memory situations.
- */
- private static final String ACTION_TRIM_MEMORY = "org.chromium.base.ACTION_TRIM_MEMORY";
-
- /**
- * Sending an intent with this action to Chrome will cause it to issue a call to onTrimMemory
- * with notification level TRIM_MEMORY_RUNNING_CRITICAL thus simulating a low memory situation
- */
- private static final String ACTION_TRIM_MEMORY_RUNNING_CRITICAL =
- "org.chromium.base.ACTION_TRIM_MEMORY_RUNNING_CRITICAL";
-
- /**
- * Sending an intent with this action to Chrome will cause it to issue a call to onTrimMemory
- * with notification level TRIM_MEMORY_MODERATE thus simulating a low memory situation
- */
- private static final String ACTION_TRIM_MEMORY_MODERATE =
- "org.chromium.base.ACTION_TRIM_MEMORY_MODERATE";
-
- @CalledByNative
- private static void registerSystemCallback(Context context) {
- context.registerComponentCallbacks(
- new ComponentCallbacks2() {
- @Override
- public void onTrimMemory(int level) {
- maybeNotifyMemoryPresure(level);
- }
-
- @Override
- public void onLowMemory() {
- nativeOnMemoryPressure(MemoryPressureLevel.CRITICAL);
- }
-
- @Override
- public void onConfigurationChanged(Configuration configuration) {
- }
- });
- }
-
- /**
- * Used by applications to simulate a memory pressure signal. By throwing certain intent
- * actions.
- */
- public static boolean handleDebugIntent(Activity activity, String action) {
- if (ACTION_LOW_MEMORY.equals(action)) {
- simulateLowMemoryPressureSignal(activity);
- } else if (ACTION_TRIM_MEMORY.equals(action)) {
- simulateTrimMemoryPressureSignal(activity, ComponentCallbacks2.TRIM_MEMORY_COMPLETE);
- } else if (ACTION_TRIM_MEMORY_RUNNING_CRITICAL.equals(action)) {
- simulateTrimMemoryPressureSignal(activity,
- ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL);
- } else if (ACTION_TRIM_MEMORY_MODERATE.equals(action)) {
- simulateTrimMemoryPressureSignal(activity, ComponentCallbacks2.TRIM_MEMORY_MODERATE);
- } else {
- return false;
- }
-
- return true;
- }
-
- public static void maybeNotifyMemoryPresure(int level) {
- if (level >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE) {
- nativeOnMemoryPressure(MemoryPressureLevel.CRITICAL);
- } else if (level >= ComponentCallbacks2.TRIM_MEMORY_BACKGROUND
- || level == ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL) {
- // Don't notifiy on TRIM_MEMORY_UI_HIDDEN, since this class only
- // dispatches actionable memory pressure signals to native.
- nativeOnMemoryPressure(MemoryPressureLevel.MODERATE);
- }
- }
-
- private static void simulateLowMemoryPressureSignal(Activity activity) {
- // The Application and the Activity each have a list of callbacks they notify when this
- // method is called. Notifying these will simulate the event at the App/Activity level
- // as well as trigger the listener bound from native in this process.
- activity.getApplication().onLowMemory();
- activity.onLowMemory();
- }
-
- private static void simulateTrimMemoryPressureSignal(Activity activity, int level) {
- // The Application and the Activity each have a list of callbacks they notify when this
- // method is called. Notifying these will simulate the event at the App/Activity level
- // as well as trigger the listener bound from native in this process.
- activity.getApplication().onTrimMemory(level);
- activity.onTrimMemory(level);
- }
-
- private static native void nativeOnMemoryPressure(int memoryPressureType);
-}
diff --git a/base/android/java/src/org/chromium/base/NativeCall.java b/base/android/java/src/org/chromium/base/NativeCall.java
deleted file mode 100644
index 352edf7da5..0000000000
--- a/base/android/java/src/org/chromium/base/NativeCall.java
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2014 The Chromium 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;
-
-/**
- * @NativeCall is used by the JNI generator to create the necessary JNI bindings
- * so a native function can be bound to a Java inner class. The native class for
- * which the JNI method will be generated is specified by the first parameter.
- */
-@Target(ElementType.METHOD)
-@Retention(RetentionPolicy.CLASS)
-public @interface NativeCall {
- /*
- * Value determines which native class the method should map to.
- */
- public String value() default "";
-}
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 e55b18c1fb..0000000000
--- a/base/android/java/src/org/chromium/base/NativeClassQualifiedName.java
+++ /dev/null
@@ -1,25 +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.
-
-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/OWNERS b/base/android/java/src/org/chromium/base/OWNERS
deleted file mode 100644
index d99aec1c06..0000000000
--- a/base/android/java/src/org/chromium/base/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-per-file ApiCompatibilityUtils.java=aurimas@chromium.org
-per-file ApiCompatibilityUtils.java=newt@chromium.org
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 7a2ab984fe..0000000000
--- a/base/android/java/src/org/chromium/base/ObserverList.java
+++ /dev/null
@@ -1,249 +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.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.
- * <p/>
- * 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.
- * <p/>
- * 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().
- * <p/>
- * This class is not threadsafe. Observers MUST be added, removed and will be notified on the same
- * thread this is created.
- *
- * @param <E> The type of observers that this list should hold.
- */
-@NotThreadSafe
-public class ObserverList<E> implements Iterable<E> {
- /**
- * Extended iterator interface that provides rewind functionality.
- */
- public interface RewindableIterator<E> extends Iterator<E> {
- /**
- * Rewind the iterator back to the beginning.
- *
- * If we need to iterate multiple times, we can avoid iterator object reallocation by using
- * this method.
- */
- public void rewind();
- }
-
- public final List<E> mObservers = new ArrayList<E>();
- private int mIterationDepth = 0;
- private int mCount = 0;
- private boolean mNeedsCompact = false;
-
- public ObserverList() {}
-
- /**
- * Add an observer to the list.
- * <p/>
- * 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.
- *
- * @return true if the observer list changed as a result of the call.
- */
- public boolean addObserver(E obs) {
- // Avoid adding null elements to the list as they may be removed on a compaction.
- if (obs == null || mObservers.contains(obs)) {
- return false;
- }
-
- // Structurally modifying the underlying list here. This means we
- // cannot use the underlying list's iterator to iterate over the list.
- boolean result = mObservers.add(obs);
- assert result;
-
- ++mCount;
- return true;
- }
-
- /**
- * Remove an observer from the list if it is in the list.
- *
- * @return true if an element was removed as a result of this call.
- */
- public boolean removeObserver(E obs) {
- if (obs == null) {
- return false;
- }
-
- int index = mObservers.indexOf(obs);
- if (index == -1) {
- return false;
- }
-
- if (mIterationDepth == 0) {
- // No one is iterating over the list.
- mObservers.remove(index);
- } else {
- mNeedsCompact = true;
- mObservers.set(index, null);
- }
- --mCount;
- assert mCount >= 0;
-
- return true;
- }
-
- public boolean hasObserver(E obs) {
- return mObservers.contains(obs);
- }
-
- public void clear() {
- mCount = 0;
-
- if (mIterationDepth == 0) {
- mObservers.clear();
- return;
- }
-
- int size = mObservers.size();
- mNeedsCompact |= size != 0;
- for (int i = 0; i < size; i++) {
- mObservers.set(i, null);
- }
- }
-
- @Override
- public Iterator<E> iterator() {
- return new ObserverListIterator();
- }
-
- /**
- * It's the same as {@link ObserverList#iterator()} but the return type is
- * {@link RewindableIterator}. Use this iterator type if you need to use
- * {@link RewindableIterator#rewind()}.
- */
- public RewindableIterator<E> rewindableIterator() {
- return new ObserverListIterator();
- }
-
- /**
- * Returns the number of observers currently registered in the ObserverList.
- * This is equivalent to the number of non-empty spaces in |mObservers|.
- */
- public int size() {
- return mCount;
- }
-
- /**
- * Returns true if the ObserverList contains no observers.
- */
- public boolean isEmpty() {
- return mCount == 0;
- }
-
- /**
- * Compact the underlying list be removing null elements.
- * <p/>
- * Should only be called when mIterationDepth is zero.
- */
- private void compact() {
- assert mIterationDepth == 0;
- for (int i = mObservers.size() - 1; i >= 0; i--) {
- if (mObservers.get(i) == null) {
- mObservers.remove(i);
- }
- }
- }
-
- private void incrementIterationDepth() {
- mIterationDepth++;
- }
-
- private void decrementIterationDepthAndCompactIfNeeded() {
- mIterationDepth--;
- assert mIterationDepth >= 0;
- if (mIterationDepth > 0) return;
- if (!mNeedsCompact) return;
- mNeedsCompact = false;
- compact();
- }
-
- /**
- * Returns the size of the underlying storage of the ObserverList.
- * It will take into account the empty spaces inside |mObservers|.
- */
- private int capacity() {
- return mObservers.size();
- }
-
- private E getObserverAt(int index) {
- return mObservers.get(index);
- }
-
- private class ObserverListIterator implements RewindableIterator<E> {
- private int mListEndMarker;
- private int mIndex = 0;
- private boolean mIsExhausted = false;
-
- private ObserverListIterator() {
- ObserverList.this.incrementIterationDepth();
- mListEndMarker = ObserverList.this.capacity();
- }
-
- @Override
- public void rewind() {
- compactListIfNeeded();
- ObserverList.this.incrementIterationDepth();
- mListEndMarker = ObserverList.this.capacity();
- mIsExhausted = false;
- mIndex = 0;
- }
-
- @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/PackageUtils.java b/base/android/java/src/org/chromium/base/PackageUtils.java
deleted file mode 100644
index b1cb29e3f7..0000000000
--- a/base/android/java/src/org/chromium/base/PackageUtils.java
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2015 The Chromium 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.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-
-/**
- * This class provides package checking related methods.
- */
-public class PackageUtils {
- /**
- * Retrieves the PackageInfo object for this application.
- *
- * @param context Any context.
- * @return The PackageInfo object for this application.
- */
- public static PackageInfo getOwnPackageInfo(Context context) {
- PackageManager manager = context.getPackageManager();
- try {
- String packageName = context.getApplicationContext().getPackageName();
- return manager.getPackageInfo(packageName, 0);
- } catch (NameNotFoundException e) {
- // Should never happen.
- throw new AssertionError("Failed to retrieve own package info");
- }
- }
-
- /**
- * Retrieves the version of the given package installed on the device.
- *
- * @param context Any context.
- * @param packageName Name of the package to find.
- * @return The package's version code if found, -1 otherwise.
- */
- public static int getPackageVersion(Context context, String packageName) {
- int versionCode = -1;
- PackageManager pm = context.getPackageManager();
- try {
- PackageInfo packageInfo = pm.getPackageInfo(packageName, 0);
- if (packageInfo != null) versionCode = packageInfo.versionCode;
- } catch (PackageManager.NameNotFoundException e) {
- // Do nothing, versionCode stays -1
- }
- return versionCode;
- }
-
- private PackageUtils() {
- // Hide constructor
- }
-}
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 b22328c663..0000000000
--- a/base/android/java/src/org/chromium/base/PathService.java
+++ /dev/null
@@ -1,24 +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.
-
-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 e46fc300e8..0000000000
--- a/base/android/java/src/org/chromium/base/PathUtils.java
+++ /dev/null
@@ -1,127 +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.
-
-package org.chromium.base;
-
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.os.AsyncTask;
-import android.os.Environment;
-
-import java.util.concurrent.ExecutionException;
-
-/**
- * This class provides the path related methods for the native library.
- */
-public abstract class PathUtils {
-
- private static final int DATA_DIRECTORY = 0;
- private static final int DATABASE_DIRECTORY = 1;
- private static final int CACHE_DIRECTORY = 2;
- private static final int NUM_DIRECTORIES = 3;
- private static AsyncTask<String, Void, String[]> sDirPathFetchTask;
-
- // Prevent instantiation.
- private PathUtils() {}
-
- /**
- * Starts an asynchronous task to fetch the path of 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, Context context) {
- final Context appContext = context.getApplicationContext();
- sDirPathFetchTask = new AsyncTask<String, Void, String[]>() {
- @Override
- protected String[] doInBackground(String... dataDirectorySuffix) {
- String[] paths = new String[NUM_DIRECTORIES];
- paths[DATA_DIRECTORY] =
- appContext.getDir(dataDirectorySuffix[0], Context.MODE_PRIVATE).getPath();
- paths[DATABASE_DIRECTORY] = appContext.getDatabasePath("foo").getParent();
- // TODO(wnwen): Find a way to avoid calling this function in renderer process.
- if (appContext.getCacheDir() != null) {
- paths[CACHE_DIRECTORY] = appContext.getCacheDir().getPath();
- }
- return paths;
- }
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, suffix);
- }
-
- /**
- * @param index The index of the cached directory path.
- * @return The directory path requested, or null if not available.
- */
- private static String getDirectoryPath(int index) {
- try {
- return sDirPathFetchTask.get()[index];
- } catch (InterruptedException e) {
- } catch (ExecutionException e) {
- }
- return null;
- }
-
- /**
- * @return the private directory that is used to store application data.
- */
- @CalledByNative
- public static String getDataDirectory(Context appContext) {
- assert sDirPathFetchTask != null : "setDataDirectorySuffix must be called first.";
- return getDirectoryPath(DATA_DIRECTORY);
- }
-
- /**
- * @return the private directory that is used to store application database.
- */
- @CalledByNative
- public static String getDatabaseDirectory(Context appContext) {
- assert sDirPathFetchTask != null : "setDataDirectorySuffix must be called first.";
- return getDirectoryPath(DATABASE_DIRECTORY);
- }
-
- /**
- * @return the cache directory.
- */
- @SuppressWarnings("unused")
- @CalledByNative
- public static String getCacheDirectory(Context appContext) {
- assert sDirPathFetchTask != null : "setDataDirectorySuffix must be called first.";
- return getDirectoryPath(CACHE_DIRECTORY);
- }
-
- /**
- * @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/PerfTraceEvent.java b/base/android/java/src/org/chromium/base/PerfTraceEvent.java
deleted file mode 100644
index c0e4b2125f..0000000000
--- a/base/android/java/src/org/chromium/base/PerfTraceEvent.java
+++ /dev/null
@@ -1,379 +0,0 @@
-// Copyright 2014 The Chromium 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.Debug;
-import android.os.Debug.MemoryInfo;
-import android.util.Log;
-
-import org.chromium.base.annotations.SuppressFBWarnings;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.PrintStream;
-import java.util.LinkedList;
-import java.util.List;
-
-/**
- * PerfTraceEvent can be used like TraceEvent, but is intended for
- * performance measurement. By limiting the types of tracing we hope
- * to minimize impact on measurement.
- *
- * All PerfTraceEvent events funnel into TraceEvent. When not doing
- * performance measurements, they act the same. However,
- * PerfTraceEvents can be enabled even when TraceEvent is not.
- *
- * Unlike TraceEvent, PerfTraceEvent data is sent to the system log,
- * not to a trace file.
- *
- * Performance events need to have very specific names so we find
- * the right ones. For example, we specify the name exactly in
- * the @TracePerf annotation. Thus, unlike TraceEvent, we do not
- * support an implicit trace name based on the callstack.
- */
-@SuppressFBWarnings("CHROMIUM_SYNCHRONIZED_METHOD")
-public class PerfTraceEvent {
- private static final int MAX_NAME_LENGTH = 40;
- private static final String MEMORY_TRACE_NAME_SUFFIX = "_BZR_PSS";
- private static File sOutputFile = null;
-
- /** The event types understood by the perf trace scripts. */
- private enum EventType {
- START("S"),
- FINISH("F"),
- INSTANT("I");
-
- // The string understood by the trace scripts.
- private final String mTypeStr;
-
- EventType(String typeStr) {
- mTypeStr = typeStr;
- }
-
- @Override
- public String toString() {
- return mTypeStr;
- }
- }
-
- private static boolean sEnabled = false;
- private static boolean sTrackTiming = true;
- private static boolean sTrackMemory = false;
-
- // A list of performance trace event strings.
- // Events are stored as a JSON dict much like TraceEvent.
- // E.g. timestamp is in microseconds.
- private static JSONArray sPerfTraceStrings;
-
- // A filter for performance tracing. Only events that match a
- // string in the list are saved. Presence of a filter does not
- // necessarily mean perf tracing is enabled.
- private static List<String> sFilter;
-
- // Nanosecond start time of performance tracing.
- private static long sBeginNanoTime;
-
- /**
- * Specifies what event names will be tracked.
- *
- * @param strings Event names we will record.
- */
- @VisibleForTesting
- public static synchronized void setFilter(List<String> strings) {
- sFilter = new LinkedList<String>(strings);
- }
-
- /**
- * Enable or disable perf tracing.
- * Disabling of perf tracing will dump trace data to the system log.
- */
- @VisibleForTesting
- public static synchronized void setEnabled(boolean enabled) {
- if (sEnabled == enabled) {
- return;
- }
- if (enabled) {
- sBeginNanoTime = System.nanoTime();
- sPerfTraceStrings = new JSONArray();
- } else {
- dumpPerf();
- sPerfTraceStrings = null;
- sFilter = null;
- }
- sEnabled = enabled;
- }
-
- /**
- * Enables memory tracking for all timing perf events tracked.
- *
- * <p>
- * Only works when called in combination with {@link #setEnabled(boolean)}.
- *
- * <p>
- * By enabling this feature, an additional perf event containing the memory usage will be
- * logged whenever {@link #instant(String)}, {@link #begin(String)}, or {@link #end(String)}
- * is called.
- *
- * @param enabled Whether to enable memory tracking for all perf events.
- */
- @VisibleForTesting
- public static synchronized void setMemoryTrackingEnabled(boolean enabled) {
- sTrackMemory = enabled;
- }
-
- /**
- * Enables timing tracking for all perf events tracked.
- *
- * <p>
- * Only works when called in combination with {@link #setEnabled(boolean)}.
- *
- * <p>
- * If this feature is enabled, whenever {@link #instant(String)}, {@link #begin(String)},
- * or {@link #end(String)} is called the time since start of tracking will be logged.
- *
- * @param enabled Whether to enable timing tracking for all perf events.
- */
- @VisibleForTesting
- public static synchronized void setTimingTrackingEnabled(boolean enabled) {
- sTrackTiming = enabled;
- }
-
- /**
- * @return True if tracing is enabled, false otherwise.
- * It is safe to call trace methods without checking if PerfTraceEvent
- * is enabled.
- */
- @VisibleForTesting
- public static synchronized boolean enabled() {
- return sEnabled;
- }
-
- /**
- * Record an "instant" perf trace event. E.g. "screen update happened".
- */
- public static synchronized void instant(String name) {
- // Instant doesn't really need/take an event id, but this should be okay.
- final long eventId = name.hashCode();
- TraceEvent.instant(name);
- if (sEnabled && matchesFilter(name)) {
- savePerfString(name, eventId, EventType.INSTANT, false);
- }
- }
-
-
- /**
- * Record an "begin" perf trace event.
- * Begin trace events should have a matching end event.
- */
- @VisibleForTesting
- public static synchronized void begin(String name) {
- final long eventId = name.hashCode();
- TraceEvent.startAsync(name, eventId);
- if (sEnabled && matchesFilter(name)) {
- // Done before calculating the starting perf data to ensure calculating the memory usage
- // does not influence the timing data.
- if (sTrackMemory) {
- savePerfString(makeMemoryTraceNameFromTimingName(name), eventId, EventType.START,
- true);
- }
- if (sTrackTiming) {
- savePerfString(name, eventId, EventType.START, false);
- }
- }
- }
-
- /**
- * Record an "end" perf trace event, to match a begin event. The
- * time delta between begin and end is usually interesting to
- * graph code.
- */
- @VisibleForTesting
- public static synchronized void end(String name) {
- final long eventId = name.hashCode();
- TraceEvent.finishAsync(name, eventId);
- if (sEnabled && matchesFilter(name)) {
- if (sTrackTiming) {
- savePerfString(name, eventId, EventType.FINISH, false);
- }
- // Done after calculating the ending perf data to ensure calculating the memory usage
- // does not influence the timing data.
- if (sTrackMemory) {
- savePerfString(makeMemoryTraceNameFromTimingName(name), eventId, EventType.FINISH,
- true);
- }
- }
- }
-
- /**
- * Record an "begin" memory trace event.
- * Begin trace events should have a matching end event.
- */
- @VisibleForTesting
- public static synchronized void begin(String name, MemoryInfo memoryInfo) {
- final long eventId = name.hashCode();
- TraceEvent.startAsync(name, eventId);
- if (sEnabled && matchesFilter(name)) {
- // Done before calculating the starting perf data to ensure calculating the memory usage
- // does not influence the timing data.
- long timestampUs = (System.nanoTime() - sBeginNanoTime) / 1000;
- savePerfString(makeMemoryTraceNameFromTimingName(name), eventId, EventType.START,
- timestampUs, memoryInfo);
- if (sTrackTiming) {
- savePerfString(name, eventId, EventType.START, false);
- }
- }
- }
-
- /**
- * Record an "end" memory trace event, to match a begin event. The
- * memory usage delta between begin and end is usually interesting to
- * graph code.
- */
- @VisibleForTesting
- public static synchronized void end(String name, MemoryInfo memoryInfo) {
- final long eventId = name.hashCode();
- TraceEvent.finishAsync(name, eventId);
- if (sEnabled && matchesFilter(name)) {
- if (sTrackTiming) {
- savePerfString(name, eventId, EventType.FINISH, false);
- }
- // Done after calculating the instant perf data to ensure calculating the memory usage
- // does not influence the timing data.
- long timestampUs = (System.nanoTime() - sBeginNanoTime) / 1000;
- savePerfString(makeMemoryTraceNameFromTimingName(name), eventId, EventType.FINISH,
- timestampUs, memoryInfo);
- }
- }
-
- /**
- * Determine if we are interested in this trace event.
- * @return True if the name matches the allowed filter; else false.
- */
- private static boolean matchesFilter(String name) {
- return sFilter != null ? sFilter.contains(name) : false;
- }
-
- /**
- * Save a perf trace event as a JSON dict. The format mirrors a TraceEvent dict.
- *
- * @param name The trace data
- * @param id The id of the event
- * @param type the type of trace event (I, S, F)
- * @param includeMemory Whether to include current browser process memory usage in the trace.
- */
- private static void savePerfString(String name, long id, EventType type,
- boolean includeMemory) {
- long timestampUs = (System.nanoTime() - sBeginNanoTime) / 1000;
- MemoryInfo memInfo = null;
- if (includeMemory) {
- memInfo = new MemoryInfo();
- Debug.getMemoryInfo(memInfo);
- }
- savePerfString(name, id, type, timestampUs, memInfo);
- }
-
- /**
- * Save a perf trace event as a JSON dict. The format mirrors a TraceEvent dict.
- *
- * @param name The trace data
- * @param id The id of the event
- * @param type the type of trace event (I, S, F)
- * @param timestampUs The time stamp at which this event was recorded
- * @param memoryInfo Memory details to be included in this perf string, null if
- * no memory details are to be included.
- */
- private static void savePerfString(String name, long id, EventType type, long timestampUs,
- MemoryInfo memoryInfo) {
- try {
- JSONObject traceObj = new JSONObject();
- traceObj.put("cat", "Java");
- traceObj.put("ts", timestampUs);
- traceObj.put("ph", type);
- traceObj.put("name", name);
- traceObj.put("id", id);
- if (memoryInfo != null) {
- int pss = memoryInfo.nativePss + memoryInfo.dalvikPss + memoryInfo.otherPss;
- traceObj.put("mem", pss);
- }
- sPerfTraceStrings.put(traceObj);
- } catch (JSONException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Generating a trace name for tracking memory based on the timing name passed in.
- *
- * @param name The timing name to use as a base for the memory perf name.
- * @return The memory perf name to use.
- */
- public static String makeMemoryTraceNameFromTimingName(String name) {
- return makeSafeTraceName(name, MEMORY_TRACE_NAME_SUFFIX);
- }
-
- /**
- * Builds a name to be used in the perf trace framework. The framework has length requirements
- * for names, so this ensures the generated name does not exceed the maximum (trimming the
- * base name if necessary).
- *
- * @param baseName The base name to use when generating the name.
- * @param suffix The required suffix to be appended to the name.
- * @return A name that is safe for the perf trace framework.
- */
- public static String makeSafeTraceName(String baseName, String suffix) {
- int suffixLength = suffix.length();
-
- if (baseName.length() + suffixLength > MAX_NAME_LENGTH) {
- baseName = baseName.substring(0, MAX_NAME_LENGTH - suffixLength);
- }
- return baseName + suffix;
- }
-
- /**
- * Sets a file to dump the results to. If {@code file} is {@code null}, it will be dumped
- * to STDOUT, otherwise the JSON performance data will be appended to {@code file}. This should
- * be called before the performance run starts. When {@link #setEnabled(boolean)} is called
- * with {@code false}, the perf data will be dumped.
- *
- * @param file Which file to append the performance data to. If {@code null}, the performance
- * data will be sent to STDOUT.
- */
- @VisibleForTesting
- public static synchronized void setOutputFile(File file) {
- sOutputFile = file;
- }
-
- /**
- * Dump all performance data we have saved up to the log.
- * Output as JSON for parsing convenience.
- */
- private static void dumpPerf() {
- String json = sPerfTraceStrings.toString();
-
- if (sOutputFile == null) {
- System.out.println(json);
- } else {
- try {
- PrintStream stream = new PrintStream(new FileOutputStream(sOutputFile, true));
- try {
- stream.print(json);
- } finally {
- try {
- stream.close();
- } catch (Exception ex) {
- Log.e("PerfTraceEvent", "Unable to close perf trace output file.");
- }
- }
- } catch (FileNotFoundException ex) {
- Log.e("PerfTraceEvent", "Unable to dump perf trace data to output file.");
- }
- }
- }
-}
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 3d0ed483ce..0000000000
--- a/base/android/java/src/org/chromium/base/PowerMonitor.java
+++ /dev/null
@@ -1,98 +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.
-
-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 ApplicationStatus.ApplicationStateListener {
- 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;
- }
-
- /**
- * Create a PowerMonitor instance if none exists.
- * @param context The context to register broadcast receivers for. The application context
- * will be used from this parameter.
- */
- public static void create(Context context) {
- context = context.getApplicationContext();
- if (sInstance == null) {
- sInstance = LazyHolder.INSTANCE;
- ApplicationStatus.registerApplicationStateListener(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 onApplicationStateChange(int newState) {
- if (newState == ApplicationState.HAS_RUNNING_ACTIVITIES) {
- // Remove the callback from the message loop in case it hasn't been executed yet.
- mHandler.removeCallbacks(sSuspendTask);
- nativeOnMainActivityResumed();
- } else if (newState == ApplicationState.HAS_PAUSED_ACTIVITIES) {
- 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 904a7401e6..0000000000
--- a/base/android/java/src/org/chromium/base/PowerStatusReceiver.java
+++ /dev/null
@@ -1,23 +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.
-
-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/README_logging.md b/base/android/java/src/org/chromium/base/README_logging.md
deleted file mode 100644
index a680ce1bb1..0000000000
--- a/base/android/java/src/org/chromium/base/README_logging.md
+++ /dev/null
@@ -1,181 +0,0 @@
-## Logging ##
-
-Logging used to be done using Android's [android.util.Log]
-(http://developer.android.com/reference/android/util/Log.html).
-
-A wrapper on that is now available: org.chromium.base.Log. It is designed to write logs as
-belonging to logical groups going beyond single classes, and to make it easy to switch logging on
-or off for individual groups.
-
-Usage:
-
- private static final String TAG = "cr.YourModuleTag";
- ...
- Log.i(TAG, "Logged INFO message.");
- Log.d(TAG, "Some DEBUG info: %s", data);
-
-Output:
-
- I/cr.YourModuleTag: ( 999): Logged INFO message
- D/cr.YourModuleTag: ( 999): [MyClass.java:42] Some DEBUG info: data's toString output
-
-Here, **TAG** will be a feature or package name, "MediaRemote" or "NFC" for example. In most
-cases, the class name is not needed.
-
-**Caveat:** Property keys are limited to 23 characters. If the tag is too long, `Log#isLoggable`
-throws a RuntimeException.
-
-### Verbose and Debug logs have special handling ###
-
-* `Log.v` and `Log.d` Calls made using `org.chromium.base.Log` are stripped
- out of production binaries using Proguard. There is no way to get those logs
- in release builds.
-
-* The file name and line number will be prepended to the log message.
- For higher priority logs, those are not added for performance concerns.
-
-* By default, Verbose and Debug logs are not enabled, see guarding:
-
-### Log calls are guarded: Tag groups can be enabled or disabled using ADB ###
-
- adb shell setprop log.tag.cr.YourModuleTag <LEVEL>
-
-Level here is either `VERBOSE`, `DEBUG`, `INFO`, `WARN`, `ERROR`, `ASSERT`, or `SUPPRESS`
-By default, the level for all tags is `INFO`.
-
-### An exception trace is printed when the exception is the last parameter ###
-
-As with `java.util.Log`, putting a throwable as last parameter will dump the corresponding stack
-trace:
-
- Log.i(TAG, "An error happened: %s", e)
-
- I/cr.YourModuleTag: ( 999): An error happened: This is the exception's message
- I/cr.YourModuleTag: ( 999): java.lang.Exception: This is the exception's message
- I/cr.YourModuleTag: ( 999): at foo.bar.MyClass.test(MyClass.java:42)
- I/cr.YourModuleTag: ( 999): ...
-
-Having the exception as last parameter doesn't prevent it from being used for string formatting.
-
-### Logging Best Practices
-
-#### Rule #1: Never log PII (Personal Identification Information):
-
-This is a huge concern, because other applications can access the log and extract a lot of data
-from your own by doing so. Even if JellyBean restricted this, people are going to run your
-application on rooted devices and allow some apps to access it. Also anyone with USB access to the
-device can use ADB to get the full logcat and get the same data right now.
-
-If you really need to print something , print a series of Xs instead (e.g. "XXXXXX"), or print a
-truncated hash of the PII instead. Truncation is required to make it harder for an attacker to
-recover the full data through rainbow tables and similar methods.
-
-Similarly, avoid dumping API keys, cookies, etc...
-
-#### Rule #2: Do not write debug logs in production code:
-
-The kernel log buffer is global and of limited size. Any extra debug log you add to your activity
-or service makes it more difficult to diagnose problems on other parts of the system, because they
-tend to push the interesting bit out of the buffer too soon. This is a recurring problem on
-Android, so avoid participating into it.
-
-Logs can be disabled using system properties. Because log messages might not be
-written, the cost of creating them should also be avoided. This can be done using three
-complementary ways:
-
-- Use string formatting instead of concatenations
-
- // BAD
- Log.d(TAG, "I " + preference + " writing logs.");
-
- // BETTER
- Log.d(TAG, "I %s writing logs.", preference);
-
- If logging is disabled, the function's arguments will still have to be computed and provided
- as input. The first call above will always lead to the creation of a `StringBuilder` and a few
- concatenations, while the second just passes the arguments and won't need that.
-
-- Guard expensive calls
-
- Sometimes the values to log aren't readily available and need to be computed specially. This
- should be avoided when logging is disabled.
-
- Using `Log#isLoggable` will return whether logging for a specific tag is allowed or not. It is
- the call used inside the log functions and using allows to know when running the expensive
- functions is needed.
-
- if (Log.isLoggable(TAG, Log.DEBUG) {
- Log.d(TAG, "Something happened: %s", dumpDom(tab));
- }
-
- For more info, See the [android framework documentation]
- (http://developer.android.com/tools/debugging/debugging-log.html).
-
- Using a debug constant is a less flexible, but more perfomance oriented alternative.
-
- static private final boolean DEBUG = false; // set to 'true' to enable debug
- ...
- if (DEBUG) {
- Log.i(TAG, createThatExpensiveLogMessage(activity))
- }
-
- Because the variable is a `static final` that can be evaluated at compile time, the Java
- compiler will optimize out all guarded calls from the generated `.class` file. Changing it
- however requires editing each of the files for which debug should be enabled and recompiling,
- while the previous method can enable or disable debugging for a whole feature without changing
- any source file.
-
-- Annotate debug functions with the `@NoSideEffects` annotation.
-
- That annotation tells Proguard to assume that a given function has no side effects, and is
- called only for its returned value. If this value is unused, the call will be removed. If the
- function is not called at all, it will also be removed. Since Proguard is already used to
- strip debug and verbose calls out of release builds, this annotation allows it to have a
- deeper action by removing also function calls used to generate the log call's arguments.
-
- /* If that function is only used in Log.d calls, proguard should completely remove it from
- * the release builds. */
- @NoSideEffects
- private static String getSomeDebugLogString(Thing[] things) {
- /* Still needs to be guarded to avoid impacting debug builds, or in case it's used for
- * some other log levels. But at least it is done only once, inside the function. */
- if (!Log.isLoggable(TAG, Log.DEBUG)) return null;
-
- StringBuilder sb = new StringBuilder("Reporting " + thing.length + " things:");
- for (Thing thing : things) {
- sb.append('\n').append(thing.id).append(' ').append(report.foo);
- }
- return sb.toString();
- }
-
- public void bar() {
- ...
- Log.d(TAG, getSomeDebugLogString(things)); /* In debug builds, the function does nothing
- * is debug is disabled, and the entire line
- * is removed in release builds. */
- }
-
- Again, this is useful only if the input to that function are variables already available in
- the scope. The idea is to move computations, concatenations, etc. to a place where that can be
- removed when not needed, without invading the main function's logic.
-
-#### Rule #3: Favor small log messages
-
-This is still related to the global fixed-sized kernel buffer used to keep all logs. Try to make
-your log information as terse as possible. This reduces the risk of pushing interesting log data
-out of the buffer when something really nasty happens. It's really better to have a single-line
-log message, than several ones. I.e. don't use:
-
- Log.GROUP.d(TAG, "field1 = %s", value1);
- Log.GROUP.d(TAG, "field2 = %s", value2);
- Log.GROUP.d(TAG, "field3 = %s", value3);
-
-Instead, write this as:
-
- Log.d(TAG, "field1 = %s, field2 = %s, field3 = %s", value1, value2, value3);
-
-That doesn't seem to be much different if you count overall character counts, but each independent
-log entry also implies a small, but non-trivial header, in the kernel log buffer.
-And since every byte count, you can also try something even shorter, as in:
-
- Log.d(TAG, "fields [%s,%s,%s]", value1, value2, value3);
diff --git a/base/android/java/src/org/chromium/base/ResourceExtractor.java b/base/android/java/src/org/chromium/base/ResourceExtractor.java
deleted file mode 100644
index d44f2fc7c2..0000000000
--- a/base/android/java/src/org/chromium/base/ResourceExtractor.java
+++ /dev/null
@@ -1,484 +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.
-
-package org.chromium.base;
-
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.res.AssetManager;
-import android.os.AsyncTask;
-import android.os.Build;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Trace;
-import android.preference.PreferenceManager;
-import android.util.Log;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.FilenameFilter;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.CancellationException;
-import java.util.concurrent.ExecutionException;
-import java.util.regex.Pattern;
-
-/**
- * Handles extracting the necessary resources bundled in an APK and moving them to a location on
- * the file system accessible from the native code.
- */
-public class ResourceExtractor {
-
- private static final String LOGTAG = "ResourceExtractor";
- private static final String LAST_LANGUAGE = "Last language";
- private static final String PAK_FILENAMES_LEGACY_NOREUSE = "Pak filenames";
- private static final String ICU_DATA_FILENAME = "icudtl.dat";
- private static final String V8_NATIVES_DATA_FILENAME = "natives_blob.bin";
- private static final String V8_SNAPSHOT_DATA_FILENAME = "snapshot_blob.bin";
-
- private static String[] sMandatoryPaks = null;
-
- // By default, we attempt to extract a pak file for the users
- // current device locale. Use setExtractImplicitLocale() to
- // change this behavior.
- private static boolean sExtractImplicitLocalePak = true;
-
- private static boolean isAppDataFile(String file) {
- return ICU_DATA_FILENAME.equals(file)
- || V8_NATIVES_DATA_FILENAME.equals(file)
- || V8_SNAPSHOT_DATA_FILENAME.equals(file);
- }
-
- private class ExtractTask extends AsyncTask<Void, Void, Void> {
- private static final int BUFFER_SIZE = 16 * 1024;
-
- private final List<Runnable> mCompletionCallbacks = new ArrayList<Runnable>();
-
- public ExtractTask() {
- }
-
- private void doInBackgroundImpl() {
- final File outputDir = getOutputDir();
- final File appDataDir = getAppDataDir();
- if (!outputDir.exists() && !outputDir.mkdirs()) {
- Log.e(LOGTAG, "Unable to create pak resources directory!");
- return;
- }
-
- String timestampFile = null;
- beginTraceSection("checkPakTimeStamp");
- try {
- timestampFile = checkPakTimestamp(outputDir);
- } finally {
- endTraceSection();
- }
- if (timestampFile != null) {
- deleteFiles();
- }
-
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
- String currentLocale = LocaleUtils.getDefaultLocale();
- String currentLanguage = currentLocale.split("-", 2)[0];
- // If everything we need is already there (and the locale hasn't
- // changed), quick exit.
- if (prefs.getString(LAST_LANGUAGE, "").equals(currentLanguage)) {
- boolean filesPresent = true;
- for (String file : sMandatoryPaks) {
- File directory = isAppDataFile(file) ? appDataDir : outputDir;
- if (!new File(directory, file).exists()) {
- filesPresent = false;
- break;
- }
- }
- if (filesPresent) return;
- } else {
- prefs.edit().putString(LAST_LANGUAGE, currentLanguage).apply();
- }
-
- StringBuilder p = new StringBuilder();
- for (String mandatoryPak : sMandatoryPaks) {
- if (p.length() > 0) p.append('|');
- p.append("\\Q" + mandatoryPak + "\\E");
- }
-
- if (sExtractImplicitLocalePak) {
- if (p.length() > 0) p.append('|');
- // As well as the minimum required set of .paks above, we'll
- // also add all .paks that we have for the user's currently
- // selected language.
- p.append(currentLanguage);
- p.append("(-\\w+)?\\.pak");
- }
-
- Pattern paksToInstall = Pattern.compile(p.toString());
-
- AssetManager manager = mContext.getResources().getAssets();
- beginTraceSection("WalkAssets");
- try {
- // Loop through every asset file that we have in the APK, and look for the
- // ones that we need to extract by trying to match the Patterns that we
- // created above.
- byte[] buffer = null;
- String[] files = manager.list("");
- for (String file : files) {
- if (!paksToInstall.matcher(file).matches()) {
- continue;
- }
- File output = new File(isAppDataFile(file) ? appDataDir : outputDir, file);
- if (output.exists()) {
- continue;
- }
-
- InputStream is = null;
- OutputStream os = null;
- beginTraceSection("ExtractResource");
- try {
- is = manager.open(file);
- os = new FileOutputStream(output);
- Log.i(LOGTAG, "Extracting resource " + file);
- if (buffer == null) {
- buffer = new byte[BUFFER_SIZE];
- }
-
- int count = 0;
- while ((count = is.read(buffer, 0, BUFFER_SIZE)) != -1) {
- os.write(buffer, 0, count);
- }
- os.flush();
-
- // Ensure something reasonable was written.
- if (output.length() == 0) {
- throw new IOException(file + " extracted with 0 length!");
- }
-
- if (isAppDataFile(file)) {
- // icu and V8 data need to be accessed by a renderer
- // process.
- output.setReadable(true, false);
- }
- } finally {
- try {
- if (is != null) {
- is.close();
- }
- } finally {
- if (os != null) {
- os.close();
- }
- endTraceSection(); // ExtractResource
- }
- }
- }
- } catch (IOException e) {
- // TODO(benm): See crbug/152413.
- // Try to recover here, can we try again after deleting files instead of
- // returning null? It might be useful to gather UMA here too to track if
- // this happens with regularity.
- Log.w(LOGTAG, "Exception unpacking required pak resources: " + e.getMessage());
- deleteFiles();
- return;
- } finally {
- endTraceSection(); // WalkAssets
- }
-
- // Finished, write out a timestamp file if we need to.
- if (timestampFile != null) {
- try {
- new File(outputDir, timestampFile).createNewFile();
- } catch (IOException e) {
- // Worst case we don't write a timestamp, so we'll re-extract the resource
- // paks next start up.
- Log.w(LOGTAG, "Failed to write resource pak timestamp!");
- }
- }
- }
-
- @Override
- protected Void doInBackground(Void... unused) {
- // TODO(lizeb): Use chrome tracing here (and above in
- // doInBackgroundImpl) when it will be possible. This is currently
- // not doable since the native library is not loaded yet, and the
- // TraceEvent calls are dropped before this point.
- beginTraceSection("ResourceExtractor.ExtractTask.doInBackground");
- try {
- doInBackgroundImpl();
- } finally {
- endTraceSection();
- }
- return null;
- }
-
- private void onPostExecuteImpl() {
- for (int i = 0; i < mCompletionCallbacks.size(); i++) {
- mCompletionCallbacks.get(i).run();
- }
- mCompletionCallbacks.clear();
- }
-
- @Override
- protected void onPostExecute(Void result) {
- beginTraceSection("ResourceExtractor.ExtractTask.onPostExecute");
- try {
- onPostExecuteImpl();
- } finally {
- endTraceSection();
- }
- }
-
- // Looks for a timestamp file on disk that indicates the version of the APK that
- // the resource paks were extracted from. Returns null if a timestamp was found
- // and it indicates that the resources match the current APK. Otherwise returns
- // a String that represents the filename of a timestamp to create.
- // Note that we do this to avoid adding a BroadcastReceiver on
- // android.content.Intent#ACTION_PACKAGE_CHANGED as that causes process churn
- // on (re)installation of *all* APK files.
- private String checkPakTimestamp(File outputDir) {
- final String timestampPrefix = "pak_timestamp-";
- PackageManager pm = mContext.getPackageManager();
- PackageInfo pi = null;
-
- try {
- pi = pm.getPackageInfo(mContext.getPackageName(), 0);
- } catch (PackageManager.NameNotFoundException e) {
- return timestampPrefix;
- }
-
- if (pi == null) {
- return timestampPrefix;
- }
-
- String expectedTimestamp = timestampPrefix + pi.versionCode + "-" + pi.lastUpdateTime;
-
- String[] timestamps = outputDir.list(new FilenameFilter() {
- @Override
- public boolean accept(File dir, String name) {
- return name.startsWith(timestampPrefix);
- }
- });
-
- if (timestamps.length != 1) {
- // If there's no timestamp, nuke to be safe as we can't tell the age of the files.
- // If there's multiple timestamps, something's gone wrong so nuke.
- return expectedTimestamp;
- }
-
- if (!expectedTimestamp.equals(timestamps[0])) {
- return expectedTimestamp;
- }
-
- // timestamp file is already up-to date.
- return null;
- }
-
- @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
- private void beginTraceSection(String section) {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) return;
- Trace.beginSection(section);
- }
-
- @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
- private void endTraceSection() {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) return;
- Trace.endSection();
- }
- }
-
- private final Context mContext;
- private ExtractTask mExtractTask;
-
- private static ResourceExtractor sInstance;
-
- public static ResourceExtractor get(Context context) {
- if (sInstance == null) {
- sInstance = new ResourceExtractor(context);
- }
- return sInstance;
- }
-
- /**
- * Specifies the .pak files that should be extracted from the APK's asset resources directory
- * and moved to {@link #getOutputDirFromContext(Context)}.
- * @param mandatoryPaks The list of pak files to be loaded. If no pak files are
- * required, pass a single empty string.
- */
- public static void setMandatoryPaksToExtract(String... mandatoryPaks) {
- assert (sInstance == null || sInstance.mExtractTask == null)
- : "Must be called before startExtractingResources is called";
- sMandatoryPaks = mandatoryPaks;
-
- }
-
- /**
- * By default the ResourceExtractor will attempt to extract a pak resource for the users
- * currently specified locale. This behavior can be changed with this function and is
- * only needed by tests.
- * @param extract False if we should not attempt to extract a pak file for
- * the users currently selected locale and try to extract only the
- * pak files specified in sMandatoryPaks.
- */
- @VisibleForTesting
- public static void setExtractImplicitLocaleForTesting(boolean extract) {
- assert (sInstance == null || sInstance.mExtractTask == null)
- : "Must be called before startExtractingResources is called";
- sExtractImplicitLocalePak = extract;
- }
-
- /**
- * Marks all the 'pak' resources, packaged as assets, for extraction during
- * running the tests.
- */
- @VisibleForTesting
- public void setExtractAllPaksAndV8SnapshotForTesting() {
- List<String> pakAndSnapshotFileAssets = new ArrayList<String>();
- AssetManager manager = mContext.getResources().getAssets();
- try {
- String[] files = manager.list("");
- for (String file : files) {
- if (file.endsWith(".pak")) pakAndSnapshotFileAssets.add(file);
- }
- } catch (IOException e) {
- Log.w(LOGTAG, "Exception while accessing assets: " + e.getMessage(), e);
- }
- pakAndSnapshotFileAssets.add("natives_blob.bin");
- pakAndSnapshotFileAssets.add("snapshot_blob.bin");
- setMandatoryPaksToExtract(pakAndSnapshotFileAssets.toArray(
- new String[pakAndSnapshotFileAssets.size()]));
- }
-
- private ResourceExtractor(Context context) {
- mContext = context.getApplicationContext();
- }
-
- /**
- * Synchronously wait for the resource extraction to be completed.
- * <p>
- * This method is bad and you should feel bad for using it.
- *
- * @see #addCompletionCallback(Runnable)
- */
- public void waitForCompletion() {
- if (shouldSkipPakExtraction()) {
- return;
- }
-
- assert mExtractTask != null;
-
- try {
- mExtractTask.get();
- } catch (CancellationException e) {
- // Don't leave the files in an inconsistent state.
- deleteFiles();
- } catch (ExecutionException e2) {
- deleteFiles();
- } catch (InterruptedException e3) {
- deleteFiles();
- }
- }
-
- /**
- * Adds a callback to be notified upon the completion of resource extraction.
- * <p>
- * If the resource task has already completed, the callback will be posted to the UI message
- * queue. Otherwise, it will be executed after all the resources have been extracted.
- * <p>
- * This must be called on the UI thread. The callback will also always be executed on
- * the UI thread.
- *
- * @param callback The callback to be enqueued.
- */
- public void addCompletionCallback(Runnable callback) {
- ThreadUtils.assertOnUiThread();
-
- Handler handler = new Handler(Looper.getMainLooper());
- if (shouldSkipPakExtraction()) {
- handler.post(callback);
- return;
- }
-
- assert mExtractTask != null;
- assert !mExtractTask.isCancelled();
- if (mExtractTask.getStatus() == AsyncTask.Status.FINISHED) {
- handler.post(callback);
- } else {
- mExtractTask.mCompletionCallbacks.add(callback);
- }
- }
-
- /**
- * This will extract the application pak resources in an
- * AsyncTask. Call waitForCompletion() at the point resources
- * are needed to block until the task completes.
- */
- public void startExtractingResources() {
- if (mExtractTask != null) {
- return;
- }
-
- if (shouldSkipPakExtraction()) {
- return;
- }
-
- mExtractTask = new ExtractTask();
- mExtractTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- }
-
- private File getAppDataDir() {
- return new File(PathUtils.getDataDirectory(mContext));
- }
-
- private File getOutputDir() {
- return new File(getAppDataDir(), "paks");
- }
-
- /**
- * Pak files (UI strings and other resources) should be updated along with
- * Chrome. A version mismatch can lead to a rather broken user experience.
- * Failing to update the V8 snapshot files will lead to a version mismatch
- * between V8 and the loaded snapshot which will cause V8 to crash, so this
- * is treated as an error. The ICU data (icudtl.dat) is less
- * version-sensitive, but still can lead to malfunction/UX misbehavior. So,
- * we regard failing to update them as an error.
- */
- private void deleteFiles() {
- File icudata = new File(getAppDataDir(), ICU_DATA_FILENAME);
- if (icudata.exists() && !icudata.delete()) {
- Log.e(LOGTAG, "Unable to remove the icudata " + icudata.getName());
- }
- File v8_natives = new File(getAppDataDir(), V8_NATIVES_DATA_FILENAME);
- if (v8_natives.exists() && !v8_natives.delete()) {
- Log.e(LOGTAG,
- "Unable to remove the v8 data " + v8_natives.getName());
- }
- File v8_snapshot = new File(getAppDataDir(), V8_SNAPSHOT_DATA_FILENAME);
- if (v8_snapshot.exists() && !v8_snapshot.delete()) {
- Log.e(LOGTAG,
- "Unable to remove the v8 data " + v8_snapshot.getName());
- }
- File dir = getOutputDir();
- if (dir.exists()) {
- File[] files = dir.listFiles();
- for (File file : files) {
- if (!file.delete()) {
- Log.e(LOGTAG, "Unable to remove existing resource " + file.getName());
- }
- }
- }
- }
-
- /**
- * Pak extraction not necessarily required by the embedder; we allow them to skip
- * this process if they call setMandatoryPaksToExtract with a single empty String.
- */
- private static boolean shouldSkipPakExtraction() {
- // Must call setMandatoryPaksToExtract before beginning resource extraction.
- assert sMandatoryPaks != null;
- return sMandatoryPaks.length == 1 && "".equals(sMandatoryPaks[0]);
- }
-}
diff --git a/base/android/java/src/org/chromium/base/SecureRandomInitializer.java b/base/android/java/src/org/chromium/base/SecureRandomInitializer.java
deleted file mode 100644
index 457e2ef8b9..0000000000
--- a/base/android/java/src/org/chromium/base/SecureRandomInitializer.java
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2014 The Chromium 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.io.FileInputStream;
-import java.io.IOException;
-import java.security.SecureRandom;
-
-/**
- * This class contains code to initialize a SecureRandom generator securely on Android platforms
- * <= 4.3. See
- * {@link http://android-developers.blogspot.com/2013/08/some-securerandom-thoughts.html}.
- */
-public class SecureRandomInitializer {
- private static final int NUM_RANDOM_BYTES = 16;
-
- private static byte[] sSeedBytes = new byte[NUM_RANDOM_BYTES];
-
- /**
- * Safely initializes the random number generator, by seeding it with data from /dev/urandom.
- */
- public static void initialize(SecureRandom generator) throws IOException {
- FileInputStream fis = null;
- try {
- fis = new FileInputStream("/dev/urandom");
- if (fis.read(sSeedBytes) != sSeedBytes.length) {
- throw new IOException("Failed to get enough random data.");
- }
- generator.setSeed(sSeedBytes);
- } finally {
- try {
- if (fis != null) {
- fis.close();
- }
- } catch (IOException e) {
- // Ignore exception closing the device.
- }
- }
- }
-}
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 9dad516299..0000000000
--- a/base/android/java/src/org/chromium/base/SysUtils.java
+++ /dev/null
@@ -1,139 +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.annotation.TargetApi;
-import android.app.ActivityManager;
-import android.content.Context;
-import android.os.Build;
-import android.os.StrictMode;
-import android.util.Log;
-
-import java.io.BufferedReader;
-import java.io.FileReader;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Exposes system related information about the current device.
- */
-public class SysUtils {
- // A device reporting strictly more total memory in megabytes cannot be considered 'low-end'.
- private static final int ANDROID_LOW_MEMORY_DEVICE_THRESHOLD_MB = 512;
-
- // Number of kilobytes in a megabyte.
- private static final int KBS_IN_MB = 1024;
-
- private static final String TAG = "SysUtils";
-
- private static Boolean sLowEndDevice;
-
- private SysUtils() { }
-
- /**
- * Return the amount of physical memory on this device in kilobytes.
- * @return Amount of physical memory in kilobytes, or 0 if there was
- * an error trying to access the information.
- */
- private static int amountOfPhysicalMemoryMB() {
- // Extract total memory RAM size by parsing /proc/meminfo, note that
- // this is exactly what the implementation of sysconf(_SC_PHYS_PAGES)
- // does. However, it can't be called because this method must be
- // usable before any native code is loaded.
-
- // An alternative is to use ActivityManager.getMemoryInfo(), but this
- // requires a valid ActivityManager handle, which can only come from
- // a valid Context object, which itself cannot be retrieved
- // during early startup, where this method is called. And making it
- // an explicit parameter here makes all call paths _much_ more
- // complicated.
-
- Pattern pattern = Pattern.compile("^MemTotal:\\s+([0-9]+) kB$");
- // Synchronously reading files in /proc in the UI thread is safe.
- StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
- try {
- FileReader fileReader = new FileReader("/proc/meminfo");
- try {
- BufferedReader reader = new BufferedReader(fileReader);
- try {
- String line;
- for (;;) {
- line = reader.readLine();
- if (line == null) {
- Log.w(TAG, "/proc/meminfo lacks a MemTotal entry?");
- break;
- }
- Matcher m = pattern.matcher(line);
- if (!m.find()) continue;
-
- int totalMemoryKB = Integer.parseInt(m.group(1));
- // Sanity check.
- if (totalMemoryKB <= KBS_IN_MB) {
- Log.w(TAG, "Invalid /proc/meminfo total size in kB: " + m.group(1));
- break;
- }
-
- return totalMemoryKB / KBS_IN_MB;
- }
-
- } finally {
- reader.close();
- }
- } finally {
- fileReader.close();
- }
- } catch (Exception e) {
- Log.w(TAG, "Cannot get total physical size from /proc/meminfo", e);
- } finally {
- StrictMode.setThreadPolicy(oldPolicy);
- }
-
- return 0;
- }
-
- /**
- * @return Whether or not this device should be considered a low end device.
- */
- @CalledByNative
- public static boolean isLowEndDevice() {
- if (sLowEndDevice == null) {
- sLowEndDevice = detectLowEndDevice();
- }
- return sLowEndDevice.booleanValue();
- }
-
- @TargetApi(Build.VERSION_CODES.KITKAT)
- private static boolean detectLowEndDevice() {
- assert CommandLine.isInitialized();
- if (CommandLine.getInstance().hasSwitch(BaseSwitches.ENABLE_LOW_END_DEVICE_MODE)) {
- return true;
- }
- if (CommandLine.getInstance().hasSwitch(BaseSwitches.DISABLE_LOW_END_DEVICE_MODE)) {
- return false;
- }
- // Any pre-KitKat device cannot be considered 'low-end'.
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
- return false;
- }
-
- Context context = ApplicationStatus.getApplicationContext();
- if (context != null) {
- ActivityManager activityManager = (ActivityManager)
- context.getSystemService(Context.ACTIVITY_SERVICE);
- if (activityManager.isLowRamDevice()) {
- return true;
- }
- } else {
- Log.e(TAG, "ApplicationContext is null in ApplicationStatus");
- }
-
- int ramSizeMB = amountOfPhysicalMemoryMB();
- if (ramSizeMB <= 0) {
- return false;
- }
-
- return ramSizeMB < ANDROID_LOW_MEMORY_DEVICE_THRESHOLD_MB;
- }
-}
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 fd3dc5a08b..0000000000
--- a/base/android/java/src/org/chromium/base/SystemMessageHandler.java
+++ /dev/null
@@ -1,111 +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.
-
-package org.chromium.base;
-
-import android.os.Handler;
-import android.os.Message;
-import android.util.Log;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
-class SystemMessageHandler extends Handler {
-
- private static final String TAG = "SystemMessageHandler";
-
- private static final int SCHEDULED_WORK = 1;
- private static final int DELAYED_SCHEDULED_WORK = 2;
-
- // Native class pointer set by the constructor of the SharedClient native class.
- private long mMessagePumpDelegateNative = 0;
- private long mDelayedScheduledTimeTicks = 0;
-
- // Reflected API for marking a message as asynchronous. This is a workaround
- // to provide fair Chromium task dispatch when served by the Android UI
- // thread's Looper, avoiding stalls when the Looper has a sync barrier.
- // Note: Use of this API is experimental and likely to evolve in the future.
- private Method mMessageMethodSetAsynchronous;
-
- private SystemMessageHandler(long messagePumpDelegateNative) {
- mMessagePumpDelegateNative = messagePumpDelegateNative;
-
- try {
- Class<?> messageClass = Class.forName("android.os.Message");
- mMessageMethodSetAsynchronous = messageClass.getMethod(
- "setAsynchronous", new Class[]{boolean.class});
- } catch (ClassNotFoundException e) {
- Log.e(TAG, "Failed to find android.os.Message class:" + e);
- } catch (NoSuchMethodException e) {
- Log.e(TAG, "Failed to load Message.setAsynchronous method:" + e);
- } catch (RuntimeException e) {
- Log.e(TAG, "Exception while loading Message.setAsynchronous method: " + e);
- }
-
- }
-
- @Override
- public void handleMessage(Message msg) {
- if (msg.what == DELAYED_SCHEDULED_WORK) {
- mDelayedScheduledTimeTicks = 0;
- }
- nativeDoRunLoopOnce(mMessagePumpDelegateNative, mDelayedScheduledTimeTicks);
- }
-
- @SuppressWarnings("unused")
- @CalledByNative
- private void scheduleWork() {
- sendMessage(obtainAsyncMessage(SCHEDULED_WORK));
- }
-
- @SuppressWarnings("unused")
- @CalledByNative
- private void scheduleDelayedWork(long delayedTimeTicks, long millis) {
- if (mDelayedScheduledTimeTicks != 0) {
- removeMessages(DELAYED_SCHEDULED_WORK);
- }
- mDelayedScheduledTimeTicks = delayedTimeTicks;
- sendMessageDelayed(obtainAsyncMessage(DELAYED_SCHEDULED_WORK), millis);
- }
-
- @SuppressWarnings("unused")
- @CalledByNative
- private void removeAllPendingMessages() {
- removeMessages(SCHEDULED_WORK);
- removeMessages(DELAYED_SCHEDULED_WORK);
- }
-
- private Message obtainAsyncMessage(int what) {
- Message msg = Message.obtain();
- msg.what = what;
- if (mMessageMethodSetAsynchronous != null) {
- // If invocation fails, assume this is indicative of future
- // failures, and avoid log spam by nulling the reflected method.
- try {
- mMessageMethodSetAsynchronous.invoke(msg, true);
- } catch (IllegalAccessException e) {
- Log.e(TAG, "Illegal access to asynchronous message creation, disabling.");
- mMessageMethodSetAsynchronous = null;
- } catch (IllegalArgumentException e) {
- Log.e(TAG, "Illegal argument for asynchronous message creation, disabling.");
- mMessageMethodSetAsynchronous = null;
- } catch (InvocationTargetException e) {
- Log.e(TAG, "Invocation exception during asynchronous message creation, disabling.");
- mMessageMethodSetAsynchronous = null;
- } catch (RuntimeException e) {
- Log.e(TAG, "Runtime exception during asynchronous message creation, disabling.");
- mMessageMethodSetAsynchronous = null;
- }
- }
- return msg;
- }
-
- @CalledByNative
- private static SystemMessageHandler create(long messagePumpDelegateNative) {
- return new SystemMessageHandler(messagePumpDelegateNative);
- }
-
- private native void nativeDoRunLoopOnce(
- long messagePumpDelegateNative, long delayedScheduledTimeTicks);
-}
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 c0b91721bd..0000000000
--- a/base/android/java/src/org/chromium/base/ThreadUtils.java
+++ /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.
-
-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 {
-
- private static final Object sLock = new Object();
-
- private static boolean sWillOverride = false;
-
- private static Handler sUiThreadHandler = null;
-
- public static void setWillOverrideUiThread() {
- synchronized (sLock) {
- sWillOverride = true;
- }
- }
-
- public static void setUiThread(Looper looper) {
- synchronized (sLock) {
- if (sUiThreadHandler != null && sUiThreadHandler.getLooper() != looper) {
- throw new RuntimeException("UI thread looper is already set to "
- + sUiThreadHandler.getLooper() + " (Main thread looper is "
- + Looper.getMainLooper() + "), cannot set to new looper " + looper);
- } else {
- sUiThreadHandler = new Handler(looper);
- }
- }
- }
-
- private static Handler getUiThreadHandler() {
- synchronized (sLock) {
- if (sUiThreadHandler == null) {
- if (sWillOverride) {
- throw new RuntimeException("Did not yet override the UI thread");
- }
- sUiThreadHandler = new Handler(Looper.getMainLooper());
- }
- return sUiThreadHandler;
- }
- }
-
- /**
- * 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<Void> task = new FutureTask<Void>(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> T runOnUiThreadBlockingNoException(Callable<T> 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> T runOnUiThreadBlocking(Callable<T> c) throws ExecutionException {
- FutureTask<T> task = new FutureTask<T>(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 <T> FutureTask<T> runOnUiThread(FutureTask<T> 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 <T> FutureTask<T> runOnUiThread(Callable<T> c) {
- return runOnUiThread(new FutureTask<T>(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 {
- getUiThreadHandler().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 <T> FutureTask<T> postOnUiThread(FutureTask<T> task) {
- getUiThreadHandler().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 task) {
- getUiThreadHandler().post(task);
- }
-
- /**
- * 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
- */
- @VisibleForTesting
- public static void postOnUiThreadDelayed(Runnable task, long delayMillis) {
- getUiThreadHandler().postDelayed(task, 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 getUiThreadHandler().getLooper() == Looper.myLooper();
- }
-
- public static Looper getUiThreadLooper() {
- return getUiThreadHandler().getLooper();
- }
-
- /**
- * Set thread priority to audio.
- */
- @CalledByNative
- public static void setThreadPriorityAudio(int tid) {
- Process.setThreadPriority(tid, Process.THREAD_PRIORITY_AUDIO);
- }
-}
diff --git a/base/android/java/src/org/chromium/base/TraceEvent.java b/base/android/java/src/org/chromium/base/TraceEvent.java
deleted file mode 100644
index 3d3b11a041..0000000000
--- a/base/android/java/src/org/chromium/base/TraceEvent.java
+++ /dev/null
@@ -1,285 +0,0 @@
-// Copyright 2014 The Chromium 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.Looper;
-import android.os.MessageQueue;
-import android.os.SystemClock;
-import android.util.Log;
-import android.util.Printer;
-/**
- * Java mirror of Chrome trace event API. See base/trace_event/trace_event.h. Unlike the native
- * version, Java does not have stack objects, so a TRACE_EVENT() which does both TRACE_EVENT_BEGIN()
- * and TRACE_EVENT_END() in ctor/dtor is not possible.
- * It is OK to use tracing before the native library has loaded, but such traces will
- * be ignored. (Perhaps we could devise to buffer them up in future?).
- */
-@JNINamespace("base::android")
-public class TraceEvent {
-
- private static volatile boolean sEnabled = false;
-
- private static class BasicLooperMonitor implements Printer {
- @Override
- public void println(final String line) {
- if (line.startsWith(">")) {
- beginHandling(line);
- } else {
- assert line.startsWith("<");
- endHandling(line);
- }
- }
-
- void beginHandling(final String line) {
- if (sEnabled) nativeBeginToplevel();
- }
-
- void endHandling(final String line) {
- if (sEnabled) nativeEndToplevel();
- }
- }
-
- /**
- * A class that records, traces and logs statistics about the UI thead's Looper.
- * The output of this class can be used in a number of interesting ways:
- * <p>
- * <ol><li>
- * When using chrometrace, there will be a near-continuous line of
- * measurements showing both event dispatches as well as idles;
- * </li><li>
- * Logging messages are output for events that run too long on the
- * event dispatcher, making it easy to identify problematic areas;
- * </li><li>
- * Statistics are output whenever there is an idle after a non-trivial
- * amount of activity, allowing information to be gathered about task
- * density and execution cadence on the Looper;
- * </li></ol>
- * <p>
- * The class attaches itself as an idle handler to the main Looper, and
- * monitors the execution of events and idle notifications. Task counters
- * accumulate between idle notifications and get reset when a new idle
- * notification is received.
- */
- private static final class IdleTracingLooperMonitor extends BasicLooperMonitor
- implements MessageQueue.IdleHandler {
- // Tags for dumping to logcat or TraceEvent
- private static final String TAG = "TraceEvent.LooperMonitor";
- private static final String IDLE_EVENT_NAME = "Looper.queueIdle";
-
- // Calculation constants
- private static final long FRAME_DURATION_MILLIS = 1000L / 60L; // 60 FPS
- // A reasonable threshold for defining a Looper event as "long running"
- private static final long MIN_INTERESTING_DURATION_MILLIS =
- FRAME_DURATION_MILLIS;
- // A reasonable threshold for a "burst" of tasks on the Looper
- private static final long MIN_INTERESTING_BURST_DURATION_MILLIS =
- MIN_INTERESTING_DURATION_MILLIS * 3;
-
- // Stats tracking
- private long mLastIdleStartedAt = 0L;
- private long mLastWorkStartedAt = 0L;
- private int mNumTasksSeen = 0;
- private int mNumIdlesSeen = 0;
- private int mNumTasksSinceLastIdle = 0;
-
- // State
- private boolean mIdleMonitorAttached = false;
-
- // Called from within the begin/end methods only.
- // This method can only execute on the looper thread, because that is
- // the only thread that is permitted to call Looper.myqueue().
- private final void syncIdleMonitoring() {
- if (sEnabled && !mIdleMonitorAttached) {
- // approximate start time for computational purposes
- mLastIdleStartedAt = SystemClock.elapsedRealtime();
- Looper.myQueue().addIdleHandler(this);
- mIdleMonitorAttached = true;
- Log.v(TAG, "attached idle handler");
- } else if (mIdleMonitorAttached && !sEnabled) {
- Looper.myQueue().removeIdleHandler(this);
- mIdleMonitorAttached = false;
- Log.v(TAG, "detached idle handler");
- }
- }
-
- @Override
- final void beginHandling(final String line) {
- // Close-out any prior 'idle' period before starting new task.
- if (mNumTasksSinceLastIdle == 0) {
- TraceEvent.end(IDLE_EVENT_NAME);
- }
- mLastWorkStartedAt = SystemClock.elapsedRealtime();
- syncIdleMonitoring();
- super.beginHandling(line);
- }
-
- @Override
- final void endHandling(final String line) {
- final long elapsed = SystemClock.elapsedRealtime()
- - mLastWorkStartedAt;
- if (elapsed > MIN_INTERESTING_DURATION_MILLIS) {
- traceAndLog(Log.WARN, "observed a task that took "
- + elapsed + "ms: " + line);
- }
- super.endHandling(line);
- syncIdleMonitoring();
- mNumTasksSeen++;
- mNumTasksSinceLastIdle++;
- }
-
- private static void traceAndLog(int level, String message) {
- TraceEvent.instant("TraceEvent.LooperMonitor:IdleStats", message);
- Log.println(level, TAG, message);
- }
-
- @Override
- public final boolean queueIdle() {
- final long now = SystemClock.elapsedRealtime();
- if (mLastIdleStartedAt == 0) mLastIdleStartedAt = now;
- final long elapsed = now - mLastIdleStartedAt;
- mNumIdlesSeen++;
- TraceEvent.begin(IDLE_EVENT_NAME, mNumTasksSinceLastIdle + " tasks since last idle.");
- if (elapsed > MIN_INTERESTING_BURST_DURATION_MILLIS) {
- // Dump stats
- String statsString = mNumTasksSeen + " tasks and "
- + mNumIdlesSeen + " idles processed so far, "
- + mNumTasksSinceLastIdle + " tasks bursted and "
- + elapsed + "ms elapsed since last idle";
- traceAndLog(Log.DEBUG, statsString);
- }
- mLastIdleStartedAt = now;
- mNumTasksSinceLastIdle = 0;
- return true; // stay installed
- }
- }
-
- // Holder for monitor avoids unnecessary construction on non-debug runs
- private static final class LooperMonitorHolder {
- private static final BasicLooperMonitor sInstance =
- CommandLine.getInstance().hasSwitch(BaseSwitches.ENABLE_IDLE_TRACING)
- ? new IdleTracingLooperMonitor() : new BasicLooperMonitor();
- }
-
-
- /**
- * Register an enabled observer, such that java traces are always enabled with native.
- */
- public static void registerNativeEnabledObserver() {
- nativeRegisterEnabledObserver();
- }
-
- /**
- * Notification from native that tracing is enabled/disabled.
- */
- @CalledByNative
- public static void setEnabled(boolean enabled) {
- sEnabled = enabled;
- ThreadUtils.getUiThreadLooper().setMessageLogging(
- enabled ? LooperMonitorHolder.sInstance : null);
- }
-
- /**
- * Enables or disabled Android systrace path of Chrome tracing. If enabled, all Chrome
- * traces will be also output to Android systrace. Because of the overhead of Android
- * systrace, this is for WebView only.
- */
- public static void setATraceEnabled(boolean enabled) {
- if (sEnabled == enabled) return;
- if (enabled) {
- nativeStartATrace();
- } else {
- nativeStopATrace();
- }
- }
-
- /**
- * @return True if tracing is enabled, false otherwise.
- * It is safe to call trace methods without checking if TraceEvent
- * is enabled.
- */
- public static boolean enabled() {
- return sEnabled;
- }
-
- /**
- * Triggers the 'instant' native trace event with no arguments.
- * @param name The name of the event.
- */
- public static void instant(String name) {
- if (sEnabled) nativeInstant(name, null);
- }
-
- /**
- * Triggers the 'instant' native trace event.
- * @param name The name of the event.
- * @param arg The arguments of the event.
- */
- public static void instant(String name, String arg) {
- if (sEnabled) nativeInstant(name, arg);
- }
-
- /**
- * Triggers the 'start' native trace event with no arguments.
- * @param name The name of the event.
- * @param id The id of the asynchronous event.
- */
- public static void startAsync(String name, long id) {
- if (sEnabled) nativeStartAsync(name, id);
- }
-
- /**
- * Triggers the 'finish' native trace event with no arguments.
- * @param name The name of the event.
- * @param id The id of the asynchronous event.
- */
- public static void finishAsync(String name, long id) {
- if (sEnabled) nativeFinishAsync(name, id);
- }
-
- /**
- * Triggers the 'begin' native trace event with no arguments.
- * @param name The name of the event.
- */
- public static void begin(String name) {
- if (sEnabled) nativeBegin(name, null);
- }
-
- /**
- * Triggers the 'begin' native trace event.
- * @param name The name of the event.
- * @param arg The arguments of the event.
- */
- public static void begin(String name, String arg) {
- if (sEnabled) nativeBegin(name, arg);
- }
-
- /**
- * Triggers the 'end' native trace event with no arguments.
- * @param name The name of the event.
- */
- public static void end(String name) {
- if (sEnabled) nativeEnd(name, null);
- }
-
- /**
- * Triggers the 'end' native trace event.
- * @param name The name of the event.
- * @param arg The arguments of the event.
- */
- public static void end(String name, String arg) {
- if (sEnabled) nativeEnd(name, arg);
- }
-
- private static native void nativeRegisterEnabledObserver();
- private static native void nativeStartATrace();
- private static native void nativeStopATrace();
- private static native void nativeInstant(String name, String arg);
- private static native void nativeBegin(String name, String arg);
- private static native void nativeEnd(String name, String arg);
- private static native void nativeBeginToplevel();
- private static native void nativeEndToplevel();
- private static native void nativeStartAsync(String name, long id);
- private static native void nativeFinishAsync(String name, long id);
-}
diff --git a/base/android/java/src/org/chromium/base/VisibleForTesting.java b/base/android/java/src/org/chromium/base/VisibleForTesting.java
deleted file mode 100644
index 24cbfadfaa..0000000000
--- a/base/android/java/src/org/chromium/base/VisibleForTesting.java
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2014 The Chromium 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;
-
-/**
- * Annotation used to mark code that has wider visibility or present for testing code.
- */
-public @interface VisibleForTesting {
-
-}
diff --git a/base/android/java/src/org/chromium/base/annotations/AccessedByNative.java b/base/android/java/src/org/chromium/base/annotations/AccessedByNative.java
deleted file mode 100644
index 6df7c11027..0000000000
--- a/base/android/java/src/org/chromium/base/annotations/AccessedByNative.java
+++ /dev/null
@@ -1,20 +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.
-
-package org.chromium.base.annotations;
-
-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/annotations/CalledByNativeUnchecked.java b/base/android/java/src/org/chromium/base/annotations/CalledByNativeUnchecked.java
deleted file mode 100644
index c0abcbe649..0000000000
--- a/base/android/java/src/org/chromium/base/annotations/CalledByNativeUnchecked.java
+++ /dev/null
@@ -1,27 +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.
-
-package org.chromium.base.annotations;
-
-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/annotations/NoSideEffects.java b/base/android/java/src/org/chromium/base/annotations/NoSideEffects.java
deleted file mode 100644
index 803c3f9596..0000000000
--- a/base/android/java/src/org/chromium/base/annotations/NoSideEffects.java
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2015 The Chromium 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.annotations;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Target;
-
-/**
- * Annotation used to indicate to proguard methods that have no side effects and can be
- * safely removed if their return value is not used. This is to be used with
- * {@link org.chromium.base.Log}'s method, that can also be removed by proguard. That way
- * expensive calls can be left in debug builds but removed in release.
- */
-@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
-public @interface NoSideEffects {}
diff --git a/base/android/java/src/org/chromium/base/annotations/SuppressFBWarnings.java b/base/android/java/src/org/chromium/base/annotations/SuppressFBWarnings.java
deleted file mode 100644
index 89068ac941..0000000000
--- a/base/android/java/src/org/chromium/base/annotations/SuppressFBWarnings.java
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2014 The Chromium 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.annotations;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * @SuppressFBWarnings is used to suppress FindBugs warnings.
- *
- * The long name of FindBugs warnings can be found at
- * http://findbugs.sourceforge.net/bugDescriptions.html
- */
-@Retention(RetentionPolicy.CLASS)
-public @interface SuppressFBWarnings {
- String[] value() default {};
- String justification() default "";
-}
diff --git a/base/android/java/src/org/chromium/base/annotations/UsedByReflection.java b/base/android/java/src/org/chromium/base/annotations/UsedByReflection.java
deleted file mode 100644
index a2af704e0c..0000000000
--- a/base/android/java/src/org/chromium/base/annotations/UsedByReflection.java
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2014 The Chromium 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.annotations;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Target;
-
-/**
- * Annotation used for marking methods and fields that are called by reflection.
- * Useful for keeping components that would otherwise be removed by Proguard.
- * Use the value parameter to mention a file that calls this method.
- *
- * Note that adding this annotation to a method is not enough to guarantee that
- * it is kept - either its class must be referenced elsewhere in the program, or
- * the class must be annotated with this as well.
- */
-@Target({
- ElementType.METHOD, ElementType.FIELD, ElementType.TYPE,
- ElementType.CONSTRUCTOR })
-public @interface UsedByReflection {
- String value();
-}
diff --git a/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java b/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java
deleted file mode 100644
index a789eff611..0000000000
--- a/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java
+++ /dev/null
@@ -1,509 +0,0 @@
-// Copyright 2014 The Chromium 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.library_loader;
-
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.os.AsyncTask;
-import android.os.Build;
-import android.os.SystemClock;
-import android.util.Log;
-
-import org.chromium.base.CalledByNative;
-import org.chromium.base.CommandLine;
-import org.chromium.base.JNINamespace;
-import org.chromium.base.PackageUtils;
-import org.chromium.base.TraceEvent;
-import org.chromium.base.VisibleForTesting;
-import org.chromium.base.metrics.RecordHistogram;
-
-import javax.annotation.Nullable;
-
-/**
- * This class provides functionality to load and register the native libraries.
- * Callers are allowed to separate loading the libraries from initializing them.
- * This may be an advantage for Android Webview, where the libraries can be loaded
- * by the zygote process, but then needs per process initialization after the
- * application processes are forked from the zygote process.
- *
- * The libraries may be loaded and initialized from any thread. Synchronization
- * primitives are used to ensure that overlapping requests from different
- * threads are handled sequentially.
- *
- * See also base/android/library_loader/library_loader_hooks.cc, which contains
- * the native counterpart to this class.
- */
-@JNINamespace("base::android")
-public class LibraryLoader {
- private static final String TAG = "LibraryLoader";
-
- // Set to true to enable debug logs.
- private static final boolean DEBUG = false;
-
- // Guards all access to the libraries
- private static final Object sLock = new Object();
-
- // The singleton instance of LibraryLoader.
- private static volatile LibraryLoader sInstance;
-
- // One-way switch becomes true when the libraries are loaded.
- private boolean mLoaded;
-
- // One-way switch becomes true when the Java command line is switched to
- // native.
- private boolean mCommandLineSwitched;
-
- // One-way switch becomes true when the libraries are initialized (
- // by calling nativeLibraryLoaded, which forwards to LibraryLoaded(...) in
- // library_loader_hooks.cc).
- // Note that this member should remain a one-way switch, since it accessed from multiple
- // threads without a lock.
- private volatile boolean mInitialized;
-
- // One-way switches recording attempts to use Relro sharing in the browser.
- // The flags are used to report UMA stats later.
- private boolean mIsUsingBrowserSharedRelros;
- private boolean mLoadAtFixedAddressFailed;
-
- // One-way switch becomes true if the Chromium library was loaded from the
- // APK file directly.
- private boolean mLibraryWasLoadedFromApk;
-
- // One-way switch becomes false if the Chromium library should be loaded
- // directly from the APK file but it was compressed or not aligned.
- private boolean mLibraryIsMappableInApk = true;
-
- // The type of process the shared library is loaded in.
- // This member can be accessed from multiple threads simultaneously, so it have to be
- // final (like now) or be protected in some way (volatile of synchronized).
- private final int mLibraryProcessType;
-
- /**
- * @param libraryProcessType the process the shared library is loaded in. refer to
- * LibraryProcessType for possible values.
- * @return LibraryLoader if existing, otherwise create a new one.
- */
- public static LibraryLoader get(int libraryProcessType) throws ProcessInitException {
- synchronized (sLock) {
- if (sInstance != null) {
- if (sInstance.mLibraryProcessType == libraryProcessType) return sInstance;
- throw new ProcessInitException(
- LoaderErrors.LOADER_ERROR_NATIVE_LIBRARY_LOAD_FAILED);
- }
- sInstance = new LibraryLoader(libraryProcessType);
- return sInstance;
- }
- }
-
- private LibraryLoader(int libraryProcessType) {
- mLibraryProcessType = libraryProcessType;
- }
-
- /**
- * The same as ensureInitialized(null, false), should only be called
- * by non-browser processes.
- *
- * @throws ProcessInitException
- */
- @VisibleForTesting
- public void ensureInitialized() throws ProcessInitException {
- ensureInitialized(null, false);
- }
-
- /**
- * This method blocks until the library is fully loaded and initialized.
- *
- * @param context The context in which the method is called, the caller
- * may pass in a null context if it doesn't know in which context it
- * is running.
- *
- * @param shouldDeleteFallbackLibraries The flag tells whether the method
- * should delete the fallback libraries or not.
- */
- public void ensureInitialized(
- Context context, boolean shouldDeleteFallbackLibraries)
- throws ProcessInitException {
- synchronized (sLock) {
- if (mInitialized) {
- // Already initialized, nothing to do.
- return;
- }
- loadAlreadyLocked(context, shouldDeleteFallbackLibraries);
- initializeAlreadyLocked();
- }
- }
-
- /**
- * Checks if library is fully loaded and initialized.
- */
- public static boolean isInitialized() {
- return sInstance != null && sInstance.mInitialized;
- }
-
- /**
- * The same as loadNow(null, false), should only be called by
- * non-browser process.
- *
- * @throws ProcessInitException
- */
- public void loadNow() throws ProcessInitException {
- loadNow(null, false);
- }
-
- /**
- * Loads the library and blocks until the load completes. The caller is responsible
- * for subsequently calling ensureInitialized().
- * May be called on any thread, but should only be called once. Note the thread
- * this is called on will be the thread that runs the native code's static initializers.
- * See the comment in doInBackground() for more considerations on this.
- *
- * @param context The context the code is running, or null if it doesn't have one.
- * @param shouldDeleteFallbackLibraries The flag tells whether the method
- * should delete the old fallback libraries or not.
- *
- * @throws ProcessInitException if the native library failed to load.
- */
- public void loadNow(Context context, boolean shouldDeleteFallbackLibraries)
- throws ProcessInitException {
- synchronized (sLock) {
- loadAlreadyLocked(context, shouldDeleteFallbackLibraries);
- }
- }
-
- /**
- * initializes the library here and now: must be called on the thread that the
- * native will call its "main" thread. The library must have previously been
- * loaded with loadNow.
- */
- public void initialize() throws ProcessInitException {
- synchronized (sLock) {
- initializeAlreadyLocked();
- }
- }
-
- /** Prefetches the native libraries in a background thread.
- *
- * Launches an AsyncTask that, through a short-lived forked process, reads a
- * part of each page of the native library. This is done to warm up the
- * page cache, turning hard page faults into soft ones.
- *
- * This is done this way, as testing shows that fadvise(FADV_WILLNEED) is
- * detrimental to the startup time.
- *
- * @param context the application context.
- */
- public void asyncPrefetchLibrariesToMemory(final Context context) {
- new AsyncTask<Void, Void, Void>() {
- @Override
- protected Void doInBackground(Void... params) {
- TraceEvent.begin("LibraryLoader.asyncPrefetchLibrariesToMemory");
- boolean success = nativeForkAndPrefetchNativeLibrary();
- if (!success) {
- Log.w(TAG, "Forking a process to prefetch the native library failed.");
- }
- RecordHistogram.recordBooleanHistogram("LibraryLoader.PrefetchStatus", success);
- TraceEvent.end("LibraryLoader.asyncPrefetchLibrariesToMemory");
- return null;
- }
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- }
-
- // Invoke System.loadLibrary(...), triggering JNI_OnLoad in native code
- private void loadAlreadyLocked(
- Context context, boolean shouldDeleteFallbackLibraries)
- throws ProcessInitException {
- try {
- if (!mLoaded) {
- assert !mInitialized;
-
- long startTime = SystemClock.uptimeMillis();
- boolean useChromiumLinker = Linker.isUsed();
- boolean fallbackWasUsed = false;
-
- if (useChromiumLinker) {
- // Determine the APK file path.
- String apkFilePath = null;
- if (context != null) {
- apkFilePath = getLibraryApkPath(context);
- } else {
- Log.w(TAG, "could not check load from APK support due to null context");
- }
-
- // Load libraries using the Chromium linker.
- Linker.prepareLibraryLoad();
-
- for (String library : NativeLibraries.LIBRARIES) {
- // Don't self-load the linker. This is because the build system is
- // not clever enough to understand that all the libraries packaged
- // in the final .apk don't need to be explicitly loaded.
- if (Linker.isChromiumLinkerLibrary(library)) {
- if (DEBUG) Log.i(TAG, "ignoring self-linker load");
- continue;
- }
-
- // Determine where the library should be loaded from.
- String zipFilePath = null;
- String libFilePath = System.mapLibraryName(library);
- if (apkFilePath != null && Linker.isInZipFile()) {
- // The library is in the APK file.
- if (!Linker.checkLibraryIsMappableInApk(apkFilePath, libFilePath)) {
- mLibraryIsMappableInApk = false;
- }
- if (mLibraryIsMappableInApk) {
- // Load directly from the APK.
- zipFilePath = apkFilePath;
- Log.i(TAG, "Loading " + library + " directly from within "
- + apkFilePath);
- } else {
- // Unpack library fallback.
- Log.i(TAG, "Loading " + library
- + " using unpack library fallback from within "
- + apkFilePath);
- libFilePath = LibraryLoaderHelper.buildFallbackLibrary(
- context, library);
- fallbackWasUsed = true;
- Log.i(TAG, "Built fallback library " + libFilePath);
- }
- } else {
- // The library is in its own file.
- Log.i(TAG, "Loading " + library);
- }
-
- // Load the library.
- boolean isLoaded = false;
- if (Linker.isUsingBrowserSharedRelros()) {
- mIsUsingBrowserSharedRelros = true;
- try {
- loadLibrary(zipFilePath, libFilePath);
- isLoaded = true;
- } catch (UnsatisfiedLinkError e) {
- Log.w(TAG, "Failed to load native library with shared RELRO, "
- + "retrying without");
- Linker.disableSharedRelros();
- mLoadAtFixedAddressFailed = true;
- }
- }
- if (!isLoaded) {
- loadLibrary(zipFilePath, libFilePath);
- }
- }
-
- Linker.finishLibraryLoad();
- } else {
- // Load libraries using the system linker.
- for (String library : NativeLibraries.LIBRARIES) {
- System.loadLibrary(library);
- }
- }
-
- if (!fallbackWasUsed && context != null
- && shouldDeleteFallbackLibraries) {
- LibraryLoaderHelper.deleteLibrariesAsynchronously(
- context, LibraryLoaderHelper.LOAD_FROM_APK_FALLBACK_DIR);
- }
-
- long stopTime = SystemClock.uptimeMillis();
- Log.i(TAG, String.format("Time to load native libraries: %d ms (timestamps %d-%d)",
- stopTime - startTime,
- startTime % 10000,
- stopTime % 10000));
-
- mLoaded = true;
- }
- } catch (UnsatisfiedLinkError e) {
- throw new ProcessInitException(LoaderErrors.LOADER_ERROR_NATIVE_LIBRARY_LOAD_FAILED, e);
- }
- // Check that the version of the library we have loaded matches the version we expect
- Log.i(TAG, String.format(
- "Expected native library version number \"%s\","
- + "actual native library version number \"%s\"",
- NativeLibraries.sVersionNumber,
- nativeGetVersionNumber()));
- if (!NativeLibraries.sVersionNumber.equals(nativeGetVersionNumber())) {
- throw new ProcessInitException(LoaderErrors.LOADER_ERROR_NATIVE_LIBRARY_WRONG_VERSION);
- }
- }
-
- // Returns whether the given split name is that of the ABI split.
- private static boolean isAbiSplit(String splitName) {
- // The split name for the ABI split is manually set in the build rules.
- return splitName.startsWith("abi_");
- }
-
- // Returns the path to the .apk that holds the native libraries.
- // This is either the main .apk, or the abi split apk.
- @TargetApi(Build.VERSION_CODES.LOLLIPOP)
- private static String getLibraryApkPath(Context context) {
- ApplicationInfo appInfo = context.getApplicationInfo();
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
- return appInfo.sourceDir;
- }
- PackageInfo packageInfo = PackageUtils.getOwnPackageInfo(context);
- if (packageInfo.splitNames != null) {
- for (int i = 0; i < packageInfo.splitNames.length; ++i) {
- if (isAbiSplit(packageInfo.splitNames[i])) {
- return appInfo.splitSourceDirs[i];
- }
- }
- }
- return appInfo.sourceDir;
- }
-
- // Load a native shared library with the Chromium linker. If the zip file
- // path is not null, the library is loaded directly from the zip file.
- private void loadLibrary(@Nullable String zipFilePath, String libFilePath) {
- Linker.loadLibrary(zipFilePath, libFilePath);
- if (zipFilePath != null) {
- mLibraryWasLoadedFromApk = true;
- }
- }
-
- // The WebView requires the Command Line to be switched over before
- // initialization is done. This is okay in the WebView's case since the
- // JNI is already loaded by this point.
- public void switchCommandLineForWebView() {
- synchronized (sLock) {
- ensureCommandLineSwitchedAlreadyLocked();
- }
- }
-
- // Switch the CommandLine over from Java to native if it hasn't already been done.
- // This must happen after the code is loaded and after JNI is ready (since after the
- // switch the Java CommandLine will delegate all calls the native CommandLine).
- private void ensureCommandLineSwitchedAlreadyLocked() {
- assert mLoaded;
- if (mCommandLineSwitched) {
- return;
- }
- nativeInitCommandLine(CommandLine.getJavaSwitchesOrNull());
- CommandLine.enableNativeProxy();
- mCommandLineSwitched = true;
- }
-
- // Invoke base::android::LibraryLoaded in library_loader_hooks.cc
- private void initializeAlreadyLocked() throws ProcessInitException {
- if (mInitialized) {
- return;
- }
-
- // Setup the native command line if necessary.
- if (!mCommandLineSwitched) {
- nativeInitCommandLine(CommandLine.getJavaSwitchesOrNull());
- }
-
- if (!nativeLibraryLoaded()) {
- Log.e(TAG, "error calling nativeLibraryLoaded");
- throw new ProcessInitException(LoaderErrors.LOADER_ERROR_FAILED_TO_REGISTER_JNI);
- }
-
- // The Chrome JNI is registered by now so we can switch the Java
- // command line over to delegating to native if it's necessary.
- if (!mCommandLineSwitched) {
- CommandLine.enableNativeProxy();
- mCommandLineSwitched = true;
- }
-
- // From now on, keep tracing in sync with native.
- TraceEvent.registerNativeEnabledObserver();
-
- // From this point on, native code is ready to use and checkIsReady()
- // shouldn't complain from now on (and in fact, it's used by the
- // following calls).
- // Note that this flag can be accessed asynchronously, so any initialization
- // must be performed before.
- mInitialized = true;
- }
-
- // Called after all native initializations are complete.
- public void onNativeInitializationComplete(Context context) {
- recordBrowserProcessHistogram(context);
- }
-
- // Record Chromium linker histogram state for the main browser process. Called from
- // onNativeInitializationComplete().
- private void recordBrowserProcessHistogram(Context context) {
- if (Linker.isUsed()) {
- nativeRecordChromiumAndroidLinkerBrowserHistogram(mIsUsingBrowserSharedRelros,
- mLoadAtFixedAddressFailed,
- getLibraryLoadFromApkStatus(context));
- }
- }
-
- // Returns the device's status for loading a library directly from the APK file.
- // This method can only be called when the Chromium linker is used.
- private int getLibraryLoadFromApkStatus(Context context) {
- assert Linker.isUsed();
-
- if (mLibraryWasLoadedFromApk) {
- return LibraryLoadFromApkStatusCodes.SUCCESSFUL;
- }
-
- if (!mLibraryIsMappableInApk) {
- return LibraryLoadFromApkStatusCodes.USED_UNPACK_LIBRARY_FALLBACK;
- }
-
- // There were no libraries to be loaded directly from the APK file.
- return LibraryLoadFromApkStatusCodes.UNKNOWN;
- }
-
- // Register pending Chromium linker histogram state for renderer processes. This cannot be
- // recorded as a histogram immediately because histograms and IPC are not ready at the
- // time it are captured. This function stores a pending value, so that a later call to
- // RecordChromiumAndroidLinkerRendererHistogram() will record it correctly.
- public void registerRendererProcessHistogram(boolean requestedSharedRelro,
- boolean loadAtFixedAddressFailed) {
- if (Linker.isUsed()) {
- nativeRegisterChromiumAndroidLinkerRendererHistogram(requestedSharedRelro,
- loadAtFixedAddressFailed);
- }
- }
-
- /**
- * @return the process the shared library is loaded in, see the LibraryProcessType
- * for possible values.
- */
- @CalledByNative
- public static int getLibraryProcessType() {
- if (sInstance == null) return LibraryProcessType.PROCESS_UNINITIALIZED;
- return sInstance.mLibraryProcessType;
- }
-
- private native void nativeInitCommandLine(String[] initCommandLine);
-
- // Only methods needed before or during normal JNI registration are during System.OnLoad.
- // nativeLibraryLoaded is then called to register everything else. This process is called
- // "initialization". This method will be mapped (by generated code) to the LibraryLoaded
- // definition in base/android/library_loader/library_loader_hooks.cc.
- //
- // Return true on success and false on failure.
- private native boolean nativeLibraryLoaded();
-
- // Method called to record statistics about the Chromium linker operation for the main
- // browser process. Indicates whether the linker attempted relro sharing for the browser,
- // and if it did, whether the library failed to load at a fixed address. Also records
- // support for loading a library directly from the APK file.
- private native void nativeRecordChromiumAndroidLinkerBrowserHistogram(
- boolean isUsingBrowserSharedRelros,
- boolean loadAtFixedAddressFailed,
- int libraryLoadFromApkStatus);
-
- // Method called to register (for later recording) statistics about the Chromium linker
- // operation for a renderer process. Indicates whether the linker attempted relro sharing,
- // and if it did, whether the library failed to load at a fixed address.
- private native void nativeRegisterChromiumAndroidLinkerRendererHistogram(
- boolean requestedSharedRelro,
- boolean loadAtFixedAddressFailed);
-
- // Get the version of the native library. This is needed so that we can check we
- // have the right version before initializing the (rest of the) JNI.
- private native String nativeGetVersionNumber();
-
- // Finds the ranges corresponding to the native library pages, forks a new
- // process to prefetch these pages and waits for it. The new process then
- // terminates. This is blocking.
- private static native boolean nativeForkAndPrefetchNativeLibrary();
-}
diff --git a/base/android/java/src/org/chromium/base/library_loader/LibraryLoaderHelper.java b/base/android/java/src/org/chromium/base/library_loader/LibraryLoaderHelper.java
deleted file mode 100644
index 7dd1a29a0e..0000000000
--- a/base/android/java/src/org/chromium/base/library_loader/LibraryLoaderHelper.java
+++ /dev/null
@@ -1,338 +0,0 @@
-// Copyright 2014 The Chromium 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.library_loader;
-
-import android.content.Context;
-import android.util.Log;
-
-import java.io.BufferedOutputStream;
-import java.io.Closeable;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipException;
-import java.util.zip.ZipFile;
-
-/**
- * Class representing an exception which occured during the unpacking process.
- */
-class UnpackingException extends Exception {
- public UnpackingException(String message, Throwable cause) {
- super(message, cause);
- }
-
- public UnpackingException(String message) {
- super(message);
- }
-}
-
-/**
- * The class provides helper functions to extract native libraries from APK,
- * and load libraries from there.
- */
-class LibraryLoaderHelper {
- private static final String TAG = "LibraryLoaderHelper";
-
- // Fallback directories.
- static final String LOAD_FROM_APK_FALLBACK_DIR = "fallback";
-
- private static final int BUFFER_SIZE = 16384;
-
- /**
- * Returns the directory for holding extracted native libraries.
- * It may create the directory if it doesn't exist.
- *
- * @param context The context the code is running.
- * @param dirName The name of the directory containing the libraries.
- * @return The directory file object.
- */
- static File getLibDir(Context context, String dirName) {
- return context.getDir(dirName, Context.MODE_PRIVATE);
- }
-
- /**
- * Delete libraries and their directory synchronously.
- */
- private static void deleteLibrariesSynchronously(Context context, String dirName) {
- File libDir = getLibDir(context, dirName);
- deleteObsoleteLibraries(libDir, Collections.<File>emptyList());
- }
-
- /**
- * Delete libraries and their directory asynchronously.
- * The actual deletion is done in a background thread.
- */
- static void deleteLibrariesAsynchronously(
- final Context context, final String dirName) {
- // Child process should not reach here.
- new Thread() {
- @Override
- public void run() {
- deleteLibrariesSynchronously(context, dirName);
- }
- }.start();
- }
-
- /**
- * Copy a library from a zip file to the application's private directory.
- * This is used as a fallback when we are unable to load the library
- * directly from the APK file (crbug.com/390618).
- *
- * @param context The context the code is running in.
- * @param library Library name.
- * @return name of the fallback copy of the library.
- */
- static String buildFallbackLibrary(Context context, String library) {
- try {
- String libName = System.mapLibraryName(library);
- File fallbackLibDir = getLibDir(context, LOAD_FROM_APK_FALLBACK_DIR);
- File fallbackLibFile = new File(fallbackLibDir, libName);
- String pathInZipFile = Linker.getLibraryFilePathInZipFile(libName);
- Map<String, File> dstFiles = Collections.singletonMap(pathInZipFile, fallbackLibFile);
-
- deleteObsoleteLibraries(fallbackLibDir, dstFiles.values());
- unpackLibraries(context, dstFiles);
-
- return fallbackLibFile.getAbsolutePath();
- } catch (Exception e) {
- String errorMessage = "Unable to load fallback for library " + library
- + " (" + (e.getMessage() == null ? e.toString() : e.getMessage()) + ")";
- Log.e(TAG, errorMessage, e);
- throw new UnsatisfiedLinkError(errorMessage);
- }
- }
-
- // Delete obsolete libraries from a library folder.
- private static void deleteObsoleteLibraries(File libDir, Collection<File> keptFiles) {
- try {
- // Build a list of libraries that should NOT be deleted.
- Set<String> keptFileNames = new HashSet<String>();
- for (File k : keptFiles) {
- keptFileNames.add(k.getName());
- }
-
- // Delete the obsolete libraries.
- Log.i(TAG, "Deleting obsolete libraries in " + libDir.getPath());
- File[] files = libDir.listFiles();
- if (files != null) {
- for (File f : files) {
- if (!keptFileNames.contains(f.getName())) {
- delete(f);
- }
- }
- } else {
- Log.e(TAG, "Failed to list files in " + libDir.getPath());
- }
-
- // Delete the folder if no libraries were kept.
- if (keptFileNames.isEmpty()) {
- delete(libDir);
- }
- } catch (Exception e) {
- Log.e(TAG, "Failed to remove obsolete libraries from " + libDir.getPath());
- }
- }
-
- // Unpack libraries from a zip file to the file system.
- private static void unpackLibraries(Context context,
- Map<String, File> dstFiles) throws UnpackingException {
- String zipFilePath = context.getApplicationInfo().sourceDir;
- Log.i(TAG, "Opening zip file " + zipFilePath);
- File zipFile = new File(zipFilePath);
- ZipFile zipArchive = openZipFile(zipFile);
-
- try {
- for (Entry<String, File> d : dstFiles.entrySet()) {
- String pathInZipFile = d.getKey();
- File dstFile = d.getValue();
- Log.i(TAG, "Unpacking " + pathInZipFile
- + " to " + dstFile.getAbsolutePath());
- ZipEntry packedLib = zipArchive.getEntry(pathInZipFile);
-
- if (needToUnpackLibrary(zipFile, packedLib, dstFile)) {
- unpackLibraryFromZipFile(zipArchive, packedLib, dstFile);
- setLibraryFilePermissions(dstFile);
- }
- }
- } finally {
- closeZipFile(zipArchive);
- }
- }
-
- // Open a zip file.
- private static ZipFile openZipFile(File zipFile) throws UnpackingException {
- try {
- return new ZipFile(zipFile);
- } catch (ZipException e) {
- throw new UnpackingException("Failed to open zip file " + zipFile.getPath());
- } catch (IOException e) {
- throw new UnpackingException("Failed to open zip file " + zipFile.getPath());
- }
- }
-
- // Determine whether it is necessary to unpack a library from a zip file.
- private static boolean needToUnpackLibrary(
- File zipFile, ZipEntry packedLib, File dstFile) {
- // Check if the fallback library already exists.
- if (!dstFile.exists()) {
- Log.i(TAG, "File " + dstFile.getPath() + " does not exist yet");
- return true;
- }
-
- // Check last modification dates.
- long zipTime = zipFile.lastModified();
- long fallbackLibTime = dstFile.lastModified();
- if (zipTime > fallbackLibTime) {
- Log.i(TAG, "Not using existing fallback file because "
- + "the APK file " + zipFile.getPath()
- + " (timestamp=" + zipTime + ") is newer than "
- + "the fallback library " + dstFile.getPath()
- + "(timestamp=" + fallbackLibTime + ")");
- return true;
- }
-
- // Check file sizes.
- long packedLibSize = packedLib.getSize();
- long fallbackLibSize = dstFile.length();
- if (fallbackLibSize != packedLibSize) {
- Log.i(TAG, "Not using existing fallback file because "
- + "the library in the APK " + zipFile.getPath()
- + " (" + packedLibSize + "B) has a different size than "
- + "the fallback library " + dstFile.getPath()
- + "(" + fallbackLibSize + "B)");
- return true;
- }
-
- Log.i(TAG, "Reusing existing file " + dstFile.getPath());
- return false;
- }
-
- // Unpack a library from a zip file to the filesystem.
- private static void unpackLibraryFromZipFile(ZipFile zipArchive, ZipEntry packedLib,
- File dstFile) throws UnpackingException {
- // Open input stream for the library file inside the zip file.
- InputStream in;
- try {
- in = zipArchive.getInputStream(packedLib);
- } catch (IOException e) {
- throw new UnpackingException(
- "IO exception when locating library in the zip file", e);
- }
-
- // Ensure that the input stream is closed at the end.
- try {
- // Delete existing file if it exists.
- if (dstFile.exists()) {
- Log.i(TAG, "Deleting existing unpacked library file " + dstFile.getPath());
- if (!dstFile.delete()) {
- throw new UnpackingException(
- "Failed to delete existing unpacked library file " + dstFile.getPath());
- }
- }
-
- // Ensure that the library folder exists. Since this is added
- // for increased robustness, we log errors and carry on.
- try {
- dstFile.getParentFile().mkdirs();
- } catch (Exception e) {
- Log.e(TAG, "Failed to make library folder", e);
- }
-
- // Create the destination file.
- try {
- if (!dstFile.createNewFile()) {
- throw new UnpackingException("existing unpacked library file was not deleted");
- }
- } catch (IOException e) {
- throw new UnpackingException("failed to create unpacked library file", e);
- }
-
- // Open the output stream for the destination file.
- OutputStream out;
- try {
- out = new BufferedOutputStream(new FileOutputStream(dstFile));
- } catch (FileNotFoundException e) {
- throw new UnpackingException(
- "failed to open output stream for unpacked library file", e);
- }
-
- // Ensure that the output stream is closed at the end.
- try {
- // Copy the library from the zip file to the destination file.
- Log.i(TAG, "Copying " + packedLib.getName() + " from " + zipArchive.getName()
- + " to " + dstFile.getPath());
- byte[] buffer = new byte[BUFFER_SIZE];
- int len;
- while ((len = in.read(buffer)) != -1) {
- out.write(buffer, 0, len);
- }
- } catch (IOException e) {
- throw new UnpackingException(
- "failed to copy the library from the zip file", e);
- } finally {
- close(out, "output stream");
- }
- } finally {
- close(in, "input stream");
- }
- }
-
- // Set up library file permissions.
- private static void setLibraryFilePermissions(File libFile) {
- // Change permission to rwxr-xr-x
- Log.i(TAG, "Setting file permissions for " + libFile.getPath());
- if (!libFile.setReadable(/* readable */ true, /* ownerOnly */ false)) {
- Log.e(TAG, "failed to chmod a+r the temporary file");
- }
- if (!libFile.setExecutable(/* executable */ true, /* ownerOnly */ false)) {
- Log.e(TAG, "failed to chmod a+x the temporary file");
- }
- if (!libFile.setWritable(/* writable */ true)) {
- Log.e(TAG, "failed to chmod +w the temporary file");
- }
- }
-
- // Close a closable and log a warning if it fails.
- private static void close(Closeable closeable, String name) {
- try {
- closeable.close();
- } catch (IOException e) {
- // Warn and ignore.
- Log.w(TAG, "IO exception when closing " + name, e);
- }
- }
-
- // Close a zip file and log a warning if it fails.
- // This needs to be a separate method because ZipFile is not Closeable in
- // Java 6 (used on some older devices).
- private static void closeZipFile(ZipFile file) {
- try {
- file.close();
- } catch (IOException e) {
- // Warn and ignore.
- Log.w(TAG, "IO exception when closing zip file", e);
- }
- }
-
- // Delete a file and log it.
- private static void delete(File file) {
- if (file.delete()) {
- Log.i(TAG, "Deleted " + file.getPath());
- } else {
- Log.w(TAG, "Failed to delete " + file.getPath());
- }
- }
-}
diff --git a/base/android/java/src/org/chromium/base/library_loader/Linker.java b/base/android/java/src/org/chromium/base/library_loader/Linker.java
deleted file mode 100644
index 9a64a3fddb..0000000000
--- a/base/android/java/src/org/chromium/base/library_loader/Linker.java
+++ /dev/null
@@ -1,1095 +0,0 @@
-// Copyright 2014 The Chromium 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.library_loader;
-
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.ParcelFileDescriptor;
-import android.os.Parcelable;
-import android.util.Log;
-
-import org.chromium.base.CalledByNative;
-import org.chromium.base.SysUtils;
-import org.chromium.base.ThreadUtils;
-import org.chromium.base.annotations.AccessedByNative;
-
-import java.io.FileNotFoundException;
-import java.util.HashMap;
-import java.util.Locale;
-import java.util.Map;
-
-import javax.annotation.Nullable;
-
-/*
- * Technical note:
- *
- * The point of this class is to provide an alternative to System.loadLibrary()
- * to load native shared libraries. One specific feature that it supports is the
- * ability to save RAM by sharing the ELF RELRO sections between renderer
- * processes.
- *
- * When two processes load the same native library at the _same_ memory address,
- * the content of their RELRO section (which includes C++ vtables or any
- * constants that contain pointers) will be largely identical [1].
- *
- * By default, the RELRO section is backed by private RAM in each process,
- * which is still significant on mobile (e.g. 1.28 MB / process on Chrome 30 for
- * Android).
- *
- * However, it is possible to save RAM by creating a shared memory region,
- * copy the RELRO content into it, then have each process swap its private,
- * regular RELRO, with a shared, read-only, mapping of the shared one.
- *
- * This trick saves 98% of the RELRO section size per extra process, after the
- * first one. On the other hand, this requires careful communication between
- * the process where the shared RELRO is created and the one(s) where it is used.
- *
- * Note that swapping the regular RELRO with the shared one is not an atomic
- * operation. Care must be taken that no other thread tries to run native code
- * that accesses it during it. In practice, this means the swap must happen
- * before library native code is executed.
- *
- * [1] The exceptions are pointers to external, randomized, symbols, like
- * those from some system libraries, but these are very few in practice.
- */
-
-/*
- * Security considerations:
- *
- * - Whether the browser process loads its native libraries at the same
- * addresses as the service ones (to save RAM by sharing the RELRO too)
- * depends on the configuration variable BROWSER_SHARED_RELRO_CONFIG below.
- *
- * Not using fixed library addresses in the browser process is preferred
- * for regular devices since it maintains the efficacy of ASLR as an
- * exploit mitigation across the render <-> browser privilege boundary.
- *
- * - The shared RELRO memory region is always forced read-only after creation,
- * which means it is impossible for a compromised service process to map
- * it read-write (e.g. by calling mmap() or mprotect()) and modify its
- * content, altering values seen in other service processes.
- *
- * - Unfortunately, certain Android systems use an old, buggy kernel, that
- * doesn't check Ashmem region permissions correctly. See CVE-2011-1149
- * for details. This linker probes the system on startup and will completely
- * disable shared RELROs if it detects the problem. For the record, this is
- * common for Android emulator system images (which are still based on 2.6.29)
- *
- * - Once the RELRO ashmem region is mapped into a service process' address
- * space, the corresponding file descriptor is immediately closed. The
- * file descriptor is kept opened in the browser process, because a copy needs
- * to be sent to each new potential service process.
- *
- * - The common library load addresses are randomized for each instance of
- * the program on the device. See computeRandomBaseLoadAddress() for more
- * details on how this is computed.
- *
- * - When loading several libraries in service processes, a simple incremental
- * approach from the original random base load address is used. This is
- * sufficient to deal correctly with component builds (which can use dozens
- * of shared libraries), while regular builds always embed a single shared
- * library per APK.
- */
-
-/**
- * Here's an explanation of how this class is supposed to be used:
- *
- * - Native shared libraries should be loaded with Linker.loadLibrary(),
- * instead of System.loadLibrary(). The two functions take the same parameter
- * and should behave the same (at a high level).
- *
- * - Before loading any library, prepareLibraryLoad() should be called.
- *
- * - After loading all libraries, finishLibraryLoad() should be called, before
- * running any native code from any of the libraries (except their static
- * constructors, which can't be avoided).
- *
- * - A service process shall call either initServiceProcess() or
- * disableSharedRelros() early (i.e. before any loadLibrary() call).
- * Otherwise, the linker considers that it is running inside the browser
- * process. This is because various Chromium projects have vastly
- * different initialization paths.
- *
- * disableSharedRelros() completely disables shared RELROs, and loadLibrary()
- * will behave exactly like System.loadLibrary().
- *
- * initServiceProcess(baseLoadAddress) indicates that shared RELROs are to be
- * used in this process.
- *
- * - The browser is in charge of deciding where in memory each library should
- * be loaded. This address must be passed to each service process (see
- * ChromiumLinkerParams.java in content for a helper class to do so).
- *
- * - The browser will also generate shared RELROs for each library it loads.
- * More specifically, by default when in the browser process, the linker
- * will:
- *
- * - Load libraries randomly (just like System.loadLibrary()).
- * - Compute the fixed address to be used to load the same library
- * in service processes.
- * - Create a shared memory region populated with the RELRO region
- * content pre-relocated for the specific fixed address above.
- *
- * Note that these shared RELRO regions cannot be used inside the browser
- * process. They are also never mapped into it.
- *
- * This behaviour is altered by the BROWSER_SHARED_RELRO_CONFIG configuration
- * variable below, which may force the browser to load the libraries at
- * fixed addresses too.
- *
- * - Once all libraries are loaded in the browser process, one can call
- * getSharedRelros() which returns a Bundle instance containing a map that
- * links each loaded library to its shared RELRO region.
- *
- * This Bundle must be passed to each service process, for example through
- * a Binder call (note that the Bundle includes file descriptors and cannot
- * be added as an Intent extra).
- *
- * - In a service process, finishLibraryLoad() will block until the RELRO
- * section Bundle is received. This is typically done by calling
- * useSharedRelros() from another thread.
- *
- * This method also ensures the process uses the shared RELROs.
- */
-public class Linker {
-
- // Log tag for this class. This must match the name of the linker's native library.
- private static final String TAG = "chromium_android_linker";
-
- // Set to true to enable debug logs.
- private static final boolean DEBUG = false;
-
- // Constants used to control the behaviour of the browser process with
- // regards to the shared RELRO section.
- // NEVER -> The browser never uses it itself.
- // LOW_RAM_ONLY -> It is only used on devices with low RAM.
- // ALWAYS -> It is always used.
- // NOTE: These names are known and expected by the Linker test scripts.
- public static final int BROWSER_SHARED_RELRO_CONFIG_NEVER = 0;
- public static final int BROWSER_SHARED_RELRO_CONFIG_LOW_RAM_ONLY = 1;
- public static final int BROWSER_SHARED_RELRO_CONFIG_ALWAYS = 2;
-
- // Configuration variable used to control how the browser process uses the
- // shared RELRO. Only change this while debugging linker-related issues.
- // NOTE: This variable's name is known and expected by the Linker test scripts.
- public static final int BROWSER_SHARED_RELRO_CONFIG =
- BROWSER_SHARED_RELRO_CONFIG_LOW_RAM_ONLY;
-
- // Constants used to control the value of sMemoryDeviceConfig.
- // INIT -> Value is undetermined (will check at runtime).
- // LOW -> This is a low-memory device.
- // NORMAL -> This is not a low-memory device.
- public static final int MEMORY_DEVICE_CONFIG_INIT = 0;
- public static final int MEMORY_DEVICE_CONFIG_LOW = 1;
- public static final int MEMORY_DEVICE_CONFIG_NORMAL = 2;
-
- // Indicates if this is a low-memory device or not. The default is to
- // determine this by probing the system at runtime, but this can be forced
- // for testing by calling setMemoryDeviceConfig().
- private static int sMemoryDeviceConfig = MEMORY_DEVICE_CONFIG_INIT;
-
- // Becomes true after linker initialization.
- private static boolean sInitialized = false;
-
- // Set to true to indicate that the system supports safe sharing of RELRO sections.
- private static boolean sRelroSharingSupported = false;
-
- // Set to true if this runs in the browser process. Disabled by initServiceProcess().
- // TODO(petrcermak): This flag can be incorrectly set to false (even though this might run in
- // the browser process) on low-memory devices.
- private static boolean sInBrowserProcess = true;
-
- // Becomes true to indicate this process needs to wait for a shared RELRO in
- // finishLibraryLoad().
- private static boolean sWaitForSharedRelros = false;
-
- // Becomes true when initialization determines that the browser process can use the
- // shared RELRO.
- private static boolean sBrowserUsesSharedRelro = false;
-
- // The map of all RELRO sections either created or used in this process.
- private static Bundle sSharedRelros = null;
-
- // Current common random base load address.
- private static long sBaseLoadAddress = 0;
-
- // Current fixed-location load address for the next library called by loadLibrary().
- private static long sCurrentLoadAddress = 0;
-
- // Becomes true once prepareLibraryLoad() has been called.
- private static boolean sPrepareLibraryLoadCalled = false;
-
- // Used internally to initialize the linker's static data. Assume lock is held.
- private static void ensureInitializedLocked() {
- assert Thread.holdsLock(Linker.class);
-
- if (!sInitialized) {
- sRelroSharingSupported = false;
- if (NativeLibraries.sUseLinker) {
- if (DEBUG) Log.i(TAG, "Loading lib" + TAG + ".so");
- try {
- System.loadLibrary(TAG);
- } catch (UnsatisfiedLinkError e) {
- // In a component build, the ".cr" suffix is added to each library name.
- Log.w(TAG, "Couldn't load lib" + TAG + ".so, trying lib" + TAG + ".cr.so");
- System.loadLibrary(TAG + ".cr");
- }
- sRelroSharingSupported = nativeCanUseSharedRelro();
- if (!sRelroSharingSupported) {
- Log.w(TAG, "This system cannot safely share RELRO sections");
- } else {
- if (DEBUG) Log.i(TAG, "This system supports safe shared RELRO sections");
- }
-
- if (sMemoryDeviceConfig == MEMORY_DEVICE_CONFIG_INIT) {
- sMemoryDeviceConfig = SysUtils.isLowEndDevice()
- ? MEMORY_DEVICE_CONFIG_LOW : MEMORY_DEVICE_CONFIG_NORMAL;
- }
-
- switch (BROWSER_SHARED_RELRO_CONFIG) {
- case BROWSER_SHARED_RELRO_CONFIG_NEVER:
- sBrowserUsesSharedRelro = false;
- break;
- case BROWSER_SHARED_RELRO_CONFIG_LOW_RAM_ONLY:
- sBrowserUsesSharedRelro =
- (sMemoryDeviceConfig == MEMORY_DEVICE_CONFIG_LOW);
- if (sBrowserUsesSharedRelro) {
- Log.w(TAG, "Low-memory device: shared RELROs used in all processes");
- }
- break;
- case BROWSER_SHARED_RELRO_CONFIG_ALWAYS:
- Log.w(TAG, "Beware: shared RELROs used in all processes!");
- sBrowserUsesSharedRelro = true;
- break;
- default:
- assert false : "Unreached";
- break;
- }
- } else {
- if (DEBUG) Log.i(TAG, "Linker disabled");
- }
-
- if (!sRelroSharingSupported) {
- // Sanity.
- sBrowserUsesSharedRelro = false;
- sWaitForSharedRelros = false;
- }
-
- sInitialized = true;
- }
- }
-
- /**
- * A public interface used to run runtime linker tests after loading
- * libraries. Should only be used to implement the linker unit tests,
- * which is controlled by the value of NativeLibraries.sEnableLinkerTests
- * configured at build time.
- */
- public interface TestRunner {
- /**
- * Run runtime checks and return true if they all pass.
- * @param memoryDeviceConfig The current memory device configuration.
- * @param inBrowserProcess true iff this is the browser process.
- */
- public boolean runChecks(int memoryDeviceConfig, boolean inBrowserProcess);
- }
-
- // The name of a class that implements TestRunner.
- static String sTestRunnerClassName = null;
-
- /**
- * Set the TestRunner by its class name. It will be instantiated at
- * runtime after all libraries are loaded.
- * @param testRunnerClassName null or a String for the class name of the
- * TestRunner to use.
- */
- public static void setTestRunnerClassName(String testRunnerClassName) {
- if (DEBUG) Log.i(TAG, "setTestRunnerByClassName(" + testRunnerClassName + ") called");
-
- if (!NativeLibraries.sEnableLinkerTests) {
- // Ignore this in production code to prevent malvolent runtime injection.
- return;
- }
-
- synchronized (Linker.class) {
- assert sTestRunnerClassName == null;
- sTestRunnerClassName = testRunnerClassName;
- }
- }
-
- /**
- * Call this to retrieve the name of the current TestRunner class name
- * if any. This can be useful to pass it from the browser process to
- * child ones.
- * @return null or a String holding the name of the class implementing
- * the TestRunner set by calling setTestRunnerClassName() previously.
- */
- public static String getTestRunnerClassName() {
- synchronized (Linker.class) {
- return sTestRunnerClassName;
- }
- }
-
- /**
- * Call this method before any other Linker method to force a specific
- * memory device configuration. Should only be used for testing.
- * @param memoryDeviceConfig either MEMORY_DEVICE_CONFIG_LOW or MEMORY_DEVICE_CONFIG_NORMAL.
- */
- public static void setMemoryDeviceConfig(int memoryDeviceConfig) {
- if (DEBUG) Log.i(TAG, "setMemoryDeviceConfig(" + memoryDeviceConfig + ") called");
- // Sanity check. This method should only be called during tests.
- assert NativeLibraries.sEnableLinkerTests;
- synchronized (Linker.class) {
- assert sMemoryDeviceConfig == MEMORY_DEVICE_CONFIG_INIT;
- assert memoryDeviceConfig == MEMORY_DEVICE_CONFIG_LOW
- || memoryDeviceConfig == MEMORY_DEVICE_CONFIG_NORMAL;
- if (DEBUG) {
- if (memoryDeviceConfig == MEMORY_DEVICE_CONFIG_LOW) {
- Log.i(TAG, "Simulating a low-memory device");
- } else {
- Log.i(TAG, "Simulating a regular-memory device");
- }
- }
- sMemoryDeviceConfig = memoryDeviceConfig;
- }
- }
-
- /**
- * Call this method to determine if this chromium project must
- * use this linker. If not, System.loadLibrary() should be used to load
- * libraries instead.
- */
- public static boolean isUsed() {
- // Only GYP targets that are APKs and have the 'use_chromium_linker' variable
- // defined as 1 will use this linker. For all others (the default), the
- // auto-generated NativeLibraries.sUseLinker variable will be false.
- if (!NativeLibraries.sUseLinker) return false;
-
- synchronized (Linker.class) {
- ensureInitializedLocked();
- // At the moment, there is also no point in using this linker if the
- // system does not support RELRO sharing safely.
- return sRelroSharingSupported;
- }
- }
-
- /**
- * Call this method to determine if the linker will try to use shared RELROs
- * for the browser process.
- */
- public static boolean isUsingBrowserSharedRelros() {
- synchronized (Linker.class) {
- ensureInitializedLocked();
- return sBrowserUsesSharedRelro;
- }
- }
-
- /**
- * Call this method to determine if the chromium project must load
- * the library directly from the zip file.
- */
- public static boolean isInZipFile() {
- return NativeLibraries.sUseLibraryInZipFile;
- }
-
- /**
- * Call this method just before loading any native shared libraries in this process.
- */
- public static void prepareLibraryLoad() {
- if (DEBUG) Log.i(TAG, "prepareLibraryLoad() called");
- synchronized (Linker.class) {
- sPrepareLibraryLoadCalled = true;
-
- if (sInBrowserProcess) {
- // Force generation of random base load address, as well
- // as creation of shared RELRO sections in this process.
- setupBaseLoadAddressLocked();
- }
- }
- }
-
- /**
- * Call this method just after loading all native shared libraries in this process.
- * Note that when in a service process, this will block until the RELRO bundle is
- * received, i.e. when another thread calls useSharedRelros().
- */
- public static void finishLibraryLoad() {
- if (DEBUG) Log.i(TAG, "finishLibraryLoad() called");
- synchronized (Linker.class) {
- if (DEBUG) Log.i(TAG, String.format(
- Locale.US,
- "sInBrowserProcess=%s sBrowserUsesSharedRelro=%s sWaitForSharedRelros=%s",
- sInBrowserProcess ? "true" : "false",
- sBrowserUsesSharedRelro ? "true" : "false",
- sWaitForSharedRelros ? "true" : "false"));
-
- if (sLoadedLibraries == null) {
- if (DEBUG) Log.i(TAG, "No libraries loaded");
- } else {
- if (sInBrowserProcess) {
- // Create new Bundle containing RELRO section information
- // for all loaded libraries. Make it available to getSharedRelros().
- sSharedRelros = createBundleFromLibInfoMap(sLoadedLibraries);
- if (DEBUG) {
- Log.i(TAG, "Shared RELRO created");
- dumpBundle(sSharedRelros);
- }
-
- if (sBrowserUsesSharedRelro) {
- useSharedRelrosLocked(sSharedRelros);
- }
- }
-
- if (sWaitForSharedRelros) {
- assert !sInBrowserProcess;
-
- // Wait until the shared relro bundle is received from useSharedRelros().
- while (sSharedRelros == null) {
- try {
- Linker.class.wait();
- } catch (InterruptedException ie) {
- // no-op
- }
- }
- useSharedRelrosLocked(sSharedRelros);
- // Clear the Bundle to ensure its file descriptor references can't be reused.
- sSharedRelros.clear();
- sSharedRelros = null;
- }
- }
-
- if (NativeLibraries.sEnableLinkerTests && sTestRunnerClassName != null) {
- // The TestRunner implementation must be instantiated _after_
- // all libraries are loaded to ensure that its native methods
- // are properly registered.
- if (DEBUG) Log.i(TAG, "Instantiating " + sTestRunnerClassName);
- TestRunner testRunner = null;
- try {
- testRunner = (TestRunner)
- Class.forName(sTestRunnerClassName).newInstance();
- } catch (Exception e) {
- Log.e(TAG, "Could not extract test runner class name", e);
- testRunner = null;
- }
- if (testRunner != null) {
- if (!testRunner.runChecks(sMemoryDeviceConfig, sInBrowserProcess)) {
- Log.wtf(TAG, "Linker runtime tests failed in this process!!");
- assert false;
- } else {
- Log.i(TAG, "All linker tests passed!");
- }
- }
- }
- }
- if (DEBUG) Log.i(TAG, "finishLibraryLoad() exiting");
- }
-
- /**
- * Call this to send a Bundle containing the shared RELRO sections to be
- * used in this process. If initServiceProcess() was previously called,
- * finishLibraryLoad() will not exit until this method is called in another
- * thread with a non-null value.
- * @param bundle The Bundle instance containing a map of shared RELRO sections
- * to use in this process.
- */
- public static void useSharedRelros(Bundle bundle) {
- // Ensure the bundle uses the application's class loader, not the framework
- // one which doesn't know anything about LibInfo.
- // Also, hold a fresh copy of it so the caller can't recycle it.
- Bundle clonedBundle = null;
- if (bundle != null) {
- bundle.setClassLoader(LibInfo.class.getClassLoader());
- clonedBundle = new Bundle(LibInfo.class.getClassLoader());
- Parcel parcel = Parcel.obtain();
- bundle.writeToParcel(parcel, 0);
- parcel.setDataPosition(0);
- clonedBundle.readFromParcel(parcel);
- parcel.recycle();
- }
- if (DEBUG) {
- Log.i(TAG, "useSharedRelros() called with " + bundle
- + ", cloned " + clonedBundle);
- }
- synchronized (Linker.class) {
- // Note that in certain cases, this can be called before
- // initServiceProcess() in service processes.
- sSharedRelros = clonedBundle;
- // Tell any listener blocked in finishLibraryLoad() about it.
- Linker.class.notifyAll();
- }
- }
-
- /**
- * Call this to retrieve the shared RELRO sections created in this process,
- * after loading all libraries.
- * @return a new Bundle instance, or null if RELRO sharing is disabled on
- * this system, or if initServiceProcess() was called previously.
- */
- public static Bundle getSharedRelros() {
- if (DEBUG) Log.i(TAG, "getSharedRelros() called");
- synchronized (Linker.class) {
- if (!sInBrowserProcess) {
- if (DEBUG) Log.i(TAG, "... returning null Bundle");
- return null;
- }
-
- // Return the Bundle created in finishLibraryLoad().
- if (DEBUG) Log.i(TAG, "... returning " + sSharedRelros);
- return sSharedRelros;
- }
- }
-
-
- /**
- * Call this method before loading any libraries to indicate that this
- * process shall neither create or reuse shared RELRO sections.
- */
- public static void disableSharedRelros() {
- if (DEBUG) Log.i(TAG, "disableSharedRelros() called");
- synchronized (Linker.class) {
- sInBrowserProcess = false;
- sWaitForSharedRelros = false;
- sBrowserUsesSharedRelro = false;
- }
- }
-
- /**
- * Call this method before loading any libraries to indicate that this
- * process is ready to reuse shared RELRO sections from another one.
- * Typically used when starting service processes.
- * @param baseLoadAddress the base library load address to use.
- */
- public static void initServiceProcess(long baseLoadAddress) {
- if (DEBUG) {
- Log.i(TAG, String.format(
- Locale.US, "initServiceProcess(0x%x) called", baseLoadAddress));
- }
- synchronized (Linker.class) {
- ensureInitializedLocked();
- sInBrowserProcess = false;
- sBrowserUsesSharedRelro = false;
- if (sRelroSharingSupported) {
- sWaitForSharedRelros = true;
- sBaseLoadAddress = baseLoadAddress;
- sCurrentLoadAddress = baseLoadAddress;
- }
- }
- }
-
- /**
- * Retrieve the base load address of all shared RELRO sections.
- * This also enforces the creation of shared RELRO sections in
- * prepareLibraryLoad(), which can later be retrieved with getSharedRelros().
- * @return a common, random base load address, or 0 if RELRO sharing is
- * disabled.
- */
- public static long getBaseLoadAddress() {
- synchronized (Linker.class) {
- ensureInitializedLocked();
- if (!sInBrowserProcess) {
- Log.w(TAG, "Shared RELRO sections are disabled in this process!");
- return 0;
- }
-
- setupBaseLoadAddressLocked();
- if (DEBUG) Log.i(TAG, String.format(Locale.US, "getBaseLoadAddress() returns 0x%x",
- sBaseLoadAddress));
- return sBaseLoadAddress;
- }
- }
-
- // Used internally to lazily setup the common random base load address.
- private static void setupBaseLoadAddressLocked() {
- assert Thread.holdsLock(Linker.class);
- if (sBaseLoadAddress == 0) {
- long address = computeRandomBaseLoadAddress();
- sBaseLoadAddress = address;
- sCurrentLoadAddress = address;
- if (address == 0) {
- // If the computed address is 0, there are issues with finding enough
- // free address space, so disable RELRO shared / fixed load addresses.
- Log.w(TAG, "Disabling shared RELROs due address space pressure");
- sBrowserUsesSharedRelro = false;
- sWaitForSharedRelros = false;
- }
- }
- }
-
-
- /**
- * Compute a random base load address at which to place loaded libraries.
- * @return new base load address, or 0 if the system does not support
- * RELRO sharing.
- */
- private static long computeRandomBaseLoadAddress() {
- // nativeGetRandomBaseLoadAddress() returns an address at which it has previously
- // successfully mapped an area of the given size, on the basis that we will be
- // able, with high probability, to map our library into it.
- //
- // One issue with this is that we do not yet know the size of the library that
- // we will load is. So here we pass a value that we expect will always be larger
- // than that needed. If it is smaller the library mapping may still succeed. The
- // other issue is that although highly unlikely, there is no guarantee that
- // something else does not map into the area we are going to use between here and
- // when we try to map into it.
- //
- // The above notes mean that all of this is probablistic. It is however okay to do
- // because if, worst case and unlikely, we get unlucky in our choice of address,
- // the back-out and retry without the shared RELRO in the ChildProcessService will
- // keep things running.
- final long maxExpectedBytes = 192 * 1024 * 1024;
- final long address = nativeGetRandomBaseLoadAddress(maxExpectedBytes);
- if (DEBUG) {
- Log.i(TAG, String.format(Locale.US, "Random native base load address: 0x%x", address));
- }
- return address;
- }
-
- // Used for debugging only.
- private static void dumpBundle(Bundle bundle) {
- if (DEBUG) Log.i(TAG, "Bundle has " + bundle.size() + " items: " + bundle);
- }
-
- /**
- * Use the shared RELRO section from a Bundle received form another process.
- * Call this after calling setBaseLoadAddress() then loading all libraries
- * with loadLibrary().
- * @param bundle Bundle instance generated with createSharedRelroBundle() in
- * another process.
- */
- private static void useSharedRelrosLocked(Bundle bundle) {
- assert Thread.holdsLock(Linker.class);
-
- if (DEBUG) Log.i(TAG, "Linker.useSharedRelrosLocked() called");
-
- if (bundle == null) {
- if (DEBUG) Log.i(TAG, "null bundle!");
- return;
- }
-
- if (!sRelroSharingSupported) {
- if (DEBUG) Log.i(TAG, "System does not support RELRO sharing");
- return;
- }
-
- if (sLoadedLibraries == null) {
- if (DEBUG) Log.i(TAG, "No libraries loaded!");
- return;
- }
-
- if (DEBUG) dumpBundle(bundle);
- HashMap<String, LibInfo> relroMap = createLibInfoMapFromBundle(bundle);
-
- // Apply the RELRO section to all libraries that were already loaded.
- for (Map.Entry<String, LibInfo> entry : relroMap.entrySet()) {
- String libName = entry.getKey();
- LibInfo libInfo = entry.getValue();
- if (!nativeUseSharedRelro(libName, libInfo)) {
- Log.w(TAG, "Could not use shared RELRO section for " + libName);
- } else {
- if (DEBUG) Log.i(TAG, "Using shared RELRO section for " + libName);
- }
- }
-
- // In service processes, close all file descriptors from the map now.
- if (!sInBrowserProcess) closeLibInfoMap(relroMap);
-
- if (DEBUG) Log.i(TAG, "Linker.useSharedRelrosLocked() exiting");
- }
-
- /**
- * Load a native shared library with the Chromium linker. If the zip file
- * is not null, the shared library must be uncompressed and page aligned
- * inside the zipfile. Note the crazy linker treats libraries and files as
- * equivalent, so you can only open one library in a given zip file. The
- * library must not be the Chromium linker library.
- *
- * @param zipFilePath The path of the zip file containing the library (or null).
- * @param libFilePath The path of the library (possibly in the zip file).
- */
- public static void loadLibrary(@Nullable String zipFilePath, String libFilePath) {
- if (DEBUG) Log.i(TAG, "loadLibrary: " + zipFilePath + ", " + libFilePath);
-
- synchronized (Linker.class) {
- ensureInitializedLocked();
-
- // Security: Ensure prepareLibraryLoad() was called before.
- // In theory, this can be done lazily here, but it's more consistent
- // to use a pair of functions (i.e. prepareLibraryLoad() + finishLibraryLoad())
- // that wrap all calls to loadLibrary() in the library loader.
- assert sPrepareLibraryLoadCalled;
-
- if (sLoadedLibraries == null) sLoadedLibraries = new HashMap<String, LibInfo>();
-
- if (sLoadedLibraries.containsKey(libFilePath)) {
- if (DEBUG) Log.i(TAG, "Not loading " + libFilePath + " twice");
- return;
- }
-
- LibInfo libInfo = new LibInfo();
- long loadAddress = 0;
- if ((sInBrowserProcess && sBrowserUsesSharedRelro) || sWaitForSharedRelros) {
- // Load the library at a fixed address.
- loadAddress = sCurrentLoadAddress;
- }
-
- String sharedRelRoName = libFilePath;
- if (zipFilePath != null) {
- if (!nativeLoadLibraryInZipFile(zipFilePath, libFilePath, loadAddress, libInfo)) {
- String errorMessage = "Unable to load library: " + libFilePath
- + ", in: " + zipFilePath;
- Log.e(TAG, errorMessage);
- throw new UnsatisfiedLinkError(errorMessage);
- }
- sharedRelRoName = zipFilePath;
- } else {
- if (!nativeLoadLibrary(libFilePath, loadAddress, libInfo)) {
- String errorMessage = "Unable to load library: " + libFilePath;
- Log.e(TAG, errorMessage);
- throw new UnsatisfiedLinkError(errorMessage);
- }
- }
-
- // Print the load address to the logcat when testing the linker. The format
- // of the string is expected by the Python test_runner script as one of:
- // BROWSER_LIBRARY_ADDRESS: <library-name> <address>
- // RENDERER_LIBRARY_ADDRESS: <library-name> <address>
- // Where <library-name> is the library name, and <address> is the hexadecimal load
- // address.
- if (NativeLibraries.sEnableLinkerTests) {
- Log.i(TAG, String.format(
- Locale.US,
- "%s_LIBRARY_ADDRESS: %s %x",
- sInBrowserProcess ? "BROWSER" : "RENDERER",
- libFilePath,
- libInfo.mLoadAddress));
- }
-
- if (sInBrowserProcess) {
- // Create a new shared RELRO section at the 'current' fixed load address.
- if (!nativeCreateSharedRelro(sharedRelRoName, sCurrentLoadAddress, libInfo)) {
- Log.w(TAG, String.format(Locale.US,
- "Could not create shared RELRO for %s at %x", libFilePath,
- sCurrentLoadAddress));
- } else {
- if (DEBUG) Log.i(TAG,
- String.format(
- Locale.US,
- "Created shared RELRO for %s at %x: %s",
- sharedRelRoName,
- sCurrentLoadAddress,
- libInfo.toString()));
- }
- }
-
- if (sCurrentLoadAddress != 0) {
- // Compute the next current load address. If sBaseLoadAddress
- // is not 0, this is an explicit library load address. Otherwise,
- // this is an explicit load address for relocated RELRO sections
- // only.
- sCurrentLoadAddress = libInfo.mLoadAddress + libInfo.mLoadSize;
- }
-
- sLoadedLibraries.put(sharedRelRoName, libInfo);
- if (DEBUG) Log.i(TAG, "Library details " + libInfo.toString());
- }
- }
-
- /**
- * Determine whether a library is the linker library. Also deal with the
- * component build that adds a .cr suffix to the name.
- */
- public static boolean isChromiumLinkerLibrary(String library) {
- return library.equals(TAG) || library.equals(TAG + ".cr");
- }
-
- /**
- * Get the full library path in zip file (lib/<abi>/crazy.<lib_name>).
- *
- * @param library The library's base name.
- * @return the library path.
- */
- public static String getLibraryFilePathInZipFile(String library) throws FileNotFoundException {
- synchronized (Linker.class) {
- ensureInitializedLocked();
-
- String path = nativeGetLibraryFilePathInZipFile(library);
- if (path.equals("")) {
- throw new FileNotFoundException(
- "Failed to retrieve path in zip file for library " + library);
- }
- return path;
- }
- }
-
- /**
- * Check whether a library is page aligned and uncompressed in the APK file.
- *
- * @param apkFile Filename of the APK.
- * @param library The library's base name.
- * @return true if page aligned and uncompressed.
- */
- public static boolean checkLibraryIsMappableInApk(String apkFile, String library) {
- synchronized (Linker.class) {
- ensureInitializedLocked();
-
- if (DEBUG) Log.i(TAG, "checkLibraryIsMappableInApk: " + apkFile + ", " + library);
- boolean aligned = nativeCheckLibraryIsMappableInApk(apkFile, library);
- if (DEBUG) Log.i(TAG, library + " is " + (aligned ? "" : "NOT ")
- + "page aligned in " + apkFile);
- return aligned;
- }
- }
-
- /**
- * Move activity from the native thread to the main UI thread.
- * Called from native code on its own thread. Posts a callback from
- * the UI thread back to native code.
- *
- * @param opaque Opaque argument.
- */
- @CalledByNative
- public static void postCallbackOnMainThread(final long opaque) {
- ThreadUtils.postOnUiThread(new Runnable() {
- @Override
- public void run() {
- nativeRunCallbackOnUiThread(opaque);
- }
- });
- }
-
- /**
- * Native method to run callbacks on the main UI thread.
- * Supplied by the crazy linker and called by postCallbackOnMainThread.
- * @param opaque Opaque crazy linker arguments.
- */
- private static native void nativeRunCallbackOnUiThread(long opaque);
-
- /**
- * Native method used to load a library.
- * @param library Platform specific library name (e.g. libfoo.so)
- * @param loadAddress Explicit load address, or 0 for randomized one.
- * @param libInfo If not null, the mLoadAddress and mLoadSize fields
- * of this LibInfo instance will set on success.
- * @return true for success, false otherwise.
- */
- private static native boolean nativeLoadLibrary(String library,
- long loadAddress,
- LibInfo libInfo);
-
- /**
- * Native method used to load a library which is inside a zipfile.
- * @param zipfileName Filename of the zip file containing the library.
- * @param library Platform specific library name (e.g. libfoo.so)
- * @param loadAddress Explicit load address, or 0 for randomized one.
- * @param libInfo If not null, the mLoadAddress and mLoadSize fields
- * of this LibInfo instance will set on success.
- * @return true for success, false otherwise.
- */
- private static native boolean nativeLoadLibraryInZipFile(String zipfileName,
- String libraryName,
- long loadAddress,
- LibInfo libInfo);
-
- /**
- * Native method used to create a shared RELRO section.
- * If the library was already loaded at the same address using
- * nativeLoadLibrary(), this creates the RELRO for it. Otherwise,
- * this loads a new temporary library at the specified address,
- * creates and extracts the RELRO section from it, then unloads it.
- * @param library Library name.
- * @param loadAddress load address, which can be different from the one
- * used to load the library in the current process!
- * @param libInfo libInfo instance. On success, the mRelroStart, mRelroSize
- * and mRelroFd will be set.
- * @return true on success, false otherwise.
- */
- private static native boolean nativeCreateSharedRelro(String library,
- long loadAddress,
- LibInfo libInfo);
-
- /**
- * Native method used to use a shared RELRO section.
- * @param library Library name.
- * @param libInfo A LibInfo instance containing valid RELRO information
- * @return true on success.
- */
- private static native boolean nativeUseSharedRelro(String library,
- LibInfo libInfo);
-
- /**
- * Checks that the system supports shared RELROs. Old Android kernels
- * have a bug in the way they check Ashmem region protection flags, which
- * makes using shared RELROs unsafe. This method performs a simple runtime
- * check for this misfeature, even though nativeEnableSharedRelro() will
- * always fail if this returns false.
- */
- private static native boolean nativeCanUseSharedRelro();
-
- /**
- * Return a random address that should be free to be mapped with the given size.
- * Maps an area of size bytes, and if successful then unmaps it and returns
- * the address of the area allocated by the system (with ASLR). The idea is
- * that this area should remain free of other mappings until we map our library
- * into it.
- * @param sizeBytes Size of area in bytes to search for.
- * @return address to pass to future mmap, or 0 on error.
- */
- private static native long nativeGetRandomBaseLoadAddress(long sizeBytes);
-
- /**
- * Native method used to get the full library path in zip file
- * (lib/<abi>/crazy.<lib_name>).
- *
- * @param library The library's base name.
- * @return the library path (or empty string on failure).
- */
- private static native String nativeGetLibraryFilePathInZipFile(String library);
-
- /**
- * Native method which checks whether a library is page aligned and
- * uncompressed in the APK file.
- *
- * @param apkFile Filename of the APK.
- * @param library The library's base name.
- * @return true if page aligned and uncompressed.
- */
- private static native boolean nativeCheckLibraryIsMappableInApk(String apkFile, String library);
-
- /**
- * Record information for a given library.
- * IMPORTANT: Native code knows about this class's fields, so
- * don't change them without modifying the corresponding C++ sources.
- * Also, the LibInfo instance owns the ashmem file descriptor.
- */
- public static class LibInfo implements Parcelable {
-
- public LibInfo() {
- mLoadAddress = 0;
- mLoadSize = 0;
- mRelroStart = 0;
- mRelroSize = 0;
- mRelroFd = -1;
- }
-
- public void close() {
- if (mRelroFd >= 0) {
- try {
- ParcelFileDescriptor.adoptFd(mRelroFd).close();
- } catch (java.io.IOException e) {
- if (DEBUG) Log.e(TAG, "Failed to close fd: " + mRelroFd);
- }
- mRelroFd = -1;
- }
- }
-
- // from Parcelable
- public LibInfo(Parcel in) {
- mLoadAddress = in.readLong();
- mLoadSize = in.readLong();
- mRelroStart = in.readLong();
- mRelroSize = in.readLong();
- ParcelFileDescriptor fd = ParcelFileDescriptor.CREATOR.createFromParcel(in);
- // If CreateSharedRelro fails, the OS file descriptor will be -1 and |fd| will be null.
- mRelroFd = (fd == null) ? -1 : fd.detachFd();
- }
-
- // from Parcelable
- @Override
- public void writeToParcel(Parcel out, int flags) {
- if (mRelroFd >= 0) {
- out.writeLong(mLoadAddress);
- out.writeLong(mLoadSize);
- out.writeLong(mRelroStart);
- out.writeLong(mRelroSize);
- try {
- ParcelFileDescriptor fd = ParcelFileDescriptor.fromFd(mRelroFd);
- fd.writeToParcel(out, 0);
- fd.close();
- } catch (java.io.IOException e) {
- Log.e(TAG, "Cant' write LibInfo file descriptor to parcel", e);
- }
- }
- }
-
- // from Parcelable
- @Override
- public int describeContents() {
- return Parcelable.CONTENTS_FILE_DESCRIPTOR;
- }
-
- // from Parcelable
- public static final Parcelable.Creator<LibInfo> CREATOR =
- new Parcelable.Creator<LibInfo>() {
- @Override
- public LibInfo createFromParcel(Parcel in) {
- return new LibInfo(in);
- }
-
- @Override
- public LibInfo[] newArray(int size) {
- return new LibInfo[size];
- }
- };
-
- @Override
- public String toString() {
- return String.format(Locale.US,
- "[load=0x%x-0x%x relro=0x%x-0x%x fd=%d]",
- mLoadAddress,
- mLoadAddress + mLoadSize,
- mRelroStart,
- mRelroStart + mRelroSize,
- mRelroFd);
- }
-
- // IMPORTANT: Don't change these fields without modifying the
- // native code that accesses them directly!
- @AccessedByNative
- public long mLoadAddress; // page-aligned library load address.
- @AccessedByNative
- public long mLoadSize; // page-aligned library load size.
- @AccessedByNative
- public long mRelroStart; // page-aligned address in memory, or 0 if none.
- @AccessedByNative
- public long mRelroSize; // page-aligned size in memory, or 0.
- @AccessedByNative
- public int mRelroFd; // ashmem file descriptor, or -1
- }
-
- // Create a Bundle from a map of LibInfo objects.
- private static Bundle createBundleFromLibInfoMap(HashMap<String, LibInfo> map) {
- Bundle bundle = new Bundle(map.size());
- for (Map.Entry<String, LibInfo> entry : map.entrySet()) {
- bundle.putParcelable(entry.getKey(), entry.getValue());
- }
-
- return bundle;
- }
-
- // Create a new LibInfo map from a Bundle.
- private static HashMap<String, LibInfo> createLibInfoMapFromBundle(Bundle bundle) {
- HashMap<String, LibInfo> map = new HashMap<String, LibInfo>();
- for (String library : bundle.keySet()) {
- LibInfo libInfo = bundle.getParcelable(library);
- map.put(library, libInfo);
- }
- return map;
- }
-
- // Call the close() method on all values of a LibInfo map.
- private static void closeLibInfoMap(HashMap<String, LibInfo> map) {
- for (Map.Entry<String, LibInfo> entry : map.entrySet()) {
- entry.getValue().close();
- }
- }
-
- // The map of libraries that are currently loaded in this process.
- private static HashMap<String, LibInfo> sLoadedLibraries = null;
-
- // Used to pass the shared RELRO Bundle through Binder.
- public static final String EXTRA_LINKER_SHARED_RELROS =
- "org.chromium.base.android.linker.shared_relros";
-}
diff --git a/base/android/java/src/org/chromium/base/library_loader/LoaderErrors.java b/base/android/java/src/org/chromium/base/library_loader/LoaderErrors.java
deleted file mode 100644
index 2b94370bd8..0000000000
--- a/base/android/java/src/org/chromium/base/library_loader/LoaderErrors.java
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2014 The Chromium 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.library_loader;
-
-/**
- * These are the possible failures from the LibraryLoader
- */
-public class LoaderErrors {
- public static final int LOADER_ERROR_NORMAL_COMPLETION = 0;
- public static final int LOADER_ERROR_FAILED_TO_REGISTER_JNI = 1;
- public static final int LOADER_ERROR_NATIVE_LIBRARY_LOAD_FAILED = 2;
- public static final int LOADER_ERROR_NATIVE_LIBRARY_WRONG_VERSION = 3;
- public static final int LOADER_ERROR_NATIVE_STARTUP_FAILED = 4;
-}
diff --git a/base/android/java/src/org/chromium/base/library_loader/ProcessInitException.java b/base/android/java/src/org/chromium/base/library_loader/ProcessInitException.java
deleted file mode 100644
index 106667536d..0000000000
--- a/base/android/java/src/org/chromium/base/library_loader/ProcessInitException.java
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2014 The Chromium 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.library_loader;
-
-/**
- * The exception that is thrown when the intialization of a process was failed.
- */
-public class ProcessInitException extends Exception {
- private int mErrorCode = LoaderErrors.LOADER_ERROR_NORMAL_COMPLETION;
-
- /**
- * @param errorCode This will be one of the LoaderErrors error codes.
- */
- public ProcessInitException(int errorCode) {
- mErrorCode = errorCode;
- }
-
- /**
- * @param errorCode This will be one of the LoaderErrors error codes.
- * @param throwable The wrapped throwable obj.
- */
- public ProcessInitException(int errorCode, Throwable throwable) {
- super(null, throwable);
- mErrorCode = errorCode;
- }
-
- /**
- * Return the error code.
- */
- public int getErrorCode() {
- return mErrorCode;
- }
-}
diff --git a/base/android/java/src/org/chromium/base/metrics/RecordHistogram.java b/base/android/java/src/org/chromium/base/metrics/RecordHistogram.java
deleted file mode 100644
index 2f4356be64..0000000000
--- a/base/android/java/src/org/chromium/base/metrics/RecordHistogram.java
+++ /dev/null
@@ -1,177 +0,0 @@
-// Copyright 2014 The Chromium 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.metrics;
-
-import org.chromium.base.JNINamespace;
-import org.chromium.base.VisibleForTesting;
-
-import java.util.concurrent.TimeUnit;
-
-/**
- * Java API for recording UMA histograms. Internally, the histogram will be cached by
- * System.identityHashCode(name).
- *
- * Note: the JNI calls are relatively costly - avoid calling these methods in performance-critical
- * code.
- */
-@JNINamespace("base::android")
-public class RecordHistogram {
- /**
- * Records a sample in a boolean UMA histogram of the given name. Boolean histogram has two
- * buckets, corresponding to success (true) and failure (false). This is the Java equivalent of
- * the UMA_HISTOGRAM_BOOLEAN C++ macro.
- * @param name name of the histogram
- * @param sample sample to be recorded, either true or false
- */
- public static void recordBooleanHistogram(String name, boolean sample) {
- nativeRecordBooleanHistogram(name, System.identityHashCode(name), sample);
- }
-
- /**
- * Records a sample in an enumerated histogram of the given name and boundary. Note that
- * |boundary| identifies the histogram - it should be the same at every invocation. This is the
- * Java equivalent of the UMA_HISTOGRAM_ENUMERATION C++ macro.
- * @param name name of the histogram
- * @param sample sample to be recorded, at least 0 and at most |boundary| - 1
- * @param boundary upper bound for legal sample values - all sample values have to be strictly
- * lower than |boundary|
- */
- public static void recordEnumeratedHistogram(String name, int sample, int boundary) {
- nativeRecordEnumeratedHistogram(name, System.identityHashCode(name), sample, boundary);
- }
-
- /**
- * Records a sample in a count histogram. This is the Java equivalent of the
- * UMA_HISTOGRAM_COUNTS C++ macro.
- * @param name name of the histogram
- * @param sample sample to be recorded, at least 1 and at most 999999
- */
- public static void recordCountHistogram(String name, int sample) {
- recordCustomCountHistogram(name, sample, 1, 1000000, 50);
- }
-
- /**
- * Records a sample in a count histogram. This is the Java equivalent of the
- * UMA_HISTOGRAM_COUNTS_100 C++ macro.
- * @param name name of the histogram
- * @param sample sample to be recorded, at least 1 and at most 99
- */
- public static void recordCount100Histogram(String name, int sample) {
- recordCustomCountHistogram(name, sample, 1, 100, 50);
- }
-
- /**
- * Records a sample in a count histogram. This is the Java equivalent of the
- * UMA_HISTOGRAM_CUSTOM_COUNTS C++ macro.
- * @param name name of the histogram
- * @param sample sample to be recorded, at least |min| and at most |max| - 1
- * @param min lower bound for expected sample values
- * @param max upper bounds for expected sample values
- * @param numBuckets the number of buckets
- */
- public static void recordCustomCountHistogram(
- String name, int sample, int min, int max, int numBuckets) {
- nativeRecordCustomCountHistogram(
- name, System.identityHashCode(name), sample, min, max, numBuckets);
- }
-
- /**
- * Records a sparse histogram. This is the Java equivalent of UMA_HISTOGRAM_SPARSE_SLOWLY.
- * @param name name of the histogram
- * @param sample sample to be recorded. All values of |sample| are valid, including negative
- * values.
- */
- public static void recordSparseSlowlyHistogram(String name, int sample) {
- nativeRecordSparseHistogram(name, System.identityHashCode(name), sample);
- }
-
- /**
- * Records a sample in a histogram of times. Useful for recording short durations. This is the
- * Java equivalent of the UMA_HISTOGRAM_TIMES C++ macro.
- * @param name name of the histogram
- * @param duration duration to be recorded
- * @param timeUnit the unit of the duration argument
- */
- public static void recordTimesHistogram(String name, long duration, TimeUnit timeUnit) {
- recordCustomTimesHistogramMilliseconds(
- name, timeUnit.toMillis(duration), 1, TimeUnit.SECONDS.toMillis(10), 50);
- }
-
- /**
- * Records a sample in a histogram of times. Useful for recording medium durations. This is the
- * Java equivalent of the UMA_HISTOGRAM_MEDIUM_TIMES C++ macro.
- * @param name name of the histogram
- * @param duration duration to be recorded
- * @param timeUnit the unit of the duration argument
- */
- public static void recordMediumTimesHistogram(String name, long duration, TimeUnit timeUnit) {
- recordCustomTimesHistogramMilliseconds(
- name, timeUnit.toMillis(duration), 10, TimeUnit.MINUTES.toMillis(3), 50);
- }
-
- /**
- * Records a sample in a histogram of times. Useful for recording long durations. This is the
- * Java equivalent of the UMA_HISTOGRAM_LONG_TIMES C++ macro.
- * @param name name of the histogram
- * @param duration duration to be recorded
- * @param timeUnit the unit of the duration argument
- */
- public static void recordLongTimesHistogram(String name, long duration, TimeUnit timeUnit) {
- recordCustomTimesHistogramMilliseconds(
- name, timeUnit.toMillis(duration), 1, TimeUnit.HOURS.toMillis(1), 50);
- }
-
- /**
- * Records a sample in a histogram of times with custom buckets. This is the Java equivalent of
- * the UMA_HISTOGRAM_CUSTOM_TIMES C++ macro.
- * @param name name of the histogram
- * @param duration duration to be recorded
- * @param min the minimum bucket value
- * @param max the maximum bucket value
- * @param timeUnit the unit of the duration, min, and max arguments
- * @param numBuckets the number of buckets
- */
- public static void recordCustomTimesHistogram(
- String name, long duration, long min, long max, TimeUnit timeUnit, int numBuckets) {
- recordCustomTimesHistogramMilliseconds(name, timeUnit.toMillis(duration),
- timeUnit.toMillis(min), timeUnit.toMillis(max), numBuckets);
- }
-
- private static void recordCustomTimesHistogramMilliseconds(
- String name, long duration, long min, long max, int numBuckets) {
- nativeRecordCustomTimesHistogramMilliseconds(
- name, System.identityHashCode(name), duration, min, max, numBuckets);
- }
-
- /**
- * Returns the number of samples recorded in the given bucket of the given histogram.
- * @param name name of the histogram to look up
- * @param sample the bucket containing this sample value will be looked up
- */
- @VisibleForTesting
- public static int getHistogramValueCountForTesting(String name, int sample) {
- return nativeGetHistogramValueCountForTesting(name, sample);
- }
-
- /**
- * Initializes the metrics system.
- */
- public static void initialize() {
- nativeInitialize();
- }
-
- private static native void nativeRecordCustomTimesHistogramMilliseconds(
- String name, int key, long duration, long min, long max, int numBuckets);
-
- private static native void nativeRecordBooleanHistogram(String name, int key, boolean sample);
- private static native void nativeRecordEnumeratedHistogram(
- String name, int key, int sample, int boundary);
- private static native void nativeRecordCustomCountHistogram(
- String name, int key, int sample, int min, int max, int numBuckets);
- private static native void nativeRecordSparseHistogram(String name, int key, int sample);
-
- private static native int nativeGetHistogramValueCountForTesting(String name, int sample);
- private static native void nativeInitialize();
-}
diff --git a/base/android/java/src/org/chromium/base/metrics/RecordUserAction.java b/base/android/java/src/org/chromium/base/metrics/RecordUserAction.java
deleted file mode 100644
index d7cc32c2b2..0000000000
--- a/base/android/java/src/org/chromium/base/metrics/RecordUserAction.java
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2015 The Chromium 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.metrics;
-
-import org.chromium.base.JNINamespace;
-import org.chromium.base.ThreadUtils;
-
-/**
- * Java API for recording UMA actions.
- *
- * WARNINGS:
- * JNI calls are relatively costly - avoid using in performance-critical code.
- *
- * We use a script (extract_actions.py) to scan the source code and extract actions. A string
- * literal (not a variable) must be passed to record().
- */
-@JNINamespace("base::android")
-public class RecordUserAction {
- public static void record(final String action) {
- if (ThreadUtils.runningOnUiThread()) {
- nativeRecordUserAction(action);
- return;
- }
-
- ThreadUtils.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- nativeRecordUserAction(action);
- }
- });
- }
-
- private static native void nativeRecordUserAction(String action);
-}
diff --git a/base/android/java/templates/NativeLibraries.template b/base/android/java/templates/NativeLibraries.template
deleted file mode 100644
index 8b812a60a9..0000000000
--- a/base/android/java/templates/NativeLibraries.template
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright 2014 The Chromium 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.library_loader;
-
-import org.chromium.base.annotations.SuppressFBWarnings;
-
-@SuppressFBWarnings
-public class NativeLibraries {
- /**
- * IMPORTANT NOTE: The variables defined here must _not_ be 'final'.
- *
- * The reason for this is very subtle:
- *
- * - This template is used to generate several distinct, but similar
- * files used in different contexts:
- *
- * o .../gen/templates/org/chromium/base/library_loader/NativeLibraries.java
- *
- * This file is used to build base.jar, which is the library
- * jar used by chromium projects. However, the
- * corresponding NativeLibraries.class file will _not_ be part
- * of the final base.jar.
- *
- * o .../$PROJECT/native_libraries_java/NativeLibraries.java
- *
- * This file is used to build an APK (e.g. $PROJECT
- * could be 'content_shell_apk'). Its content will depend on
- * this target's specific build configuration, and differ from
- * the source file above.
- *
- * - During the final link, all .jar files are linked together into
- * a single .dex file, and the second version of NativeLibraries.class
- * will be put into the final output file, and used at runtime.
- *
- * - If the variables were defined as 'final', their value would be
- * optimized out inside of 'base.jar', and could not be specialized
- * for every chromium program. This, however, doesn't apply to arrays of
- * strings, which can be defined as final.
- *
- * This exotic scheme is used to avoid injecting project-specific, or
- * even build-specific, values into the base layer. E.g. this is
- * how the component build is supported on Android without modifying
- * the sources of each and every Chromium-based target.
- */
-
-#if defined(ENABLE_CHROMIUM_LINKER_LIBRARY_IN_ZIP_FILE) && \
- !defined(ENABLE_CHROMIUM_LINKER)
-#error "Must have ENABLE_CHROMIUM_LINKER to enable library in zip file"
-#endif
-
- // Set to true to enable the use of the Chromium Linker.
-#if defined(ENABLE_CHROMIUM_LINKER)
- public static boolean sUseLinker = true;
-#else
- public static boolean sUseLinker = false;
-#endif
-
-#if defined(ENABLE_CHROMIUM_LINKER_LIBRARY_IN_ZIP_FILE)
- public static boolean sUseLibraryInZipFile = true;
-#else
- public static boolean sUseLibraryInZipFile = false;
-#endif
-
-#if defined(ENABLE_CHROMIUM_LINKER_TESTS)
- public static boolean sEnableLinkerTests = true;
-#else
- public static boolean sEnableLinkerTests = false;
-#endif
-
- // This is the list of native libraries to be loaded (in the correct order)
- // by LibraryLoader.java. The base java library is compiled with no
- // array defined, and then the build system creates a version of the file
- // with the real list of libraries required (which changes based upon which
- // .apk is being built).
- // TODO(cjhopman): This is public since it is referenced by NativeTestActivity.java
- // directly. The two ways of library loading should be refactored into one.
- public static final String[] LIBRARIES =
-#if defined(NATIVE_LIBRARIES_LIST)
- NATIVE_LIBRARIES_LIST;
-#else
- {};
-#endif
-
- // This is the expected version of the 'main' native library, which is the one that
- // implements the initial set of base JNI functions including
- // base::android::nativeGetVersionName()
- static String sVersionNumber =
-#if defined(NATIVE_LIBRARIES_VERSION_NUMBER)
- NATIVE_LIBRARIES_VERSION_NUMBER;
-#else
- "";
-#endif
-}
diff --git a/base/android/javatests/src/org/chromium/base/AdvancedMockContextTest.java b/base/android/javatests/src/org/chromium/base/AdvancedMockContextTest.java
deleted file mode 100644
index d7c103b95b..0000000000
--- a/base/android/javatests/src/org/chromium/base/AdvancedMockContextTest.java
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2014 The Chromium 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.Application;
-import android.content.ComponentCallbacks;
-import android.content.ComponentCallbacks2;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.test.InstrumentationTestCase;
-
-import org.chromium.base.test.util.AdvancedMockContext;
-
-/**
- * Tests for {@link org.chromium.base.test.util.AdvancedMockContext}.
- */
-public class AdvancedMockContextTest extends InstrumentationTestCase {
- private static class Callback1 implements ComponentCallbacks {
- protected Configuration mConfiguration;
- protected boolean mOnLowMemoryCalled;
-
- @Override
- public void onConfigurationChanged(Configuration configuration) {
- mConfiguration = configuration;
- }
-
- @Override
- public void onLowMemory() {
- mOnLowMemoryCalled = true;
- }
- }
-
- private static class Callback2 extends Callback1 implements ComponentCallbacks2 {
- private int mLevel;
-
- @Override
- public void onTrimMemory(int level) {
- mLevel = level;
- }
- }
-
- public void testComponentCallbacksForTargetContext() {
- Context targetContext = getInstrumentation().getTargetContext();
- Application targetApplication = (Application) targetContext.getApplicationContext();
- AdvancedMockContext context = new AdvancedMockContext(targetContext);
- Callback1 callback1 = new Callback1();
- Callback2 callback2 = new Callback2();
- context.registerComponentCallbacks(callback1);
- context.registerComponentCallbacks(callback2);
-
- targetApplication.onLowMemory();
- assertTrue("onLowMemory should have been called.", callback1.mOnLowMemoryCalled);
- assertTrue("onLowMemory should have been called.", callback2.mOnLowMemoryCalled);
-
- Configuration configuration = new Configuration();
- targetApplication.onConfigurationChanged(configuration);
- assertEquals("onConfigurationChanged should have been called.", configuration,
- callback1.mConfiguration);
- assertEquals("onConfigurationChanged should have been called.", configuration,
- callback2.mConfiguration);
-
- targetApplication.onTrimMemory(ComponentCallbacks2.TRIM_MEMORY_MODERATE);
- assertEquals("onTrimMemory should have been called.", ComponentCallbacks2
- .TRIM_MEMORY_MODERATE, callback2.mLevel);
- }
-}
diff --git a/base/android/javatests/src/org/chromium/base/ApiCompatibilityUtilsTest.java b/base/android/javatests/src/org/chromium/base/ApiCompatibilityUtilsTest.java
deleted file mode 100644
index 45b3e21150..0000000000
--- a/base/android/javatests/src/org/chromium/base/ApiCompatibilityUtilsTest.java
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright 2015 The Chromium 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.annotation.TargetApi;
-import android.app.Activity;
-import android.os.Build;
-import android.os.SystemClock;
-import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-
-/**
- * Test of ApiCompatibilityUtils
- */
-public class ApiCompatibilityUtilsTest extends InstrumentationTestCase {
- private static final long WAIT_TIMEOUT_IN_MS = 5000;
- private static final long SLEEP_INTERVAL_IN_MS = 50;
-
- static class MockActivity extends Activity {
- int mFinishAndRemoveTaskCallbackCount;
- int mFinishCallbackCount;
- boolean mIsFinishing;
-
- @TargetApi(Build.VERSION_CODES.LOLLIPOP)
- @Override
- public void finishAndRemoveTask() {
- mFinishAndRemoveTaskCallbackCount++;
- if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) mIsFinishing = true;
- }
-
- @Override
- public void finish() {
- mFinishCallbackCount++;
- mIsFinishing = true;
- }
-
- @Override
- public boolean isFinishing() {
- return mIsFinishing;
- }
- }
-
- @SmallTest
- public void testFinishAndRemoveTask() throws InterruptedException {
- MockActivity activity = new MockActivity();
- ApiCompatibilityUtils.finishAndRemoveTask(activity);
-
- if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
- assertEquals(1, activity.mFinishAndRemoveTaskCallbackCount);
- assertEquals(0, activity.mFinishCallbackCount);
- } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP) {
- long startTime = SystemClock.uptimeMillis();
- while (activity.mFinishCallbackCount == 0
- && SystemClock.uptimeMillis() - startTime < WAIT_TIMEOUT_IN_MS) {
- Thread.sleep(SLEEP_INTERVAL_IN_MS);
- }
-
- // MockActivity#finishAndRemoveTask() never sets isFinishing() to true for LOLLIPOP to
- // simulate an exceptional case. In that case, MockActivity#finish() should be called
- // after 3 tries.
- assertEquals(3, activity.mFinishAndRemoveTaskCallbackCount);
- assertEquals(1, activity.mFinishCallbackCount);
- } else {
- assertEquals(0, activity.mFinishAndRemoveTaskCallbackCount);
- assertEquals(1, activity.mFinishCallbackCount);
- }
- assertTrue(activity.mIsFinishing);
- }
-}
diff --git a/base/android/javatests/src/org/chromium/base/CommandLineTest.java b/base/android/javatests/src/org/chromium/base/CommandLineTest.java
deleted file mode 100644
index 2b1a967556..0000000000
--- a/base/android/javatests/src/org/chromium/base/CommandLineTest.java
+++ /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.
-
-package org.chromium.base;
-
-import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import org.chromium.base.test.util.Feature;
-
-public class CommandLineTest extends InstrumentationTestCase {
- // A reference command line. Note that switch2 is [brea\d], switch3 is [and "butter"],
- // and switch4 is [a "quoted" 'food'!]
- static final String INIT_SWITCHES[] = { "init_command", "--SWITCH", "Arg",
- "--switch2=brea\\d", "--switch3=and \"butter\"",
- "--switch4=a \"quoted\" 'food'!",
- "--", "--actually_an_arg" };
-
- // The same command line, but in quoted string format.
- static final char INIT_SWITCHES_BUFFER[] =
- ("init_command --SWITCH Arg --switch2=brea\\d --switch3=\"and \\\"butt\"er\\\" "
- + "--switch4='a \"quoted\" \\'food\\'!' "
- + "-- --actually_an_arg").toCharArray();
-
- static final String CL_ADDED_SWITCH = "zappo-dappo-doggy-trainer";
- static final String CL_ADDED_SWITCH_2 = "username";
- static final String CL_ADDED_VALUE_2 = "bozo";
-
- @Override
- public void setUp() throws Exception {
- CommandLine.reset();
- }
-
- void checkInitSwitches() {
- CommandLine cl = CommandLine.getInstance();
- assertFalse(cl.hasSwitch("init_command"));
- assertFalse(cl.hasSwitch("switch"));
- assertTrue(cl.hasSwitch("SWITCH"));
- assertFalse(cl.hasSwitch("--SWITCH"));
- assertFalse(cl.hasSwitch("Arg"));
- assertFalse(cl.hasSwitch("actually_an_arg"));
- assertEquals("brea\\d", cl.getSwitchValue("switch2"));
- assertEquals("and \"butter\"", cl.getSwitchValue("switch3"));
- assertEquals("a \"quoted\" 'food'!", cl.getSwitchValue("switch4"));
- assertNull(cl.getSwitchValue("SWITCH"));
- assertNull(cl.getSwitchValue("non-existant"));
- }
-
- void checkSettingThenGetting() {
- CommandLine cl = CommandLine.getInstance();
-
- // Add a plain switch.
- assertFalse(cl.hasSwitch(CL_ADDED_SWITCH));
- cl.appendSwitch(CL_ADDED_SWITCH);
- assertTrue(cl.hasSwitch(CL_ADDED_SWITCH));
-
- // Add a switch paired with a value.
- assertFalse(cl.hasSwitch(CL_ADDED_SWITCH_2));
- assertNull(cl.getSwitchValue(CL_ADDED_SWITCH_2));
- cl.appendSwitchWithValue(CL_ADDED_SWITCH_2, CL_ADDED_VALUE_2);
- assertTrue(CL_ADDED_VALUE_2.equals(cl.getSwitchValue(CL_ADDED_SWITCH_2)));
-
- // Append a few new things.
- final String switchesAndArgs[] = { "dummy", "--superfast", "--speed=turbo" };
- assertFalse(cl.hasSwitch("dummy"));
- assertFalse(cl.hasSwitch("superfast"));
- assertNull(cl.getSwitchValue("speed"));
- cl.appendSwitchesAndArguments(switchesAndArgs);
- assertFalse(cl.hasSwitch("dummy"));
- assertFalse(cl.hasSwitch("command"));
- assertTrue(cl.hasSwitch("superfast"));
- assertTrue("turbo".equals(cl.getSwitchValue("speed")));
- }
-
- void checkTokenizer(String[] expected, String toParse) {
- String[] actual = CommandLine.tokenizeQuotedAruments(toParse.toCharArray());
- assertEquals(expected.length, actual.length);
- for (int i = 0; i < expected.length; ++i) {
- assertEquals("comparing element " + i, expected[i], actual[i]);
- }
- }
-
- @SmallTest
- @Feature({"Android-AppBase"})
- public void testJavaInitialization() {
- CommandLine.init(INIT_SWITCHES);
- checkInitSwitches();
- checkSettingThenGetting();
- }
-
- @SmallTest
- @Feature({"Android-AppBase"})
- public void testBufferInitialization() {
- CommandLine.init(CommandLine.tokenizeQuotedAruments(INIT_SWITCHES_BUFFER));
- checkInitSwitches();
- checkSettingThenGetting();
- }
-
- @SmallTest
- @Feature({"Android-AppBase"})
- public void testArgumentTokenizer() {
- String toParse = " a\"\\bc de\\\"f g\"\\h ij k\" \"lm";
- String[] expected = { "a\\bc de\"f g\\h",
- "ij",
- "k lm" };
- checkTokenizer(expected, toParse);
-
- toParse = "";
- expected = new String[0];
- checkTokenizer(expected, toParse);
-
- toParse = " \t\n";
- checkTokenizer(expected, toParse);
-
- toParse = " \"a'b\" 'c\"d' \"e\\\"f\" 'g\\'h' \"i\\'j\" 'k\\\"l'"
- + " m\"n\\'o\"p q'r\\\"s't";
- expected = new String[] { "a'b",
- "c\"d",
- "e\"f",
- "g'h",
- "i\\'j",
- "k\\\"l",
- "mn\\'op",
- "qr\\\"st"};
- checkTokenizer(expected, toParse);
- }
-}
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 973682b932..0000000000
--- a/base/android/javatests/src/org/chromium/base/ObserverListTest.java
+++ /dev/null
@@ -1,326 +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.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<Observer> mList;
- private final Observer mLucky;
-
- FooAdder(ObserverList<Observer> 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<Observer> mList;
- private final Observer mDoomed;
-
- FooRemover(ObserverList<Observer> list, Observer innocent) {
- mList = list;
- mDoomed = innocent;
- }
-
- @Override
- public void observe(int x) {
- mList.removeObserver(mDoomed);
- }
- }
-
- private static <T> int getSizeOfIterable(Iterable<T> iterable) {
- int num = 0;
- for (T el : iterable) num++;
- return num;
- }
-
- @SmallTest
- @Feature({"Android-AppBase"})
- public void testRemoveWhileIteration() {
- ObserverList<Observer> observerList = new ObserverList<Observer>();
- 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<Observer> observerList = new ObserverList<Observer>();
- 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<Integer> observerList = new ObserverList<Integer>();
- observerList.addObserver(5);
- observerList.addObserver(10);
- observerList.addObserver(15);
- assertEquals(3, getSizeOfIterable(observerList));
-
- observerList.removeObserver(10);
- assertEquals(2, getSizeOfIterable(observerList));
-
- Iterator<Integer> 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);
- }
-
- @SmallTest
- @Feature({"Android-AppBase"})
- public void testRewindableIterator() {
- ObserverList<Integer> observerList = new ObserverList<Integer>();
- observerList.addObserver(5);
- observerList.addObserver(10);
- observerList.addObserver(15);
- assertEquals(3, getSizeOfIterable(observerList));
-
- ObserverList.RewindableIterator<Integer> it = observerList.rewindableIterator();
- assertTrue(it.hasNext());
- assertTrue(5 == it.next());
- assertTrue(it.hasNext());
- assertTrue(10 == it.next());
- assertTrue(it.hasNext());
- assertTrue(15 == it.next());
- assertFalse(it.hasNext());
-
- it.rewind();
-
- assertTrue(it.hasNext());
- assertTrue(5 == it.next());
- assertTrue(it.hasNext());
- assertTrue(10 == it.next());
- assertTrue(it.hasNext());
- assertTrue(15 == it.next());
- assertEquals(5, (int) observerList.mObservers.get(0));
- observerList.removeObserver(5);
- assertEquals(null, observerList.mObservers.get(0));
-
- it.rewind();
-
- assertEquals(10, (int) observerList.mObservers.get(0));
- assertTrue(it.hasNext());
- assertTrue(10 == it.next());
- assertTrue(it.hasNext());
- assertTrue(15 == it.next());
- }
-
- @SmallTest
- @Feature({"Android-AppBase"})
- public void testAddObserverReturnValue() {
- ObserverList<Object> observerList = new ObserverList<Object>();
-
- Object a = new Object();
- assertTrue(observerList.addObserver(a));
- assertFalse(observerList.addObserver(a));
-
- Object b = new Object();
- assertTrue(observerList.addObserver(b));
- assertFalse(observerList.addObserver(null));
- }
-
- @SmallTest
- @Feature({"Android-AppBase"})
- public void testRemoveObserverReturnValue() {
- ObserverList<Object> observerList = new ObserverList<Object>();
-
- Object a = new Object();
- Object b = new Object();
- observerList.addObserver(a);
- observerList.addObserver(b);
-
- assertTrue(observerList.removeObserver(a));
- assertFalse(observerList.removeObserver(a));
- assertFalse(observerList.removeObserver(new Object()));
- assertTrue(observerList.removeObserver(b));
- assertFalse(observerList.removeObserver(null));
-
- // If we remove an object while iterating, it will be replaced by 'null'.
- observerList.addObserver(a);
- assertTrue(observerList.removeObserver(a));
- assertFalse(observerList.removeObserver(null));
- }
-
- @SmallTest
- @Feature({"Android-AppBase"})
- public void testSize() {
- ObserverList<Object> observerList = new ObserverList<Object>();
-
- assertEquals(0, observerList.size());
- assertTrue(observerList.isEmpty());
-
- observerList.addObserver(null);
- assertEquals(0, observerList.size());
- assertTrue(observerList.isEmpty());
-
- Object a = new Object();
- observerList.addObserver(a);
- assertEquals(1, observerList.size());
- assertFalse(observerList.isEmpty());
-
- observerList.addObserver(a);
- assertEquals(1, observerList.size());
- assertFalse(observerList.isEmpty());
-
- observerList.addObserver(null);
- assertEquals(1, observerList.size());
- assertFalse(observerList.isEmpty());
-
- Object b = new Object();
- observerList.addObserver(b);
- assertEquals(2, observerList.size());
- assertFalse(observerList.isEmpty());
-
- observerList.removeObserver(null);
- assertEquals(2, observerList.size());
- assertFalse(observerList.isEmpty());
-
- observerList.removeObserver(new Object());
- assertEquals(2, observerList.size());
- assertFalse(observerList.isEmpty());
-
- observerList.removeObserver(b);
- assertEquals(1, observerList.size());
- assertFalse(observerList.isEmpty());
-
- observerList.removeObserver(b);
- assertEquals(1, observerList.size());
- assertFalse(observerList.isEmpty());
-
- observerList.removeObserver(a);
- assertEquals(0, observerList.size());
- assertTrue(observerList.isEmpty());
-
- observerList.removeObserver(a);
- observerList.removeObserver(b);
- observerList.removeObserver(null);
- observerList.removeObserver(new Object());
- assertEquals(0, observerList.size());
- assertTrue(observerList.isEmpty());
-
- observerList.addObserver(new Object());
- observerList.addObserver(new Object());
- observerList.addObserver(new Object());
- observerList.addObserver(a);
- assertEquals(4, observerList.size());
- assertFalse(observerList.isEmpty());
-
- observerList.clear();
- assertEquals(0, observerList.size());
- assertTrue(observerList.isEmpty());
-
- observerList.removeObserver(a);
- observerList.removeObserver(b);
- observerList.removeObserver(null);
- observerList.removeObserver(new Object());
- assertEquals(0, observerList.size());
- assertTrue(observerList.isEmpty());
- }
-}
diff --git a/base/android/javatests/src/org/chromium/base/metrics/RecordHistogramTest.java b/base/android/javatests/src/org/chromium/base/metrics/RecordHistogramTest.java
deleted file mode 100644
index 24af056f1c..0000000000
--- a/base/android/javatests/src/org/chromium/base/metrics/RecordHistogramTest.java
+++ /dev/null
@@ -1,159 +0,0 @@
-// Copyright 2014 The Chromium 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.metrics;
-
-import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import org.chromium.base.library_loader.LibraryLoader;
-import org.chromium.base.library_loader.LibraryProcessType;
-import org.chromium.base.test.util.MetricsUtils.HistogramDelta;
-
-import java.util.concurrent.TimeUnit;
-
-/**
- * Tests for the Java API for recording UMA histograms.
- */
-public class RecordHistogramTest extends InstrumentationTestCase {
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- LibraryLoader.get(LibraryProcessType.PROCESS_BROWSER).ensureInitialized();
- RecordHistogram.initialize();
- }
-
- /**
- * Tests recording of boolean histograms.
- */
- @SmallTest
- public void testRecordBooleanHistogram() {
- String histogram = "HelloWorld.BooleanMetric";
- HistogramDelta falseCount = new HistogramDelta(histogram, 0);
- HistogramDelta trueCount = new HistogramDelta(histogram, 1);
- assertEquals(0, trueCount.getDelta());
- assertEquals(0, falseCount.getDelta());
-
- RecordHistogram.recordBooleanHistogram(histogram, true);
- assertEquals(1, trueCount.getDelta());
- assertEquals(0, falseCount.getDelta());
-
- RecordHistogram.recordBooleanHistogram(histogram, true);
- assertEquals(2, trueCount.getDelta());
- assertEquals(0, falseCount.getDelta());
-
- RecordHistogram.recordBooleanHistogram(histogram, false);
- assertEquals(2, trueCount.getDelta());
- assertEquals(1, falseCount.getDelta());
- }
-
- /**
- * Tests recording of enumerated histograms.
- */
- @SmallTest
- public void testRecordEnumeratedHistogram() {
- String histogram = "HelloWorld.EnumeratedMetric";
- HistogramDelta zeroCount = new HistogramDelta(histogram, 0);
- HistogramDelta oneCount = new HistogramDelta(histogram, 1);
- HistogramDelta twoCount = new HistogramDelta(histogram, 2);
- final int boundary = 3;
-
- assertEquals(0, zeroCount.getDelta());
- assertEquals(0, oneCount.getDelta());
- assertEquals(0, twoCount.getDelta());
-
- RecordHistogram.recordEnumeratedHistogram(histogram, 0, boundary);
- assertEquals(1, zeroCount.getDelta());
- assertEquals(0, oneCount.getDelta());
- assertEquals(0, twoCount.getDelta());
-
- RecordHistogram.recordEnumeratedHistogram(histogram, 0, boundary);
- assertEquals(2, zeroCount.getDelta());
- assertEquals(0, oneCount.getDelta());
- assertEquals(0, twoCount.getDelta());
-
- RecordHistogram.recordEnumeratedHistogram(histogram, 2, boundary);
- assertEquals(2, zeroCount.getDelta());
- assertEquals(0, oneCount.getDelta());
- assertEquals(1, twoCount.getDelta());
- }
-
- /**
- * Tests recording of count histograms.
- */
- @SmallTest
- public void testRecordCountHistogram() {
- String histogram = "HelloWorld.CountMetric";
- HistogramDelta zeroCount = new HistogramDelta(histogram, 0);
- HistogramDelta oneCount = new HistogramDelta(histogram, 1);
- HistogramDelta twoCount = new HistogramDelta(histogram, 2);
- HistogramDelta eightThousandCount = new HistogramDelta(histogram, 8000);
-
- assertEquals(0, zeroCount.getDelta());
- assertEquals(0, oneCount.getDelta());
- assertEquals(0, twoCount.getDelta());
- assertEquals(0, eightThousandCount.getDelta());
-
- RecordHistogram.recordCountHistogram(histogram, 0);
- assertEquals(1, zeroCount.getDelta());
- assertEquals(0, oneCount.getDelta());
- assertEquals(0, twoCount.getDelta());
- assertEquals(0, eightThousandCount.getDelta());
-
- RecordHistogram.recordCountHistogram(histogram, 0);
- assertEquals(2, zeroCount.getDelta());
- assertEquals(0, oneCount.getDelta());
- assertEquals(0, twoCount.getDelta());
- assertEquals(0, eightThousandCount.getDelta());
-
- RecordHistogram.recordCountHistogram(histogram, 2);
- assertEquals(2, zeroCount.getDelta());
- assertEquals(0, oneCount.getDelta());
- assertEquals(1, twoCount.getDelta());
- assertEquals(0, eightThousandCount.getDelta());
-
- RecordHistogram.recordCountHistogram(histogram, 8000);
- assertEquals(2, zeroCount.getDelta());
- assertEquals(0, oneCount.getDelta());
- assertEquals(1, twoCount.getDelta());
- assertEquals(1, eightThousandCount.getDelta());
- }
-
- /**
- * Tests recording of custom times histograms.
- */
- @SmallTest
- public void testRecordCustomTimesHistogram() {
- String histogram = "HelloWorld.CustomTimesMetric";
- HistogramDelta zeroCount = new HistogramDelta(histogram, 0);
- HistogramDelta oneCount = new HistogramDelta(histogram, 1);
- HistogramDelta twoCount = new HistogramDelta(histogram, 100);
-
- assertEquals(0, zeroCount.getDelta());
- assertEquals(0, oneCount.getDelta());
- assertEquals(0, twoCount.getDelta());
-
- TimeUnit milli = TimeUnit.MILLISECONDS;
-
- RecordHistogram.recordCustomTimesHistogram(histogram, 0, 1, 100, milli, 3);
- assertEquals(1, zeroCount.getDelta());
- assertEquals(0, oneCount.getDelta());
- assertEquals(0, twoCount.getDelta());
-
- RecordHistogram.recordCustomTimesHistogram(histogram, 0, 1, 100, milli, 3);
- assertEquals(2, zeroCount.getDelta());
- assertEquals(0, oneCount.getDelta());
- assertEquals(0, twoCount.getDelta());
-
- RecordHistogram.recordCustomTimesHistogram(histogram, 95, 1, 100, milli, 3);
- assertEquals(2, zeroCount.getDelta());
- assertEquals(1, oneCount.getDelta());
- assertEquals(0, twoCount.getDelta());
-
- RecordHistogram.recordCustomTimesHistogram(histogram, 200, 1, 100, milli, 3);
- assertEquals(2, zeroCount.getDelta());
- assertEquals(1, oneCount.getDelta());
- assertEquals(1, twoCount.getDelta());
- }
-}
diff --git a/base/android/jni_generator/android_jar.classes b/base/android/jni_generator/android_jar.classes
deleted file mode 100644
index 7d412cee47..0000000000
--- a/base/android/jni_generator/android_jar.classes
+++ /dev/null
@@ -1,98 +0,0 @@
-java/lang/AbstractMethodError.class
-java/lang/AbstractStringBuilder.class
-java/lang/Appendable.class
-java/lang/ArithmeticException.class
-java/lang/ArrayIndexOutOfBoundsException.class
-java/lang/ArrayStoreException.class
-java/lang/AssertionError.class
-java/lang/AutoCloseable.class
-java/lang/Boolean.class
-java/lang/Byte.class
-java/lang/Character.class
-java/lang/Character$Subset.class
-java/lang/Character$UnicodeBlock.class
-java/lang/CharSequence.class
-java/lang/ClassCastException.class
-java/lang/ClassCircularityError.class
-java/lang/Class.class
-java/lang/ClassFormatError.class
-java/lang/ClassLoader.class
-java/lang/ClassNotFoundException.class
-java/lang/Cloneable.class
-java/lang/CloneNotSupportedException.class
-java/lang/Comparable.class
-java/lang/Compiler.class
-java/lang/Deprecated.class
-java/lang/Double.class
-java/lang/Enum.class
-java/lang/EnumConstantNotPresentException.class
-java/lang/Error.class
-java/lang/Exception.class
-java/lang/ExceptionInInitializerError.class
-java/lang/Float.class
-java/lang/IllegalAccessError.class
-java/lang/IllegalAccessException.class
-java/lang/IllegalArgumentException.class
-java/lang/IllegalMonitorStateException.class
-java/lang/IllegalStateException.class
-java/lang/IncompatibleClassChangeError.class
-java/lang/IndexOutOfBoundsException.class
-java/lang/InheritableThreadLocal.class
-java/lang/InstantiationError.class
-java/lang/InstantiationException.class
-java/lang/Integer.class
-java/lang/InternalError.class
-java/lang/InterruptedException.class
-java/lang/Iterable.class
-java/lang/LinkageError.class
-java/lang/Long.class
-java/lang/Math.class
-java/lang/NegativeArraySizeException.class
-java/lang/NoClassDefFoundError.class
-java/lang/NoSuchFieldError.class
-java/lang/NoSuchFieldException.class
-java/lang/NoSuchMethodError.class
-java/lang/NoSuchMethodException.class
-java/lang/NullPointerException.class
-java/lang/Number.class
-java/lang/NumberFormatException.class
-java/lang/Object.class
-java/lang/OutOfMemoryError.class
-java/lang/Override.class
-java/lang/Package.class
-java/lang/ProcessBuilder.class
-java/lang/Process.class
-java/lang/Readable.class
-java/lang/ReflectiveOperationException.class
-java/lang/Runnable.class
-java/lang/Runtime.class
-java/lang/RuntimeException.class
-java/lang/RuntimePermission.class
-java/lang/SafeVarargs.class
-java/lang/SecurityException.class
-java/lang/SecurityManager.class
-java/lang/Short.class
-java/lang/StackOverflowError.class
-java/lang/StackTraceElement.class
-java/lang/StrictMath.class
-java/lang/StringBuffer.class
-java/lang/StringBuilder.class
-java/lang/String.class
-java/lang/StringIndexOutOfBoundsException.class
-java/lang/SuppressWarnings.class
-java/lang/System.class
-java/lang/Thread.class
-java/lang/ThreadDeath.class
-java/lang/ThreadGroup.class
-java/lang/ThreadLocal.class
-java/lang/Thread$State.class
-java/lang/Thread$UncaughtExceptionHandler.class
-java/lang/Throwable.class
-java/lang/TypeNotPresentException.class
-java/lang/UnknownError.class
-java/lang/UnsatisfiedLinkError.class
-java/lang/UnsupportedClassVersionError.class
-java/lang/UnsupportedOperationException.class
-java/lang/VerifyError.class
-java/lang/VirtualMachineError.class
-java/lang/Void.class
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 ba7494e9b8..0000000000
--- a/base/android/jni_generator/golden_sample_for_tests_jni.h
+++ /dev/null
@@ -1,400 +0,0 @@
-// Copyright 2014 The Chromium 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.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 <jni.h>
-
-#include "base/android/jni_generator/jni_generator_helper.h"
-
-#include "base/android/jni_int_wrapper.h"
-
-// 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;
-#define InnerStructA_clazz(env) g_InnerStructA_clazz
-// Leaking this jclass as we cannot use LazyInstance from some threads.
-jclass g_SampleForTests_clazz = NULL;
-#define SampleForTests_clazz(env) g_SampleForTests_clazz
-// Leaking this jclass as we cannot use LazyInstance from some threads.
-jclass g_InnerStructB_clazz = NULL;
-#define InnerStructB_clazz(env) g_InnerStructB_clazz
-
-} // namespace
-
-namespace base {
-namespace android {
-
-static jlong Init(JNIEnv* env, jobject jcaller,
- jstring param);
-
-static jdouble GetDoubleFunction(JNIEnv* env, jobject jcaller);
-
-static jfloat GetFloatFunction(JNIEnv* env, jclass jcaller);
-
-static void SetNonPODDatatype(JNIEnv* env, jobject jcaller,
- jobject rect);
-
-static jobject GetNonPODDatatype(JNIEnv* env, jobject jcaller);
-
-// Step 2: method stubs.
-static void Destroy(JNIEnv* env, jobject jcaller,
- jlong nativeCPPClass) {
- CPPClass* native = reinterpret_cast<CPPClass*>(nativeCPPClass);
- CHECK_NATIVE_PTR(env, jcaller, native, "Destroy");
- return native->Destroy(env, jcaller);
-}
-
-static jint Method(JNIEnv* env, jobject jcaller,
- jlong nativeCPPClass) {
- CPPClass* native = reinterpret_cast<CPPClass*>(nativeCPPClass);
- CHECK_NATIVE_PTR(env, jcaller, native, "Method", 0);
- return native->Method(env, jcaller);
-}
-
-static jdouble MethodOtherP0(JNIEnv* env, jobject jcaller,
- jlong nativePtr) {
- CPPClass::InnerClass* native =
- reinterpret_cast<CPPClass::InnerClass*>(nativePtr);
- CHECK_NATIVE_PTR(env, jcaller, native, "MethodOtherP0", 0);
- return native->MethodOtherP0(env, jcaller);
-}
-
-static void AddStructB(JNIEnv* env, jobject jcaller,
- jlong nativeCPPClass,
- jobject b) {
- CPPClass* native = reinterpret_cast<CPPClass*>(nativeCPPClass);
- CHECK_NATIVE_PTR(env, jcaller, native, "AddStructB");
- return native->AddStructB(env, jcaller, b);
-}
-
-static void IterateAndDoSomethingWithStructB(JNIEnv* env, jobject jcaller,
- jlong nativeCPPClass) {
- CPPClass* native = reinterpret_cast<CPPClass*>(nativeCPPClass);
- CHECK_NATIVE_PTR(env, jcaller, native, "IterateAndDoSomethingWithStructB");
- return native->IterateAndDoSomethingWithStructB(env, jcaller);
-}
-
-static jstring ReturnAString(JNIEnv* env, jobject jcaller,
- jlong nativeCPPClass) {
- CPPClass* native = reinterpret_cast<CPPClass*>(nativeCPPClass);
- CHECK_NATIVE_PTR(env, jcaller, native, "ReturnAString", NULL);
- return native->ReturnAString(env, jcaller).Release();
-}
-
-static base::subtle::AtomicWord g_SampleForTests_javaMethod = 0;
-static jint Java_SampleForTests_javaMethod(JNIEnv* env, jobject obj,
- JniIntWrapper foo,
- JniIntWrapper bar) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- SampleForTests_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, SampleForTests_clazz(env),
- "javaMethod",
-
-"("
-"I"
-"I"
-")"
-"I",
- &g_SampleForTests_javaMethod);
-
- jint ret =
- env->CallIntMethod(obj,
- method_id, as_jint(foo), as_jint(bar));
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_SampleForTests_staticJavaMethod = 0;
-static jboolean Java_SampleForTests_staticJavaMethod(JNIEnv* env) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, SampleForTests_clazz(env),
- SampleForTests_clazz(env), false);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_STATIC>(
- env, SampleForTests_clazz(env),
- "staticJavaMethod",
-
-"("
-")"
-"Z",
- &g_SampleForTests_staticJavaMethod);
-
- jboolean ret =
- env->CallStaticBooleanMethod(SampleForTests_clazz(env),
- method_id);
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_SampleForTests_packagePrivateJavaMethod = 0;
-static void Java_SampleForTests_packagePrivateJavaMethod(JNIEnv* env, jobject
- obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- SampleForTests_clazz(env));
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, SampleForTests_clazz(env),
- "packagePrivateJavaMethod",
-
-"("
-")"
-"V",
- &g_SampleForTests_packagePrivateJavaMethod);
-
- env->CallVoidMethod(obj,
- method_id);
- jni_generator::CheckException(env);
-
-}
-
-static base::subtle::AtomicWord g_SampleForTests_methodThatThrowsException = 0;
-static void Java_SampleForTests_methodThatThrowsException(JNIEnv* env, jobject
- obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- SampleForTests_clazz(env));
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, SampleForTests_clazz(env),
- "methodThatThrowsException",
-
-"("
-")"
-"V",
- &g_SampleForTests_methodThatThrowsException);
-
- env->CallVoidMethod(obj,
- method_id);
-
-}
-
-static base::subtle::AtomicWord g_InnerStructA_create = 0;
-static base::android::ScopedJavaLocalRef<jobject>
- Java_InnerStructA_create(JNIEnv* env, jlong l,
- JniIntWrapper i,
- jstring s) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, InnerStructA_clazz(env),
- InnerStructA_clazz(env), NULL);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_STATIC>(
- env, InnerStructA_clazz(env),
- "create",
-
-"("
-"J"
-"I"
-"Ljava/lang/String;"
-")"
-"Lorg/chromium/example/jni_generator/SampleForTests$InnerStructA;",
- &g_InnerStructA_create);
-
- jobject ret =
- env->CallStaticObjectMethod(InnerStructA_clazz(env),
- method_id, l, as_jint(i), s);
- jni_generator::CheckException(env);
- return base::android::ScopedJavaLocalRef<jobject>(env, ret);
-}
-
-static base::subtle::AtomicWord g_SampleForTests_addStructA = 0;
-static void Java_SampleForTests_addStructA(JNIEnv* env, jobject obj, jobject a)
- {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- SampleForTests_clazz(env));
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, SampleForTests_clazz(env),
- "addStructA",
-
-"("
-"Lorg/chromium/example/jni_generator/SampleForTests$InnerStructA;"
-")"
-"V",
- &g_SampleForTests_addStructA);
-
- env->CallVoidMethod(obj,
- method_id, a);
- jni_generator::CheckException(env);
-
-}
-
-static base::subtle::AtomicWord g_SampleForTests_iterateAndDoSomething = 0;
-static void Java_SampleForTests_iterateAndDoSomething(JNIEnv* env, jobject obj)
- {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- SampleForTests_clazz(env));
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, SampleForTests_clazz(env),
- "iterateAndDoSomething",
-
-"("
-")"
-"V",
- &g_SampleForTests_iterateAndDoSomething);
-
- env->CallVoidMethod(obj,
- method_id);
- jni_generator::CheckException(env);
-
-}
-
-static base::subtle::AtomicWord g_InnerStructB_getKey = 0;
-static jlong Java_InnerStructB_getKey(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- InnerStructB_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, InnerStructB_clazz(env),
- "getKey",
-
-"("
-")"
-"J",
- &g_InnerStructB_getKey);
-
- jlong ret =
- env->CallLongMethod(obj,
- method_id);
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_InnerStructB_getValue = 0;
-static base::android::ScopedJavaLocalRef<jstring>
- Java_InnerStructB_getValue(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- InnerStructB_clazz(env), NULL);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, InnerStructB_clazz(env),
- "getValue",
-
-"("
-")"
-"Ljava/lang/String;",
- &g_InnerStructB_getValue);
-
- jstring ret =
- static_cast<jstring>(env->CallObjectMethod(obj,
- method_id));
- jni_generator::CheckException(env);
- return base::android::ScopedJavaLocalRef<jstring>(env, ret);
-}
-
-// Step 3: RegisterNatives.
-
-static const JNINativeMethod kMethodsSampleForTests[] = {
- { "nativeInit",
-"("
-"Ljava/lang/String;"
-")"
-"J", reinterpret_cast<void*>(Init) },
- { "nativeDestroy",
-"("
-"J"
-")"
-"V", reinterpret_cast<void*>(Destroy) },
- { "nativeGetDoubleFunction",
-"("
-")"
-"D", reinterpret_cast<void*>(GetDoubleFunction) },
- { "nativeGetFloatFunction",
-"("
-")"
-"F", reinterpret_cast<void*>(GetFloatFunction) },
- { "nativeSetNonPODDatatype",
-"("
-"Landroid/graphics/Rect;"
-")"
-"V", reinterpret_cast<void*>(SetNonPODDatatype) },
- { "nativeGetNonPODDatatype",
-"("
-")"
-"Ljava/lang/Object;", reinterpret_cast<void*>(GetNonPODDatatype) },
- { "nativeMethod",
-"("
-"J"
-")"
-"I", reinterpret_cast<void*>(Method) },
- { "nativeMethodOtherP0",
-"("
-"J"
-")"
-"D", reinterpret_cast<void*>(MethodOtherP0) },
- { "nativeAddStructB",
-"("
-"J"
-"Lorg/chromium/example/jni_generator/SampleForTests$InnerStructB;"
-")"
-"V", reinterpret_cast<void*>(AddStructB) },
- { "nativeIterateAndDoSomethingWithStructB",
-"("
-"J"
-")"
-"V", reinterpret_cast<void*>(IterateAndDoSomethingWithStructB) },
- { "nativeReturnAString",
-"("
-"J"
-")"
-"Ljava/lang/String;", reinterpret_cast<void*>(ReturnAString) },
-};
-
-static bool RegisterNativesImpl(JNIEnv* env) {
-
- g_InnerStructA_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
- base::android::GetClass(env, kInnerStructAClassPath).obj()));
- g_SampleForTests_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
- base::android::GetClass(env, kSampleForTestsClassPath).obj()));
- g_InnerStructB_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
- base::android::GetClass(env, kInnerStructBClassPath).obj()));
-
- const int kMethodsSampleForTestsSize = arraysize(kMethodsSampleForTests);
-
- if (env->RegisterNatives(SampleForTests_clazz(env),
- kMethodsSampleForTests,
- kMethodsSampleForTestsSize) < 0) {
- jni_generator::HandleRegistrationError(
- env, SampleForTests_clazz(env), __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 f54944b1ff..0000000000
--- a/base/android/jni_generator/java/src/org/chromium/example/jni_generator/SampleForTests.java
+++ /dev/null
@@ -1,304 +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.
-
-package org.chromium.example.jni_generator;
-
-import android.graphics.Rect;
-
-import org.chromium.base.CalledByNative;
-import org.chromium.base.JNINamespace;
-import org.chromium.base.NativeClassQualifiedName;
-import org.chromium.base.annotations.AccessedByNative;
-import org.chromium.base.annotations.CalledByNativeUnchecked;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-// 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 "long 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.
-//
-// An important note about qualified class name resolution:
-// The generator doesn't compile the class and have little context about the
-// classes being passed through the JNI layers. It adds a few simple rules:
-//
-// - all classes are either explicitly imported, or they are assumed to be in
-// the same package.
-//
-// - Inner class needs to be done through an import and usage of the
-// outer class, so that the generator knows how to qualify it:
-// import foo.bar.Zoo;
-// void call(Zoo.Inner);
-//
-// - implicitly imported classes aren't supported, so in order to pass
-// things like Runnable, please import java.lang.Runnable;
-//
-// 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. Replace "CPPClass" with your particular class name!
- long 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 C++ Init(...) method 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_<Class>_"
- // 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 mArrgh = "*/*";
-
- // ---------------------------------------------------------------------------------------------
- // 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 mJavaField;
-
- // ---------------------------------------------------------------------------------------------
- // 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 long 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. Replace "CPPClass" with your particular class name!
- private native void nativeDestroy(long 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<jobject> GetNonPODDatatype(JNIEnv* env, jobject obj);
- // The jobject parameter refers back to this java side object instance.
- // Note that it returns a ScopedJavaLocalRef<jobject> 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. Replace "CPPClass" with your particular class name!
- private native int nativeMethod(long 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(long 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<InnerStructA> mListInnerStructA = new ArrayList<InnerStructA>();
-
- @CalledByNative
- private void addStructA(InnerStructA a) {
- // Called by the native side to append another element.
- mListInnerStructA.add(a);
- }
-
- @CalledByNative
- private void iterateAndDoSomething() {
- Iterator<InnerStructA> 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<InnerStructB> mListInnerStructB = new ArrayList<InnerStructB>();
-
- void iterateAndDoSomethingWithMap() {
- Iterator<InnerStructB> it = mListInnerStructB.iterator();
- while (it.hasNext()) {
- InnerStructB element = it.next();
- // Now, do something with element.
- nativeAddStructB(mNativeCPPObject, element);
- }
- nativeIterateAndDoSomethingWithStructB(mNativeCPPObject);
- }
-
- native void nativeAddStructB(long nativeCPPClass, InnerStructB b);
- native void nativeIterateAndDoSomethingWithStructB(long nativeCPPClass);
- native String nativeReturnAString(long nativeCPPClass);
-}
diff --git a/base/android/jni_generator/jni_generator.gyp b/base/android/jni_generator/jni_generator.gyp
deleted file mode 100644
index 4a17f3e57c..0000000000
--- a/base/android/jni_generator/jni_generator.gyp
+++ /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.
-
-{
- 'targets': [
- {
- 'target_name': 'jni_generator_py_tests',
- 'type': 'none',
- 'variables': {
- 'stamp': '<(INTERMEDIATE_DIR)/jni_generator_py_tests.stamp',
- },
- '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': [
- '<(stamp)',
- ],
- 'action': [
- 'python', 'jni_generator_tests.py',
- '--stamp=<(stamp)',
- ],
- },
- ],
- },
- {
- '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',
- ],
- '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 d1f14baa42..0000000000
--- a/base/android/jni_generator/jni_generator.py
+++ /dev/null
@@ -1,1557 +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
-
-CHROMIUM_SRC = os.path.join(
- os.path.dirname(__file__), os.pardir, os.pardir, os.pardir)
-BUILD_ANDROID_GYP = os.path.join(
- CHROMIUM_SRC, 'build', 'android', 'gyp')
-
-sys.path.append(BUILD_ANDROID_GYP)
-
-from util import build_utils
-
-
-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 == kwargs.get('ptr_type', '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.signature = kwargs.get('signature')
- 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)
-
-
-class ConstantField(object):
- def __init__(self, **kwargs):
- self.name = kwargs['name']
- self.value = kwargs['value']
-
-
-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',
- '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'
- elif java_type.startswith('Class'):
- # Checking just the start of the name, rather than a direct comparison,
- # in order to handle generics.
- return 'jclass'
- else:
- return 'jobject'
-
-
-def JavaDataTypeToCForCalledByNativeParam(java_type):
- """Returns a C datatype to be when calling from native."""
- if java_type == 'int':
- return 'JniIntWrapper'
- else:
- return JavaDataTypeToC(java_type)
-
-
-def JavaReturnValueToC(java_type):
- """Returns a valid C return value for the given java type."""
- java_pod_type_map = {
- 'int': '0',
- 'byte': '0',
- 'char': '0',
- 'short': '0',
- 'boolean': 'false',
- 'long': '0',
- 'double': '0',
- 'float': '0',
- 'void': ''
- }
- return java_pod_type_map.get(java_type, 'NULL')
-
-
-class JniParams(object):
- _imports = []
- _fully_qualified_class = ''
- _package = ''
- _inner_classes = []
- _remappings = []
- _implicit_imports = []
-
- @staticmethod
- def SetFullyQualifiedClass(fully_qualified_class):
- JniParams._fully_qualified_class = 'L' + fully_qualified_class
- JniParams._package = '/'.join(fully_qualified_class.split('/')[:-1])
-
- @staticmethod
- def AddAdditionalImport(class_name):
- assert class_name.endswith('.class')
- raw_class_name = class_name[:-len('.class')]
- if '.' in raw_class_name:
- raise SyntaxError('%s cannot be used in @JNIAdditionalImport. '
- 'Only import unqualified outer classes.' % class_name)
- new_import = 'L%s/%s' % (JniParams._package, raw_class_name)
- if new_import in JniParams._imports:
- raise SyntaxError('Do not use JNIAdditionalImport on an already '
- 'imported class: %s' % (new_import.replace('/', '.')))
- JniParams._imports += [new_import]
-
- @staticmethod
- def ExtractImportsAndInnerClasses(contents):
- if not JniParams._package:
- raise RuntimeError('SetFullyQualifiedClass must be called before '
- 'ExtractImportsAndInnerClasses')
- contents = contents.replace('\n', '')
- re_import = re.compile(r'import.*?(?P<class>\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<name>\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]
-
- re_additional_imports = re.compile(
- r'@JNIAdditionalImport\(\s*{?(?P<class_names>.*?)}?\s*\)')
- for match in re.finditer(re_additional_imports, contents):
- for class_name in match.group('class_names').split(','):
- JniParams.AddAdditionalImport(class_name.strip())
-
- @staticmethod
- def ParseJavaPSignature(signature_line):
- prefix = 'Signature: '
- index = signature_line.find(prefix)
- if index == -1:
- prefix = 'descriptor: '
- index = signature_line.index(prefix)
- return '"%s"' % signature_line[index + len(prefix):]
-
- @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 + ';')
- raise SyntaxError('Inner class (%s) can not be '
- 'used directly by JNI. Please import the outer '
- 'class, probably:\n'
- 'import %s.%s;' %
- (param, JniParams._package.replace('/', '.'),
- outer.replace('/', '.')))
-
- JniParams._CheckImplicitImports(param)
-
- # Type not found, falling back to same package as this class.
- return (prefix + 'L' +
- JniParams.RemapClassName(JniParams._package + '/' + param) + ';')
-
- @staticmethod
- def _CheckImplicitImports(param):
- # Ensure implicit imports, such as java.lang.*, are not being treated
- # as being in the same package.
- if not JniParams._implicit_imports:
- # This file was generated from android.jar and lists
- # all classes that are implicitly imported.
- with file(os.path.join(os.path.dirname(sys.argv[0]),
- 'android_jar.classes'), 'r') as f:
- JniParams._implicit_imports = f.readlines()
- for implicit_import in JniParams._implicit_imports:
- implicit_import = implicit_import.strip().replace('.class', '')
- implicit_import = implicit_import.replace('/', '.')
- if implicit_import.endswith('.' + param):
- raise SyntaxError('Ambiguous class (%s) can not be used directly '
- 'by JNI.\nPlease import it, probably:\n\n'
- 'import %s;' %
- (param, implicit_import))
-
-
- @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.endswith('**') and old[:-2] in class_name:
- return class_name.replace(old[:-2], new, 1)
- if '*' not in old and class_name.endswith(old):
- 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():
- rule = line.split()
- if rule[0] != 'rule':
- continue
- _, src, dest = rule
- src = src.replace('.', '/')
- dest = dest.replace('.', '/')
- if src.endswith('**'):
- src_real_name = src[:-2]
- else:
- assert not '*' in src
- src_real_name = src
-
- if dest.endswith('@0'):
- JniParams._remappings.append((src, dest[:-2] + src_real_name))
- elif dest.endswith('@1'):
- assert '**' in src
- JniParams._remappings.append((src, dest[:-2]))
- else:
- assert not '@' in dest
- JniParams._remappings.append((src, dest))
-
-
-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, ptr_type):
- """Returns a list of dict containing information about a native method."""
- contents = contents.replace('\n', '')
- natives = []
- re_native = re.compile(r'(@NativeClassQualifiedName'
- '\(\"(?P<native_class_name>.*?)\"\)\s+)?'
- '(@NativeCall(\(\"(?P<java_class_name>.*?)\"\))\s+)?'
- '(?P<qualifiers>\w+\s\w+|\w+|\s+)\s*native '
- '(?P<return_type>\S*) '
- '(?P<name>native\w+)\((?P<params>.*?)\);')
- 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')),
- ptr_type=ptr_type)
- 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',
- 'float[]': 'jfloatArray',
- '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>(Unchecked)*?)(?:\("(?P<annotation>.*)"\))?'
- '\s+(?P<prefix>[\w ]*?)'
- '\s*(?P<return_type>\S+?)'
- '\s+(?P<name>\w+)'
- '\s*\((?P<params>[^\)]*)\)')
-
-
-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, options):
- self.contents = contents
- self.namespace = options.namespace
- for line in contents:
- class_name = re.match(
- '.*?(public).*?(class|interface) (?P<class_name>\S+?)( |\Z)',
- line)
- if class_name:
- self.fully_qualified_class = class_name.group('class_name')
- break
- self.fully_qualified_class = self.fully_qualified_class.replace('.', '/')
- # Java 7's javap includes type parameters in output, like HashSet<T>. Strip
- # away the <...> and use the raw class name that Java 6 would've given us.
- self.fully_qualified_class = self.fully_qualified_class.split('<', 1)[0]
- 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<prefix>.*?)(?P<return_type>\S+?) (?P<name>\w+?)'
- '\((?P<params>.*?)\)')
- self.called_by_natives = []
- for lineno, content in enumerate(contents[2:], 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('.', '/')),
- signature=JniParams.ParseJavaPSignature(contents[lineno + 1]))]
- re_constructor = re.compile('(.*?)public ' +
- self.fully_qualified_class.replace('/', '.') +
- '\((?P<params>.*?)\)')
- for lineno, content in enumerate(contents[2:], 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('.', '/')),
- signature=JniParams.ParseJavaPSignature(contents[lineno + 1]),
- is_constructor=True)]
- self.called_by_natives = MangleCalledByNatives(self.called_by_natives)
-
- self.constant_fields = []
- re_constant_field = re.compile('.*?public static final int (?P<name>.*?);')
- re_constant_field_value = re.compile(
- '.*?Constant(Value| value): int (?P<value>(-*[0-9]+)?)')
- for lineno, content in enumerate(contents[2:], 2):
- match = re.match(re_constant_field, content)
- if not match:
- continue
- value = re.match(re_constant_field_value, contents[lineno + 2])
- if not value:
- value = re.match(re_constant_field_value, contents[lineno + 3])
- if value:
- self.constant_fields.append(
- ConstantField(name=match.group('name'),
- value=value.group('value')))
-
- self.inl_header_file_generator = InlHeaderFileGenerator(
- self.namespace, self.fully_qualified_class, [],
- self.called_by_natives, self.constant_fields, options)
-
- def GetContent(self):
- return self.inl_header_file_generator.GetContent()
-
- @staticmethod
- def CreateFromClass(class_file, options):
- class_name = os.path.splitext(os.path.basename(class_file))[0]
- p = subprocess.Popen(args=[options.javap, '-c', '-verbose',
- '-s', class_name],
- cwd=os.path.dirname(class_file),
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- stdout, _ = p.communicate()
- jni_from_javap = JNIFromJavaP(stdout.split('\n'), options)
- return jni_from_javap
-
-
-class JNIFromJavaSource(object):
- """Uses the given java source file to generate the JNI header file."""
-
- # Match single line comments, multiline comments, character literals, and
- # double-quoted strings.
- _comment_remover_regex = re.compile(
- r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"',
- re.DOTALL | re.MULTILINE)
-
- def __init__(self, contents, fully_qualified_class, options):
- contents = self._RemoveComments(contents)
- JniParams.SetFullyQualifiedClass(fully_qualified_class)
- JniParams.ExtractImportsAndInnerClasses(contents)
- jni_namespace = ExtractJNINamespace(contents) or options.namespace
- natives = ExtractNatives(contents, options.ptr_type)
- 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,
- [], options)
- self.content = inl_header_file_generator.GetContent()
-
- @classmethod
- def _RemoveComments(cls, contents):
- # We need to support both inline and block comments, and we need to handle
- # strings that contain '//' or '/*'.
- # TODO(bulach): 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
- def replacer(match):
- # Replace matches that are comments with nothing; return literals/strings
- # unchanged.
- s = match.group(0)
- if s.startswith('/'):
- return ''
- else:
- return s
- return cls._comment_remover_regex.sub(replacer, contents)
-
- def GetContent(self):
- return self.content
-
- @staticmethod
- def CreateFromFile(java_file_name, options):
- contents = file(java_file_name).read()
- fully_qualified_class = ExtractFullyQualifiedJavaClassName(java_file_name,
- contents)
- return JNIFromJavaSource(contents, fully_qualified_class, options)
-
-
-class InlHeaderFileGenerator(object):
- """Generates an inline header file for JNI integration."""
-
- def __init__(self, namespace, fully_qualified_class, natives,
- called_by_natives, constant_fields, options):
- 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'
- self.constant_fields = constant_fields
- self.options = options
- self.init_native = self.ExtractInitNative(options)
-
- def ExtractInitNative(self, options):
- for native in self.natives:
- if options.jni_init_native_name == 'native' + native.name:
- self.natives.remove(native)
- return native
- return None
-
- def GetContent(self):
- """Returns the content of the JNI binding file."""
- template = Template("""\
-// Copyright 2014 The Chromium 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 <jni.h>
-
-${INCLUDES}
-
-#include "base/android/jni_int_wrapper.h"
-
-// Step 1: forward declarations.
-namespace {
-$CLASS_PATH_DEFINITIONS
-$METHOD_ID_DEFINITIONS
-} // namespace
-
-$OPEN_NAMESPACE
-$FORWARD_DECLARATIONS
-
-$CONSTANT_FIELDS
-
-// Step 2: method stubs.
-$METHOD_STUBS
-
-// Step 3: RegisterNatives.
-$JNI_NATIVE_METHODS
-$REGISTER_NATIVES
-$CLOSE_NAMESPACE
-$JNI_REGISTER_NATIVES
-#endif // ${HEADER_GUARD}
-""")
- values = {
- 'SCRIPT_NAME': self.options.script_name,
- 'FULLY_QUALIFIED_CLASS': self.fully_qualified_class,
- 'CLASS_PATH_DEFINITIONS': self.GetClassPathDefinitionsString(),
- 'METHOD_ID_DEFINITIONS': self.GetMethodIDDefinitionsString(),
- 'FORWARD_DECLARATIONS': self.GetForwardDeclarationsString(),
- 'CONSTANT_FIELDS': self.GetConstantFieldsString(),
- 'METHOD_STUBS': self.GetMethodStubsString(),
- 'OPEN_NAMESPACE': self.GetOpenNamespaceString(),
- 'JNI_NATIVE_METHODS': self.GetJNINativeMethodsString(),
- 'REGISTER_NATIVES': self.GetRegisterNativesString(),
- 'CLOSE_NAMESPACE': self.GetCloseNamespaceString(),
- 'HEADER_GUARD': self.header_guard,
- 'INCLUDES': self.GetIncludesString(),
- 'JNI_REGISTER_NATIVES': self.GetJNIRegisterNativesString()
- }
- return WrapOutput(template.substitute(values))
-
- def GetClassPathDefinitionsString(self):
- ret = []
- ret += [self.GetClassPathDefinitions()]
- return '\n'.join(ret)
-
- def GetMethodIDDefinitionsString(self):
- """Returns the definition of method ids for the called by native methods."""
- if not self.options.eager_called_by_natives:
- return ''
- template = Template("""\
-jmethodID g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME} = NULL;""")
- ret = []
- for called_by_native in self.called_by_natives:
- values = {
- 'JAVA_CLASS': called_by_native.java_class_name or self.class_name,
- 'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name,
- }
- ret += [template.substitute(values)]
- return '\n'.join(ret)
-
- def GetForwardDeclarationsString(self):
- ret = []
- for native in self.natives:
- if native.type != 'method':
- ret += [self.GetForwardDeclaration(native)]
- if self.options.native_exports and ret:
- return '\nextern "C" {\n' + "\n".join(ret) + '\n}; // extern "C"'
- return '\n'.join(ret)
-
- def GetConstantFieldsString(self):
- if not self.constant_fields:
- return ''
- ret = ['enum Java_%s_constant_fields {' % self.class_name]
- for c in self.constant_fields:
- ret += [' %s = %s,' % (c.name, c.value)]
- ret += ['};']
- return '\n'.join(ret)
-
- def GetMethodStubsString(self):
- """Returns the code corresponding to method stubs."""
- ret = []
- for native in self.natives:
- if native.type == 'method':
- ret += [self.GetNativeMethodStubString(native)]
- if self.options.eager_called_by_natives:
- ret += self.GetEagerCalledByNativeMethodStubs()
- else:
- ret += self.GetLazyCalledByNativeMethodStubs()
-
- if self.options.native_exports and ret:
- return '\nextern "C" {\n' + "\n".join(ret) + '\n}; // extern "C"'
- return '\n'.join(ret)
-
- def GetLazyCalledByNativeMethodStubs(self):
- return [self.GetLazyCalledByNativeMethodStub(called_by_native)
- for called_by_native in self.called_by_natives]
-
- def GetEagerCalledByNativeMethodStubs(self):
- ret = []
- if self.called_by_natives:
- ret += ['namespace {']
- for called_by_native in self.called_by_natives:
- ret += [self.GetEagerCalledByNativeMethodStub(called_by_native)]
- ret += ['} // namespace']
- return ret
-
- def GetIncludesString(self):
- if not self.options.includes:
- return ''
- includes = self.options.includes.split(',')
- return '\n'.join('#include "%s"' % x for x in includes)
-
- 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 SubstituteNativeMethods(self, template):
- """Substitutes JAVA_CLASS and KMETHODS in the provided template."""
- ret = []
- 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 GetJNINativeMethodsString(self):
- """Returns the implementation of the array of native methods."""
- if self.options.native_exports and not self.options.native_exports_optional:
- return ''
- template = Template("""\
-static const JNINativeMethod kMethods${JAVA_CLASS}[] = {
-${KMETHODS}
-};
-""")
- return self.SubstituteNativeMethods(template)
-
- def GetRegisterCalledByNativesImplString(self):
- """Returns the code for registering the called by native methods."""
- if not self.options.eager_called_by_natives:
- return ''
- template = Template("""\
- g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME} = ${GET_METHOD_ID_IMPL}
- if (g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME} == NULL) {
- return false;
- }
- """)
- ret = []
- for called_by_native in self.called_by_natives:
- values = {
- 'JAVA_CLASS': called_by_native.java_class_name or self.class_name,
- 'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name,
- 'GET_METHOD_ID_IMPL': self.GetMethodIDImpl(called_by_native),
- }
- ret += [template.substitute(values)]
- return '\n'.join(ret)
-
- def GetRegisterNativesString(self):
- """Returns the code for RegisterNatives."""
- template = Template("""\
-${REGISTER_NATIVES_SIGNATURE} {
-${EARLY_EXIT}
-${CLASSES}
-${NATIVES}
-${CALLED_BY_NATIVES}
- return true;
-}
-""")
- signature = 'static bool RegisterNativesImpl(JNIEnv* env'
- if self.init_native:
- signature += ', jclass clazz)'
- else:
- signature += ')'
-
- early_exit = ''
- if self.options.native_exports_optional:
- early_exit = """\
- if (base::android::IsManualJniRegistrationDisabled()) return true;
-"""
-
- natives = self.GetRegisterNativesImplString()
- called_by_natives = self.GetRegisterCalledByNativesImplString()
- values = {'REGISTER_NATIVES_SIGNATURE': signature,
- 'EARLY_EXIT': early_exit,
- 'CLASSES': self.GetFindClasses(),
- 'NATIVES': natives,
- 'CALLED_BY_NATIVES': called_by_natives,
- }
- return template.substitute(values)
-
- def GetRegisterNativesImplString(self):
- """Returns the shared implementation for RegisterNatives."""
- if self.options.native_exports and not self.options.native_exports_optional:
- return ''
-
- template = Template("""\
- const int kMethods${JAVA_CLASS}Size = arraysize(kMethods${JAVA_CLASS});
-
- if (env->RegisterNatives(${JAVA_CLASS}_clazz(env),
- kMethods${JAVA_CLASS},
- kMethods${JAVA_CLASS}Size) < 0) {
- jni_generator::HandleRegistrationError(
- env, ${JAVA_CLASS}_clazz(env), __FILE__);
- return false;
- }
-""")
- return self.SubstituteNativeMethods(template)
-
- def GetJNIRegisterNativesString(self):
- """Returns the implementation for the JNI registration of native methods."""
- if not self.init_native:
- return ''
-
- template = Template("""\
-extern "C" JNIEXPORT bool JNICALL
-Java_${FULLY_QUALIFIED_CLASS}_${INIT_NATIVE_NAME}(JNIEnv* env, jclass clazz) {
- return ${NAMESPACE}RegisterNativesImpl(env, clazz);
-}
-""")
-
- if self.options.native_exports:
- java_name = JniParams.RemapClassName(self.fully_qualified_class)
- java_name = java_name.replace('_', '_1').replace('/', '_')
- else:
- java_name = self.fully_qualified_class.replace('/', '_')
-
- namespace = ''
- if self.namespace:
- namespace = self.namespace + '::'
- values = {'FULLY_QUALIFIED_CLASS': java_name,
- 'INIT_NATIVE_NAME': 'native' + self.init_native.name,
- 'NAMESPACE': namespace,
- 'REGISTER_NATIVES_IMPL': self.GetRegisterNativesImplString()
- }
- return template.substitute(values)
-
- 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 jcaller']
- elif native.type == 'function':
- if native.static:
- ret = ['jclass jcaller']
- else:
- ret = ['jobject jcaller']
- 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([
- JavaDataTypeToCForCalledByNativeParam(param.datatype) + ' ' +
- param.name
- for param in called_by_native.params])
-
- def GetStubName(self, native):
- """Return the name of the stub function for this native method.
-
- Args:
- native: the native dictionary describing the method.
-
- Returns:
- A string with the stub function name. For native exports mode this is the
- Java_* symbol name required by the JVM; otherwise it is just the name of
- the native method itself.
- """
- if self.options.native_exports:
- template = Template("Java_${JAVA_NAME}_native${NAME}")
-
- java_name = JniParams.RemapClassName(self.fully_qualified_class)
- java_name = java_name.replace('_', '_1').replace('/', '_')
- if native.java_class_name:
- java_name += '_00024' + native.java_class_name
-
- values = {'NAME': native.name,
- 'JAVA_NAME': java_name}
- return template.substitute(values)
- else:
- return native.name
-
- def GetForwardDeclaration(self, native):
- template_str = """
-static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS});
-"""
- if self.options.native_exports:
- template_str += """
-__attribute__((visibility("default")))
-${RETURN} ${STUB_NAME}(JNIEnv* env, ${PARAMS}) {
- return ${NAME}(${PARAMS_IN_CALL});
-}
-"""
- template = Template(template_str)
- params_in_call = []
- if not self.options.pure_native_methods:
- params_in_call = ['env', 'jcaller']
- params_in_call = ', '.join(params_in_call + [p.name for p in native.params])
-
- values = {'RETURN': JavaDataTypeToC(native.return_type),
- 'NAME': native.name,
- 'PARAMS': self.GetParamsInDeclaration(native),
- 'PARAMS_IN_CALL': params_in_call,
- 'STUB_NAME': self.GetStubName(native)}
- return template.substitute(values)
-
- def GetNativeMethodStubString(self, native):
- """Returns stubs for native methods."""
- if self.options.native_exports:
- template_str = """\
-__attribute__((visibility("default")))
-${RETURN} ${STUB_NAME}(JNIEnv* env,
- ${PARAMS_IN_DECLARATION}) {"""
- else:
- template_str = """\
-static ${RETURN} ${STUB_NAME}(JNIEnv* env, ${PARAMS_IN_DECLARATION}) {"""
- template_str += """
- ${P0_TYPE}* native = reinterpret_cast<${P0_TYPE}*>(${PARAM0_NAME});
- CHECK_NATIVE_PTR(env, jcaller, native, "${NAME}"${OPTIONAL_ERROR_RETURN});
- return native->${NAME}(${PARAMS_IN_CALL})${POST_CALL};
-}
-"""
-
- template = Template(template_str)
- params = []
- if not self.options.pure_native_methods:
- params = ['env', 'jcaller']
- params_in_call = ', '.join(params + [p.name for p in native.params[1:]])
-
- return_type = JavaDataTypeToC(native.return_type)
- optional_error_return = JavaReturnValueToC(native.return_type)
- if optional_error_return:
- optional_error_return = ', ' + optional_error_return
- post_call = ''
- if re.match(RE_SCOPED_JNI_RETURN_TYPES, return_type):
- post_call = '.Release()'
-
- values = {
- 'RETURN': return_type,
- 'OPTIONAL_ERROR_RETURN': optional_error_return,
- 'NAME': native.name,
- 'PARAMS_IN_DECLARATION': self.GetParamsInDeclaration(native),
- 'PARAM0_NAME': native.params[0].name,
- 'P0_TYPE': native.p0_type,
- 'PARAMS_IN_CALL': params_in_call,
- 'POST_CALL': post_call,
- 'STUB_NAME': self.GetStubName(native),
- }
- return template.substitute(values)
-
- def GetArgument(self, param):
- return ('as_jint(' + param.name + ')'
- if param.datatype == 'int' else param.name)
-
- def GetArgumentsInCall(self, params):
- """Return a string of arguments to call from native into Java"""
- return [self.GetArgument(p) for p in params]
-
- def GetCalledByNativeValues(self, called_by_native):
- """Fills in necessary values for the CalledByNative methods."""
- java_class = called_by_native.java_class_name or self.class_name
- if called_by_native.static or called_by_native.is_constructor:
- first_param_in_declaration = ''
- first_param_in_call = ('%s_clazz(env)' % java_class)
- 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_in_call = ', '.join(self.GetArgumentsInCall(called_by_native.params))
- if params_in_call:
- params_in_call = ', ' + params_in_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 = 'jni_generator::CheckException(env);'
- return_type = JavaDataTypeToC(called_by_native.return_type)
- optional_error_return = JavaReturnValueToC(called_by_native.return_type)
- if optional_error_return:
- optional_error_return = ', ' + optional_error_return
- 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 = 'base::android::ScopedJavaLocalRef<' + return_type + '>'
- return_clause = 'return ' + return_type + '(env, ret);'
- else:
- return_clause = 'return ret;'
- return {
- 'JAVA_CLASS': java_class,
- 'RETURN_TYPE': return_type,
- 'OPTIONAL_ERROR_RETURN': optional_error_return,
- 'RETURN_DECLARATION': return_declaration,
- 'RETURN_CLAUSE': return_clause,
- 'FIRST_PARAM_IN_DECLARATION': first_param_in_declaration,
- 'PARAMS_IN_DECLARATION': params_in_declaration,
- '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_in_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)
- }
-
- def GetEagerCalledByNativeMethodStub(self, called_by_native):
- """Returns the implementation of the called by native method."""
- template = Template("""
-static ${RETURN_TYPE} ${METHOD_ID_VAR_NAME}(\
-JNIEnv* env${FIRST_PARAM_IN_DECLARATION}${PARAMS_IN_DECLARATION}) {
- ${RETURN_DECLARATION}${PRE_CALL}env->${ENV_CALL}(${FIRST_PARAM_IN_CALL},
- g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME}${PARAMS_IN_CALL})${POST_CALL};
- ${RETURN_CLAUSE}
-}""")
- values = self.GetCalledByNativeValues(called_by_native)
- return template.substitute(values)
-
- def GetLazyCalledByNativeMethodStub(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() */
- CHECK_CLAZZ(env, ${FIRST_PARAM_IN_CALL},
- ${JAVA_CLASS}_clazz(env)${OPTIONAL_ERROR_RETURN});
- 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}
-}""")
- values = self.GetCalledByNativeValues(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<void*>(${STUB_NAME}) },')
- values = {'NAME': native.name,
- 'JNI_SIGNATURE': JniParams.Signature(native.params,
- native.return_type,
- True),
- 'STUB_NAME': self.GetStubName(native)}
- 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)
- if self.options.native_exports:
- all_classes = called_by_native_classes
- else:
- 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 += ''
-
- class_getter_methods = []
- if self.options.native_exports:
- template = Template("""\
-// Leaking this jclass as we cannot use LazyInstance from some threads.
-base::subtle::AtomicWord g_${JAVA_CLASS}_clazz __attribute__((unused)) = 0;
-#define ${JAVA_CLASS}_clazz(env) \
-base::android::LazyGetClass(env, k${JAVA_CLASS}ClassPath, \
-&g_${JAVA_CLASS}_clazz)""")
- else:
- template = Template("""\
-// Leaking this jclass as we cannot use LazyInstance from some threads.
-jclass g_${JAVA_CLASS}_clazz = NULL;
-#define ${JAVA_CLASS}_clazz(env) g_${JAVA_CLASS}_clazz""")
-
- for clazz in called_by_native_classes:
- values = {
- 'JAVA_CLASS': clazz,
- }
- ret += [template.substitute(values)]
-
- return '\n'.join(ret)
-
- def GetFindClasses(self):
- """Returns the imlementation of FindClass for all known classes."""
- if self.init_native:
- if self.options.native_exports:
- template = Template("""\
- base::subtle::Release_Store(&g_${JAVA_CLASS}_clazz,
- static_cast<base::subtle::AtomicWord>(env->NewWeakGlobalRef(clazz));""")
- else:
- template = Template("""\
- g_${JAVA_CLASS}_clazz = static_cast<jclass>(env->NewWeakGlobalRef(clazz));""")
- else:
- if self.options.native_exports:
- return '\n'
- template = Template("""\
- g_${JAVA_CLASS}_clazz = reinterpret_cast<jclass>(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."""
- if self.options.eager_called_by_natives:
- template = Template("""\
-env->Get${STATIC_METHOD_PART}MethodID(
- ${JAVA_CLASS}_clazz(env),
- "${JNI_NAME}", ${JNI_SIGNATURE});""")
- else:
- template = Template("""\
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_${STATIC}>(
- env, ${JAVA_CLASS}_clazz(env),
- "${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 = '<init>'
- jni_return_type = 'void'
- if called_by_native.signature:
- signature = called_by_native.signature
- else:
- signature = JniParams.Signature(called_by_native.params,
- jni_return_type,
- True)
- 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',
- 'STATIC_METHOD_PART': 'Static' if called_by_native.static else '',
- 'JNI_SIGNATURE': signature,
- }
- 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, options):
- try:
- if os.path.splitext(input_file)[1] == '.class':
- jni_from_javap = JNIFromJavaP.CreateFromClass(input_file, options)
- content = jni_from_javap.GetContent()
- else:
- jni_from_java_source = JNIFromJavaSource.CreateFromFile(
- input_file, options)
- 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 options.optimize_generation 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 content
-
-
-def GetScriptName():
- script_components = os.path.abspath(sys.argv[0]).split(os.path.sep)
- base_index = 0
- for idx, value in enumerate(script_components):
- if value == 'base' or value == 'third_party':
- base_index = idx
- break
- return os.sep.join(script_components[base_index:])
-
-
-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)
- build_utils.AddDepfileOption(option_parser)
-
- option_parser.add_option('-j', '--jar_file', 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, or when there is '
- 'no JNINamespace annotation in the java source.')
- 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.')
- option_parser.add_option('--script_name', default=GetScriptName(),
- help='The name of this script in the generated '
- 'header.')
- option_parser.add_option('--includes',
- help='The comma-separated list of header files to '
- 'include in the generated header.')
- option_parser.add_option('--pure_native_methods',
- action='store_true', dest='pure_native_methods',
- help='When true, the native methods will be called '
- 'without any JNI-specific arguments.')
- option_parser.add_option('--ptr_type', default='int',
- type='choice', choices=['int', 'long'],
- help='The type used to represent native pointers in '
- 'Java code. For 32-bit, use int; '
- 'for 64-bit, use long.')
- option_parser.add_option('--jni_init_native_name', default='',
- help='The name of the JNI registration method that '
- 'is used to initialize all native methods. If a '
- 'method with this name is not present in the Java '
- 'source file, setting this option is a no-op. When '
- 'a method with this name is found however, the '
- 'naming convention Java_<packageName>_<className> '
- 'will limit the initialization to only the '
- 'top-level class.')
- option_parser.add_option('--eager_called_by_natives',
- action='store_true', dest='eager_called_by_natives',
- help='When true, the called-by-native methods will '
- 'be initialized in a non-atomic way.')
- option_parser.add_option('--cpp', default='cpp',
- help='The path to cpp command.')
- option_parser.add_option('--javap', default='javap',
- help='The path to javap command.')
- option_parser.add_option('--native_exports', action='store_true',
- help='Native method registration through .so '
- 'exports.')
- option_parser.add_option('--native_exports_optional', action='store_true',
- help='Support both explicit and native method'
- 'registration.')
- options, args = option_parser.parse_args(argv)
- if options.native_exports_optional:
- options.native_exports = True
- if options.jar_file:
- input_file = ExtractJarInputFile(options.jar_file, options.input_file,
- options.output_dir)
- elif options.input_file:
- input_file = options.input_file
- else:
- option_parser.print_help()
- print '\nError: Must specify --jar_file or --input_file.'
- return 1
- 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)
-
- if options.depfile:
- build_utils.WriteDepfile(
- options.depfile,
- build_utils.GetPythonDependencies())
-
-
-if __name__ == '__main__':
- sys.exit(main(sys.argv))
diff --git a/base/android/jni_generator/jni_generator_helper.h b/base/android/jni_generator/jni_generator_helper.h
deleted file mode 100644
index b9736e1c24..0000000000
--- a/base/android/jni_generator/jni_generator_helper.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2014 The Chromium Authors. All 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_GENERATOR_JNI_GENERATOR_HELPER_H_
-#define BASE_ANDROID_JNI_GENERATOR_JNI_GENERATOR_HELPER_H_
-
-#include <jni.h>
-
-#include "base/android/jni_android.h"
-#include "base/android/scoped_java_ref.h"
-#include "base/basictypes.h"
-#include "base/logging.h"
-
-// Project-specific macros used by the header files generated by
-// jni_generator.py. Different projects can then specify their own
-// implementation for this file.
-#define CHECK_NATIVE_PTR(env, jcaller, native_ptr, method_name, ...) \
- DCHECK(native_ptr) << method_name;
-
-#define CHECK_CLAZZ(env, jcaller, clazz, ...) \
- DCHECK(clazz);
-
-namespace jni_generator {
-
- inline void HandleRegistrationError(JNIEnv* env, jclass clazz,
- const char* filename) {
- LOG(ERROR) << "RegisterNatives failed in " << filename;
- }
-
- inline void CheckException(JNIEnv* env) {
- base::android::CheckException(env);
- }
-
-} // namespace jni_generator
-
-using base::android::ScopedJavaLocalRef;
-
-#endif // BASE_ANDROID_JNI_GENERATOR_JNI_GENERATOR_HELPER_H_
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 60148470b3..0000000000
--- a/base/android/jni_generator/jni_generator_tests.py
+++ /dev/null
@@ -1,1175 +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 inspect
-import optparse
-import os
-import sys
-import unittest
-import jni_generator
-from jni_generator import CalledByNative, JniParams, NativeMethod, Param
-
-
-SCRIPT_NAME = 'base/android/jni_generator/jni_generator.py'
-INCLUDES = (
- 'base/android/jni_generator/jni_generator_helper.h'
-)
-
-# Set this environment variable in order to regenerate the golden text
-# files.
-REBASELINE_ENV = 'REBASELINE'
-
-class TestOptions(object):
- """The mock options object which is passed to the jni_generator.py script."""
-
- def __init__(self):
- self.namespace = None
- self.script_name = SCRIPT_NAME
- self.includes = INCLUDES
- self.pure_native_methods = False
- self.ptr_type = 'long'
- self.jni_init_native_name = None
- self.eager_called_by_natives = False
- self.cpp = 'cpp'
- self.javap = 'javap'
- self.native_exports = False
- self.native_exports_optional = False
-
-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):
- if not self.compareText(golden_text, generated_text):
- self.fail('Golden text mismatch.')
-
- def compareText(self, golden_text, generated_text):
- def FilterText(text):
- return [
- l.strip() for l in text.split('\n')
- if not l.startswith('// Copyright')
- ]
- stripped_golden = FilterText(golden_text)
- stripped_generated = FilterText(generated_text)
- if stripped_golden == stripped_generated:
- return True
- 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
- print 'Run with:'
- print 'REBASELINE=1', sys.argv[0]
- print 'to regenerate the data files.'
-
- def _ReadGoldenFile(self, golden_file):
- if not os.path.exists(golden_file):
- return None
- with file(golden_file, 'r') as f:
- return f.read()
-
- def assertGoldenTextEquals(self, generated_text):
- script_dir = os.path.dirname(sys.argv[0])
- # This is the caller test method.
- caller = inspect.stack()[1][3]
- self.assertTrue(caller.startswith('test'),
- 'assertGoldenTextEquals can only be called from a '
- 'test* method, not %s' % caller)
- golden_file = os.path.join(script_dir, caller + '.golden')
- golden_text = self._ReadGoldenFile(golden_file)
- if os.environ.get(REBASELINE_ENV):
- if golden_text != generated_text:
- with file(golden_file, 'w') as f:
- f.write(generated_text)
- return
- self.assertTextEquals(golden_text, generated_text)
-
- def testInspectCaller(self):
- def willRaise():
- # This function can only be called from a test* method.
- self.assertGoldenTextEquals('')
- self.assertRaises(AssertionError, willRaise)
-
- 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.SetFullyQualifiedClass(
- 'org/chromium/example/jni_generator/SampleForTests')
- jni_generator.JniParams.ExtractImportsAndInnerClasses(test_data)
- natives = jni_generator.ExtractNatives(test_data, 'int')
- 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, [], [], TestOptions())
- self.assertGoldenTextEquals(h.GetContent())
-
- def testInnerClassNatives(self):
- test_data = """
- class MyInnerClass {
- @NativeCall("MyInnerClass")
- private native int nativeInit();
- }
- """
- natives = jni_generator.ExtractNatives(test_data, 'int')
- 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, [], [], TestOptions())
- self.assertGoldenTextEquals(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, 'int')
- 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, [], [], TestOptions())
- self.assertGoldenTextEquals(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, 'int')
- 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, [], [], TestOptions())
- self.assertGoldenTextEquals(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<Bitmap.CompressFormat> 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<Bitmap.CompressFormat>',
- 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, [],
- TestOptions())
- self.assertGoldenTextEquals(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 testFromJavaPGenerics(self):
- contents = """
-public abstract class java.util.HashSet<T> extends java.util.AbstractSet<E>
- implements java.util.Set<E>, java.lang.Cloneable, java.io.Serializable {
- public void dummy();
- Signature: ()V
-}
-"""
- jni_from_javap = jni_generator.JNIFromJavaP(contents.split('\n'),
- TestOptions())
- self.assertEquals(1, len(jni_from_javap.called_by_natives))
- self.assertGoldenTextEquals(jni_from_javap.GetContent())
-
- def testSnippnetJavap6_7_8(self):
- content_javap6 = """
-public class java.util.HashSet {
-public boolean add(java.lang.Object);
- Signature: (Ljava/lang/Object;)Z
-}
-"""
-
- content_javap7 = """
-public class java.util.HashSet {
-public boolean add(E);
- Signature: (Ljava/lang/Object;)Z
-}
-"""
-
- content_javap8 = """
-public class java.util.HashSet {
- public boolean add(E);
- descriptor: (Ljava/lang/Object;)Z
-}
-"""
-
- jni_from_javap6 = jni_generator.JNIFromJavaP(content_javap6.split('\n'),
- TestOptions())
- jni_from_javap7 = jni_generator.JNIFromJavaP(content_javap7.split('\n'),
- TestOptions())
- jni_from_javap8 = jni_generator.JNIFromJavaP(content_javap8.split('\n'),
- TestOptions())
- self.assertTrue(jni_from_javap6.GetContent())
- self.assertTrue(jni_from_javap7.GetContent())
- self.assertTrue(jni_from_javap8.GetContent())
- # Ensure the javap7 is correctly parsed and uses the Signature field rather
- # than the "E" parameter.
- self.assertTextEquals(jni_from_javap6.GetContent(),
- jni_from_javap7.GetContent())
- # Ensure the javap8 is correctly parsed and uses the descriptor field.
- self.assertTextEquals(jni_from_javap7.GetContent(),
- jni_from_javap8.GetContent())
-
- def testFromJavaP(self):
- contents = self._ReadGoldenFile(os.path.join(os.path.dirname(sys.argv[0]),
- 'testInputStream.javap'))
- jni_from_javap = jni_generator.JNIFromJavaP(contents.split('\n'),
- TestOptions())
- self.assertEquals(10, len(jni_from_javap.called_by_natives))
- self.assertGoldenTextEquals(jni_from_javap.GetContent())
-
- def testConstantsFromJavaP(self):
- for f in ['testMotionEvent.javap', 'testMotionEvent.javap7']:
- contents = self._ReadGoldenFile(os.path.join(os.path.dirname(sys.argv[0]),
- f))
- jni_from_javap = jni_generator.JNIFromJavaP(contents.split('\n'),
- TestOptions())
- self.assertEquals(86, len(jni_from_javap.called_by_natives))
- self.assertGoldenTextEquals(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', TestOptions())
-
- def testRaisesOnNonJNIMethod(self):
- test_data = """
- class MyInnerClass {
- private int Foo(int p0) {
- }
- }
- """
- self.assertRaises(SyntaxError,
- jni_generator.JNIFromJavaSource,
- test_data, 'foo/bar', TestOptions())
-
- 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_file = os.path.join(script_dir, 'golden_sample_for_tests_jni.h')
- golden_content = file(golden_file).read()
- jni_from_java = jni_generator.JNIFromJavaSource(
- content, 'org/chromium/example/jni_generator/SampleForTests',
- TestOptions())
- generated_text = jni_from_java.GetContent()
- if not self.compareText(golden_content, generated_text):
- if os.environ.get(REBASELINE_ENV):
- with file(golden_file, 'w') as f:
- f.write(generated_text)
- return
- self.fail('testJniSelfDocumentingExample')
-
- 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'),
- TestOptions())
- 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;
-
- import org.chromium.example3.PrefixFoo;
- import org.chromium.example3.Prefix;
- import org.chromium.example3.Bar$Inner;
-
- class Example {
- private static native void nativeTest(Test t);
- private static native void nativeTest2(PrefixFoo t);
- private static native void nativeTest3(Prefix t);
- private static native void nativeTest4(Bar$Inner t);
- }
- """
- jni_generator.JniParams.SetJarJarMappings(
- """rule org.chromium.example.** com.test.@1
- rule org.chromium.example2.** org.test2.@1
- rule org.chromium.example3.Prefix org.test3.Test
- rule org.chromium.example3.Bar$** org.test3.TestBar$@1""")
- jni_from_java = jni_generator.JNIFromJavaSource(
- test_data, 'org/chromium/example/jni_generator/Example', TestOptions())
- jni_generator.JniParams.SetJarJarMappings('')
- self.assertGoldenTextEquals(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[]'))
-
- def testNativesLong(self):
- test_options = TestOptions()
- test_options.ptr_type = 'long'
- test_data = """"
- private native void nativeDestroy(long nativeChromeBrowserProvider);
- """
- jni_generator.JniParams.ExtractImportsAndInnerClasses(test_data)
- natives = jni_generator.ExtractNatives(test_data, test_options.ptr_type)
- golden_natives = [
- NativeMethod(return_type='void', static=False, name='Destroy',
- params=[Param(datatype='long',
- name='nativeChromeBrowserProvider')],
- java_class_name=None,
- type='method',
- p0_type='ChromeBrowserProvider',
- ptr_type=test_options.ptr_type),
- ]
- self.assertListEquals(golden_natives, natives)
- h = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni',
- natives, [], [], test_options)
- self.assertGoldenTextEquals(h.GetContent())
-
- def testPureNativeMethodsOption(self):
- test_data = """
- package org.chromium.example.jni_generator;
-
- /** The pointer to the native Test. */
- long nativeTest;
-
- class Test {
- private static native long nativeMethod(long nativeTest, int arg1);
- }
- """
- options = TestOptions()
- options.pure_native_methods = True
- jni_from_java = jni_generator.JNIFromJavaSource(
- test_data, 'org/chromium/example/jni_generator/Test', options)
- self.assertGoldenTextEquals(jni_from_java.GetContent())
-
- def testJNIInitNativeNameOption(self):
- test_data = """
- package org.chromium.example.jni_generator;
-
- /** The pointer to the native Test. */
- long nativeTest;
-
- class Test {
- private static native boolean nativeInitNativeClass();
- private static native int nativeMethod(long nativeTest, int arg1);
- }
- """
- options = TestOptions()
- options.jni_init_native_name = 'nativeInitNativeClass'
- jni_from_java = jni_generator.JNIFromJavaSource(
- test_data, 'org/chromium/example/jni_generator/Test', options)
- self.assertGoldenTextEquals(jni_from_java.GetContent())
-
- def testEagerCalledByNativesOption(self):
- test_data = """
- package org.chromium.example.jni_generator;
-
- /** The pointer to the native Test. */
- long nativeTest;
-
- class Test {
- private static native boolean nativeInitNativeClass();
- private static native int nativeMethod(long nativeTest, int arg1);
- @CalledByNative
- private void testMethodWithParam(int iParam);
- @CalledByNative
- private static int testStaticMethodWithParam(int iParam);
- @CalledByNative
- private static double testMethodWithNoParam();
- @CalledByNative
- private static String testStaticMethodWithNoParam();
- }
- """
- options = TestOptions()
- options.jni_init_native_name = 'nativeInitNativeClass'
- options.eager_called_by_natives = True
- jni_from_java = jni_generator.JNIFromJavaSource(
- test_data, 'org/chromium/example/jni_generator/Test', options)
- self.assertGoldenTextEquals(jni_from_java.GetContent())
-
- def runNativeExportsOption(self, optional):
- test_data = """
- package org.chromium.example.jni_generator;
-
- /** The pointer to the native Test. */
- long nativeTest;
-
- class Test {
- private static native boolean nativeInitNativeClass();
- private static native int nativeStaticMethod(long nativeTest, int arg1);
- private native int nativeMethod(long nativeTest, int arg1);
- @CalledByNative
- private void testMethodWithParam(int iParam);
- @CalledByNative
- private String testMethodWithParamAndReturn(int iParam);
- @CalledByNative
- private static int testStaticMethodWithParam(int iParam);
- @CalledByNative
- private static double testMethodWithNoParam();
- @CalledByNative
- private static String testStaticMethodWithNoParam();
-
- class MyInnerClass {
- @NativeCall("MyInnerClass")
- private native int nativeInit();
- }
- class MyOtherInnerClass {
- @NativeCall("MyOtherInnerClass")
- private native int nativeInit();
- }
- }
- """
- options = TestOptions()
- options.jni_init_native_name = 'nativeInitNativeClass'
- options.native_exports = True
- options.native_exports_optional = optional
- jni_from_java = jni_generator.JNIFromJavaSource(
- test_data, 'org/chromium/example/jni_generator/SampleForTests', options)
- return jni_from_java.GetContent()
-
- def testNativeExportsOption(self):
- content = self.runNativeExportsOption(False)
- self.assertGoldenTextEquals(content)
-
- def testNativeExportsOptionalOption(self):
- content = self.runNativeExportsOption(True)
- self.assertGoldenTextEquals(content)
-
- def testOuterInnerRaises(self):
- test_data = """
- package org.chromium.media;
-
- @CalledByNative
- static int getCaptureFormatWidth(VideoCapture.CaptureFormat format) {
- return format.getWidth();
- }
- """
- def willRaise():
- jni_generator.JNIFromJavaSource(
- test_data,
- 'org/chromium/media/VideoCaptureFactory',
- TestOptions())
- self.assertRaises(SyntaxError, willRaise)
-
- def testImplicitImport(self):
- test_data = """
- package org.chromium.android_webview;
-
- %(IMPORT)s
-
- @CalledByNative
- private static void clientCertificatesCleared(Runnable callback) {
- if (callbaback == null) return;
- callback.run();
- }
- """
- def generate(import_clause):
- jni_generator.JNIFromJavaSource(
- test_data % {'IMPORT': import_clause},
- 'org/chromium/android_webview/AwContentStatics',
- TestOptions())
- # Ensure it raises without the import.
- self.assertRaises(SyntaxError, lambda: generate(''))
-
- # Ensure it's fine with the import.
- generate('import java.lang.Runnable;')
-
- def testSingleJNIAdditionalImport(self):
- test_data = """
- package org.chromium.foo;
-
- @JNIAdditionalImport(Bar.class)
- class Foo {
-
- @CalledByNative
- private static void calledByNative(Bar.Callback callback) {
- }
-
- private static native void nativeDoSomething(Bar.Callback callback);
- }
- """
- jni_from_java = jni_generator.JNIFromJavaSource(test_data,
- 'org/chromium/foo/Foo',
- TestOptions())
- self.assertGoldenTextEquals(jni_from_java.GetContent())
-
- def testMultipleJNIAdditionalImport(self):
- test_data = """
- package org.chromium.foo;
-
- @JNIAdditionalImport({Bar1.class, Bar2.class})
- class Foo {
-
- @CalledByNative
- private static void calledByNative(Bar1.Callback callback1,
- Bar2.Callback callback2) {
- }
-
- private static native void nativeDoSomething(Bar1.Callback callback1,
- Bar2.Callback callback2);
- }
- """
- jni_from_java = jni_generator.JNIFromJavaSource(test_data,
- 'org/chromium/foo/Foo',
- TestOptions())
- self.assertGoldenTextEquals(jni_from_java.GetContent())
-
-
-def TouchStamp(stamp_path):
- dir_name = os.path.dirname(stamp_path)
- if not os.path.isdir(dir_name):
- os.makedirs()
-
- with open(stamp_path, 'a'):
- os.utime(stamp_path, None)
-
-
-def main(argv):
- parser = optparse.OptionParser()
- parser.add_option('--stamp', help='Path to touch on success.')
- options, _ = parser.parse_args(argv[1:])
-
- test_result = unittest.main(argv=argv[0:1], exit=False)
-
- if test_result.result.wasSuccessful() and options.stamp:
- TouchStamp(options.stamp)
-
- return not test_result.result.wasSuccessful()
-
-
-if __name__ == '__main__':
- sys.exit(main(sys.argv))
diff --git a/base/android/jni_generator/testCalledByNatives.golden b/base/android/jni_generator/testCalledByNatives.golden
deleted file mode 100644
index e33356aa4e..0000000000
--- a/base/android/jni_generator/testCalledByNatives.golden
+++ /dev/null
@@ -1,510 +0,0 @@
-// Copyright 2014 The Chromium 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.py
-// For
-// org/chromium/TestJni
-
-#ifndef org_chromium_TestJni_JNI
-#define org_chromium_TestJni_JNI
-
-#include <jni.h>
-
-#include "base/android/jni_generator/jni_generator_helper.h"
-
-#include "base/android/jni_int_wrapper.h"
-
-// 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;
-#define TestJni_clazz(env) g_TestJni_clazz
-// Leaking this jclass as we cannot use LazyInstance from some threads.
-jclass g_InfoBar_clazz = NULL;
-#define InfoBar_clazz(env) g_InfoBar_clazz
-
-} // namespace
-
-// Step 2: method stubs.
-
-static base::subtle::AtomicWord g_TestJni_showConfirmInfoBar = 0;
-static base::android::ScopedJavaLocalRef<jobject>
- Java_TestJni_showConfirmInfoBar(JNIEnv* env, jobject obj, JniIntWrapper
- nativeInfoBar,
- jstring buttonOk,
- jstring buttonCancel,
- jstring title,
- jobject icon) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- TestJni_clazz(env), NULL);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, TestJni_clazz(env),
- "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, as_jint(nativeInfoBar), buttonOk, buttonCancel, title,
- icon);
- jni_generator::CheckException(env);
- return base::android::ScopedJavaLocalRef<jobject>(env, ret);
-}
-
-static base::subtle::AtomicWord g_TestJni_showAutoLoginInfoBar = 0;
-static base::android::ScopedJavaLocalRef<jobject>
- Java_TestJni_showAutoLoginInfoBar(JNIEnv* env, jobject obj, JniIntWrapper
- nativeInfoBar,
- jstring realm,
- jstring account,
- jstring args) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- TestJni_clazz(env), NULL);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, TestJni_clazz(env),
- "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, as_jint(nativeInfoBar), realm, account, args);
- jni_generator::CheckException(env);
- return base::android::ScopedJavaLocalRef<jobject>(env, ret);
-}
-
-static base::subtle::AtomicWord g_InfoBar_dismiss = 0;
-static void Java_InfoBar_dismiss(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- InfoBar_clazz(env));
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, InfoBar_clazz(env),
- "dismiss",
-
-"("
-")"
-"V",
- &g_InfoBar_dismiss);
-
- env->CallVoidMethod(obj,
- method_id);
- jni_generator::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() */
- CHECK_CLAZZ(env, TestJni_clazz(env),
- TestJni_clazz(env), false);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_STATIC>(
- env, TestJni_clazz(env),
- "shouldShowAutoLogin",
-
-"("
-"Landroid/view/View;"
-"Ljava/lang/String;"
-"Ljava/lang/String;"
-"Ljava/lang/String;"
-")"
-"Z",
- &g_TestJni_shouldShowAutoLogin);
-
- jboolean ret =
- env->CallStaticBooleanMethod(TestJni_clazz(env),
- method_id, view, realm, account, args);
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_TestJni_openUrl = 0;
-static base::android::ScopedJavaLocalRef<jobject> Java_TestJni_openUrl(JNIEnv*
- env, jstring url) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, TestJni_clazz(env),
- TestJni_clazz(env), NULL);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_STATIC>(
- env, TestJni_clazz(env),
- "openUrl",
-
-"("
-"Ljava/lang/String;"
-")"
-"Ljava/io/InputStream;",
- &g_TestJni_openUrl);
-
- jobject ret =
- env->CallStaticObjectMethod(TestJni_clazz(env),
- method_id, url);
- jni_generator::CheckException(env);
- return base::android::ScopedJavaLocalRef<jobject>(env, ret);
-}
-
-static base::subtle::AtomicWord g_TestJni_activateHardwareAcceleration = 0;
-static void Java_TestJni_activateHardwareAcceleration(JNIEnv* env, jobject obj,
- jboolean activated,
- JniIntWrapper iPid,
- JniIntWrapper iType,
- JniIntWrapper iPrimaryID,
- JniIntWrapper iSecondaryID) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- TestJni_clazz(env));
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, TestJni_clazz(env),
- "activateHardwareAcceleration",
-
-"("
-"Z"
-"I"
-"I"
-"I"
-"I"
-")"
-"V",
- &g_TestJni_activateHardwareAcceleration);
-
- env->CallVoidMethod(obj,
- method_id, activated, as_jint(iPid), as_jint(iType),
- as_jint(iPrimaryID), as_jint(iSecondaryID));
- jni_generator::CheckException(env);
-
-}
-
-static base::subtle::AtomicWord g_TestJni_uncheckedCall = 0;
-static void Java_TestJni_uncheckedCall(JNIEnv* env, jobject obj, JniIntWrapper
- iParam) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- TestJni_clazz(env));
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, TestJni_clazz(env),
- "uncheckedCall",
-
-"("
-"I"
-")"
-"V",
- &g_TestJni_uncheckedCall);
-
- env->CallVoidMethod(obj,
- method_id, as_jint(iParam));
-
-}
-
-static base::subtle::AtomicWord g_TestJni_returnByteArray = 0;
-static base::android::ScopedJavaLocalRef<jbyteArray>
- Java_TestJni_returnByteArray(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- TestJni_clazz(env), NULL);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, TestJni_clazz(env),
- "returnByteArray",
-
-"("
-")"
-"[B",
- &g_TestJni_returnByteArray);
-
- jbyteArray ret =
- static_cast<jbyteArray>(env->CallObjectMethod(obj,
- method_id));
- jni_generator::CheckException(env);
- return base::android::ScopedJavaLocalRef<jbyteArray>(env, ret);
-}
-
-static base::subtle::AtomicWord g_TestJni_returnBooleanArray = 0;
-static base::android::ScopedJavaLocalRef<jbooleanArray>
- Java_TestJni_returnBooleanArray(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- TestJni_clazz(env), NULL);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, TestJni_clazz(env),
- "returnBooleanArray",
-
-"("
-")"
-"[Z",
- &g_TestJni_returnBooleanArray);
-
- jbooleanArray ret =
- static_cast<jbooleanArray>(env->CallObjectMethod(obj,
- method_id));
- jni_generator::CheckException(env);
- return base::android::ScopedJavaLocalRef<jbooleanArray>(env, ret);
-}
-
-static base::subtle::AtomicWord g_TestJni_returnCharArray = 0;
-static base::android::ScopedJavaLocalRef<jcharArray>
- Java_TestJni_returnCharArray(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- TestJni_clazz(env), NULL);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, TestJni_clazz(env),
- "returnCharArray",
-
-"("
-")"
-"[C",
- &g_TestJni_returnCharArray);
-
- jcharArray ret =
- static_cast<jcharArray>(env->CallObjectMethod(obj,
- method_id));
- jni_generator::CheckException(env);
- return base::android::ScopedJavaLocalRef<jcharArray>(env, ret);
-}
-
-static base::subtle::AtomicWord g_TestJni_returnShortArray = 0;
-static base::android::ScopedJavaLocalRef<jshortArray>
- Java_TestJni_returnShortArray(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- TestJni_clazz(env), NULL);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, TestJni_clazz(env),
- "returnShortArray",
-
-"("
-")"
-"[S",
- &g_TestJni_returnShortArray);
-
- jshortArray ret =
- static_cast<jshortArray>(env->CallObjectMethod(obj,
- method_id));
- jni_generator::CheckException(env);
- return base::android::ScopedJavaLocalRef<jshortArray>(env, ret);
-}
-
-static base::subtle::AtomicWord g_TestJni_returnIntArray = 0;
-static base::android::ScopedJavaLocalRef<jintArray>
- Java_TestJni_returnIntArray(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- TestJni_clazz(env), NULL);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, TestJni_clazz(env),
- "returnIntArray",
-
-"("
-")"
-"[I",
- &g_TestJni_returnIntArray);
-
- jintArray ret =
- static_cast<jintArray>(env->CallObjectMethod(obj,
- method_id));
- jni_generator::CheckException(env);
- return base::android::ScopedJavaLocalRef<jintArray>(env, ret);
-}
-
-static base::subtle::AtomicWord g_TestJni_returnLongArray = 0;
-static base::android::ScopedJavaLocalRef<jlongArray>
- Java_TestJni_returnLongArray(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- TestJni_clazz(env), NULL);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, TestJni_clazz(env),
- "returnLongArray",
-
-"("
-")"
-"[J",
- &g_TestJni_returnLongArray);
-
- jlongArray ret =
- static_cast<jlongArray>(env->CallObjectMethod(obj,
- method_id));
- jni_generator::CheckException(env);
- return base::android::ScopedJavaLocalRef<jlongArray>(env, ret);
-}
-
-static base::subtle::AtomicWord g_TestJni_returnDoubleArray = 0;
-static base::android::ScopedJavaLocalRef<jdoubleArray>
- Java_TestJni_returnDoubleArray(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- TestJni_clazz(env), NULL);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, TestJni_clazz(env),
- "returnDoubleArray",
-
-"("
-")"
-"[D",
- &g_TestJni_returnDoubleArray);
-
- jdoubleArray ret =
- static_cast<jdoubleArray>(env->CallObjectMethod(obj,
- method_id));
- jni_generator::CheckException(env);
- return base::android::ScopedJavaLocalRef<jdoubleArray>(env, ret);
-}
-
-static base::subtle::AtomicWord g_TestJni_returnObjectArray = 0;
-static base::android::ScopedJavaLocalRef<jobjectArray>
- Java_TestJni_returnObjectArray(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- TestJni_clazz(env), NULL);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, TestJni_clazz(env),
- "returnObjectArray",
-
-"("
-")"
-"[Ljava/lang/Object;",
- &g_TestJni_returnObjectArray);
-
- jobjectArray ret =
- static_cast<jobjectArray>(env->CallObjectMethod(obj,
- method_id));
- jni_generator::CheckException(env);
- return base::android::ScopedJavaLocalRef<jobjectArray>(env, ret);
-}
-
-static base::subtle::AtomicWord g_TestJni_returnArrayOfByteArray = 0;
-static base::android::ScopedJavaLocalRef<jobjectArray>
- Java_TestJni_returnArrayOfByteArray(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- TestJni_clazz(env), NULL);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, TestJni_clazz(env),
- "returnArrayOfByteArray",
-
-"("
-")"
-"[[B",
- &g_TestJni_returnArrayOfByteArray);
-
- jobjectArray ret =
- static_cast<jobjectArray>(env->CallObjectMethod(obj,
- method_id));
- jni_generator::CheckException(env);
- return base::android::ScopedJavaLocalRef<jobjectArray>(env, ret);
-}
-
-static base::subtle::AtomicWord g_TestJni_getCompressFormat = 0;
-static base::android::ScopedJavaLocalRef<jobject>
- Java_TestJni_getCompressFormat(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- TestJni_clazz(env), NULL);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, TestJni_clazz(env),
- "getCompressFormat",
-
-"("
-")"
-"Landroid/graphics/Bitmap$CompressFormat;",
- &g_TestJni_getCompressFormat);
-
- jobject ret =
- env->CallObjectMethod(obj,
- method_id);
- jni_generator::CheckException(env);
- return base::android::ScopedJavaLocalRef<jobject>(env, ret);
-}
-
-static base::subtle::AtomicWord g_TestJni_getCompressFormatList = 0;
-static base::android::ScopedJavaLocalRef<jobject>
- Java_TestJni_getCompressFormatList(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- TestJni_clazz(env), NULL);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, TestJni_clazz(env),
- "getCompressFormatList",
-
-"("
-")"
-"Ljava/util/List;",
- &g_TestJni_getCompressFormatList);
-
- jobject ret =
- env->CallObjectMethod(obj,
- method_id);
- jni_generator::CheckException(env);
- return base::android::ScopedJavaLocalRef<jobject>(env, ret);
-}
-
-// Step 3: RegisterNatives.
-
-static bool RegisterNativesImpl(JNIEnv* env) {
-
- g_TestJni_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
- base::android::GetClass(env, kTestJniClassPath).obj()));
- g_InfoBar_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
- base::android::GetClass(env, kInfoBarClassPath).obj()));
-
- return true;
-}
-
-#endif // org_chromium_TestJni_JNI
diff --git a/base/android/jni_generator/testConstantsFromJavaP.golden b/base/android/jni_generator/testConstantsFromJavaP.golden
deleted file mode 100644
index 1c816bcf99..0000000000
--- a/base/android/jni_generator/testConstantsFromJavaP.golden
+++ /dev/null
@@ -1,2233 +0,0 @@
-// Copyright 2014 The Chromium 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.py
-// For
-// android/view/MotionEvent
-
-#ifndef android_view_MotionEvent_JNI
-#define android_view_MotionEvent_JNI
-
-#include <jni.h>
-
-#include "base/android/jni_generator/jni_generator_helper.h"
-
-#include "base/android/jni_int_wrapper.h"
-
-// Step 1: forward declarations.
-namespace {
-const char kMotionEventClassPath[] = "android/view/MotionEvent";
-// Leaking this jclass as we cannot use LazyInstance from some threads.
-jclass g_MotionEvent_clazz = NULL;
-#define MotionEvent_clazz(env) g_MotionEvent_clazz
-
-} // namespace
-
-namespace JNI_MotionEvent {
-
-enum Java_MotionEvent_constant_fields {
- INVALID_POINTER_ID = -1,
- ACTION_MASK = 255,
- ACTION_DOWN = 0,
- ACTION_UP = 1,
- ACTION_MOVE = 2,
- ACTION_CANCEL = 3,
- ACTION_OUTSIDE = 4,
- ACTION_POINTER_DOWN = 5,
- ACTION_POINTER_UP = 6,
- ACTION_HOVER_MOVE = 7,
- ACTION_SCROLL = 8,
- ACTION_HOVER_ENTER = 9,
- ACTION_HOVER_EXIT = 10,
- ACTION_POINTER_INDEX_MASK = 65280,
- ACTION_POINTER_INDEX_SHIFT = 8,
- ACTION_POINTER_1_DOWN = 5,
- ACTION_POINTER_2_DOWN = 261,
- ACTION_POINTER_3_DOWN = 517,
- ACTION_POINTER_1_UP = 6,
- ACTION_POINTER_2_UP = 262,
- ACTION_POINTER_3_UP = 518,
- ACTION_POINTER_ID_MASK = 65280,
- ACTION_POINTER_ID_SHIFT = 8,
- FLAG_WINDOW_IS_OBSCURED = 1,
- EDGE_TOP = 1,
- EDGE_BOTTOM = 2,
- EDGE_LEFT = 4,
- EDGE_RIGHT = 8,
- AXIS_X = 0,
- AXIS_Y = 1,
- AXIS_PRESSURE = 2,
- AXIS_SIZE = 3,
- AXIS_TOUCH_MAJOR = 4,
- AXIS_TOUCH_MINOR = 5,
- AXIS_TOOL_MAJOR = 6,
- AXIS_TOOL_MINOR = 7,
- AXIS_ORIENTATION = 8,
- AXIS_VSCROLL = 9,
- AXIS_HSCROLL = 10,
- AXIS_Z = 11,
- AXIS_RX = 12,
- AXIS_RY = 13,
- AXIS_RZ = 14,
- AXIS_HAT_X = 15,
- AXIS_HAT_Y = 16,
- AXIS_LTRIGGER = 17,
- AXIS_RTRIGGER = 18,
- AXIS_THROTTLE = 19,
- AXIS_RUDDER = 20,
- AXIS_WHEEL = 21,
- AXIS_GAS = 22,
- AXIS_BRAKE = 23,
- AXIS_DISTANCE = 24,
- AXIS_TILT = 25,
- AXIS_GENERIC_1 = 32,
- AXIS_GENERIC_2 = 33,
- AXIS_GENERIC_3 = 34,
- AXIS_GENERIC_4 = 35,
- AXIS_GENERIC_5 = 36,
- AXIS_GENERIC_6 = 37,
- AXIS_GENERIC_7 = 38,
- AXIS_GENERIC_8 = 39,
- AXIS_GENERIC_9 = 40,
- AXIS_GENERIC_10 = 41,
- AXIS_GENERIC_11 = 42,
- AXIS_GENERIC_12 = 43,
- AXIS_GENERIC_13 = 44,
- AXIS_GENERIC_14 = 45,
- AXIS_GENERIC_15 = 46,
- AXIS_GENERIC_16 = 47,
- BUTTON_PRIMARY = 1,
- BUTTON_SECONDARY = 2,
- BUTTON_TERTIARY = 4,
- BUTTON_BACK = 8,
- BUTTON_FORWARD = 16,
- TOOL_TYPE_UNKNOWN = 0,
- TOOL_TYPE_FINGER = 1,
- TOOL_TYPE_STYLUS = 2,
- TOOL_TYPE_MOUSE = 3,
- TOOL_TYPE_ERASER = 4,
-};
-
-// Step 2: method stubs.
-
-static base::subtle::AtomicWord g_MotionEvent_finalize = 0;
-static void Java_MotionEvent_finalize(JNIEnv* env, jobject obj) __attribute__
- ((unused));
-static void Java_MotionEvent_finalize(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env));
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "finalize",
- "()V",
- &g_MotionEvent_finalize);
-
- env->CallVoidMethod(obj,
- method_id);
- jni_generator::CheckException(env);
-
-}
-
-static base::subtle::AtomicWord
- g_MotionEvent_obtainAVME_J_J_I_I_LAVMEPP_LAVMEPC_I_I_F_F_I_I_I_I = 0;
-static base::android::ScopedJavaLocalRef<jobject>
- Java_MotionEvent_obtainAVME_J_J_I_I_LAVMEPP_LAVMEPC_I_I_F_F_I_I_I_I(JNIEnv*
- env, jlong p0,
- jlong p1,
- JniIntWrapper p2,
- JniIntWrapper p3,
- jobjectArray p4,
- jobjectArray p5,
- JniIntWrapper p6,
- JniIntWrapper p7,
- jfloat p8,
- jfloat p9,
- JniIntWrapper p10,
- JniIntWrapper p11,
- JniIntWrapper p12,
- JniIntWrapper p13) __attribute__ ((unused));
-static base::android::ScopedJavaLocalRef<jobject>
- Java_MotionEvent_obtainAVME_J_J_I_I_LAVMEPP_LAVMEPC_I_I_F_F_I_I_I_I(JNIEnv*
- env, jlong p0,
- jlong p1,
- JniIntWrapper p2,
- JniIntWrapper p3,
- jobjectArray p4,
- jobjectArray p5,
- JniIntWrapper p6,
- JniIntWrapper p7,
- jfloat p8,
- jfloat p9,
- JniIntWrapper p10,
- JniIntWrapper p11,
- JniIntWrapper p12,
- JniIntWrapper p13) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, MotionEvent_clazz(env),
- MotionEvent_clazz(env), NULL);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_STATIC>(
- env, MotionEvent_clazz(env),
- "obtain",
-"(JJII[Landroid/view/MotionEvent$PointerProperties;[Landroid/view/MotionEvent$PointerCoords;IIFFIIII)Landroid/view/MotionEvent;",
- &g_MotionEvent_obtainAVME_J_J_I_I_LAVMEPP_LAVMEPC_I_I_F_F_I_I_I_I);
-
- jobject ret =
- env->CallStaticObjectMethod(MotionEvent_clazz(env),
- method_id, p0, p1, as_jint(p2), as_jint(p3), p4, p5, as_jint(p6),
- as_jint(p7), p8, p9, as_jint(p10), as_jint(p11), as_jint(p12),
- as_jint(p13));
- jni_generator::CheckException(env);
- return base::android::ScopedJavaLocalRef<jobject>(env, ret);
-}
-
-static base::subtle::AtomicWord
- g_MotionEvent_obtainAVME_J_J_I_I_AI_LAVMEPC_I_F_F_I_I_I_I = 0;
-static base::android::ScopedJavaLocalRef<jobject>
- Java_MotionEvent_obtainAVME_J_J_I_I_AI_LAVMEPC_I_F_F_I_I_I_I(JNIEnv* env,
- jlong p0,
- jlong p1,
- JniIntWrapper p2,
- JniIntWrapper p3,
- jintArray p4,
- jobjectArray p5,
- JniIntWrapper p6,
- jfloat p7,
- jfloat p8,
- JniIntWrapper p9,
- JniIntWrapper p10,
- JniIntWrapper p11,
- JniIntWrapper p12) __attribute__ ((unused));
-static base::android::ScopedJavaLocalRef<jobject>
- Java_MotionEvent_obtainAVME_J_J_I_I_AI_LAVMEPC_I_F_F_I_I_I_I(JNIEnv* env,
- jlong p0,
- jlong p1,
- JniIntWrapper p2,
- JniIntWrapper p3,
- jintArray p4,
- jobjectArray p5,
- JniIntWrapper p6,
- jfloat p7,
- jfloat p8,
- JniIntWrapper p9,
- JniIntWrapper p10,
- JniIntWrapper p11,
- JniIntWrapper p12) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, MotionEvent_clazz(env),
- MotionEvent_clazz(env), NULL);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_STATIC>(
- env, MotionEvent_clazz(env),
- "obtain",
-"(JJII[I[Landroid/view/MotionEvent$PointerCoords;IFFIIII)Landroid/view/MotionEvent;",
- &g_MotionEvent_obtainAVME_J_J_I_I_AI_LAVMEPC_I_F_F_I_I_I_I);
-
- jobject ret =
- env->CallStaticObjectMethod(MotionEvent_clazz(env),
- method_id, p0, p1, as_jint(p2), as_jint(p3), p4, p5, as_jint(p6), p7,
- p8, as_jint(p9), as_jint(p10), as_jint(p11), as_jint(p12));
- jni_generator::CheckException(env);
- return base::android::ScopedJavaLocalRef<jobject>(env, ret);
-}
-
-static base::subtle::AtomicWord g_MotionEvent_obtainAVME_J_J_I_F_F_F_F_I_F_F_I_I
- = 0;
-static base::android::ScopedJavaLocalRef<jobject>
- Java_MotionEvent_obtainAVME_J_J_I_F_F_F_F_I_F_F_I_I(JNIEnv* env, jlong p0,
- jlong p1,
- JniIntWrapper p2,
- jfloat p3,
- jfloat p4,
- jfloat p5,
- jfloat p6,
- JniIntWrapper p7,
- jfloat p8,
- jfloat p9,
- JniIntWrapper p10,
- JniIntWrapper p11) __attribute__ ((unused));
-static base::android::ScopedJavaLocalRef<jobject>
- Java_MotionEvent_obtainAVME_J_J_I_F_F_F_F_I_F_F_I_I(JNIEnv* env, jlong p0,
- jlong p1,
- JniIntWrapper p2,
- jfloat p3,
- jfloat p4,
- jfloat p5,
- jfloat p6,
- JniIntWrapper p7,
- jfloat p8,
- jfloat p9,
- JniIntWrapper p10,
- JniIntWrapper p11) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, MotionEvent_clazz(env),
- MotionEvent_clazz(env), NULL);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_STATIC>(
- env, MotionEvent_clazz(env),
- "obtain",
- "(JJIFFFFIFFII)Landroid/view/MotionEvent;",
- &g_MotionEvent_obtainAVME_J_J_I_F_F_F_F_I_F_F_I_I);
-
- jobject ret =
- env->CallStaticObjectMethod(MotionEvent_clazz(env),
- method_id, p0, p1, as_jint(p2), p3, p4, p5, p6, as_jint(p7), p8, p9,
- as_jint(p10), as_jint(p11));
- jni_generator::CheckException(env);
- return base::android::ScopedJavaLocalRef<jobject>(env, ret);
-}
-
-static base::subtle::AtomicWord
- g_MotionEvent_obtainAVME_J_J_I_I_F_F_F_F_I_F_F_I_I = 0;
-static base::android::ScopedJavaLocalRef<jobject>
- Java_MotionEvent_obtainAVME_J_J_I_I_F_F_F_F_I_F_F_I_I(JNIEnv* env, jlong p0,
- jlong p1,
- JniIntWrapper p2,
- JniIntWrapper p3,
- jfloat p4,
- jfloat p5,
- jfloat p6,
- jfloat p7,
- JniIntWrapper p8,
- jfloat p9,
- jfloat p10,
- JniIntWrapper p11,
- JniIntWrapper p12) __attribute__ ((unused));
-static base::android::ScopedJavaLocalRef<jobject>
- Java_MotionEvent_obtainAVME_J_J_I_I_F_F_F_F_I_F_F_I_I(JNIEnv* env, jlong p0,
- jlong p1,
- JniIntWrapper p2,
- JniIntWrapper p3,
- jfloat p4,
- jfloat p5,
- jfloat p6,
- jfloat p7,
- JniIntWrapper p8,
- jfloat p9,
- jfloat p10,
- JniIntWrapper p11,
- JniIntWrapper p12) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, MotionEvent_clazz(env),
- MotionEvent_clazz(env), NULL);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_STATIC>(
- env, MotionEvent_clazz(env),
- "obtain",
- "(JJIIFFFFIFFII)Landroid/view/MotionEvent;",
- &g_MotionEvent_obtainAVME_J_J_I_I_F_F_F_F_I_F_F_I_I);
-
- jobject ret =
- env->CallStaticObjectMethod(MotionEvent_clazz(env),
- method_id, p0, p1, as_jint(p2), as_jint(p3), p4, p5, p6, p7,
- as_jint(p8), p9, p10, as_jint(p11), as_jint(p12));
- jni_generator::CheckException(env);
- return base::android::ScopedJavaLocalRef<jobject>(env, ret);
-}
-
-static base::subtle::AtomicWord g_MotionEvent_obtainAVME_J_J_I_F_F_I = 0;
-static base::android::ScopedJavaLocalRef<jobject>
- Java_MotionEvent_obtainAVME_J_J_I_F_F_I(JNIEnv* env, jlong p0,
- jlong p1,
- JniIntWrapper p2,
- jfloat p3,
- jfloat p4,
- JniIntWrapper p5) __attribute__ ((unused));
-static base::android::ScopedJavaLocalRef<jobject>
- Java_MotionEvent_obtainAVME_J_J_I_F_F_I(JNIEnv* env, jlong p0,
- jlong p1,
- JniIntWrapper p2,
- jfloat p3,
- jfloat p4,
- JniIntWrapper p5) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, MotionEvent_clazz(env),
- MotionEvent_clazz(env), NULL);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_STATIC>(
- env, MotionEvent_clazz(env),
- "obtain",
- "(JJIFFI)Landroid/view/MotionEvent;",
- &g_MotionEvent_obtainAVME_J_J_I_F_F_I);
-
- jobject ret =
- env->CallStaticObjectMethod(MotionEvent_clazz(env),
- method_id, p0, p1, as_jint(p2), p3, p4, as_jint(p5));
- jni_generator::CheckException(env);
- return base::android::ScopedJavaLocalRef<jobject>(env, ret);
-}
-
-static base::subtle::AtomicWord g_MotionEvent_obtainAVME_AVME = 0;
-static base::android::ScopedJavaLocalRef<jobject>
- Java_MotionEvent_obtainAVME_AVME(JNIEnv* env, jobject p0) __attribute__
- ((unused));
-static base::android::ScopedJavaLocalRef<jobject>
- Java_MotionEvent_obtainAVME_AVME(JNIEnv* env, jobject p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, MotionEvent_clazz(env),
- MotionEvent_clazz(env), NULL);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_STATIC>(
- env, MotionEvent_clazz(env),
- "obtain",
- "(Landroid/view/MotionEvent;)Landroid/view/MotionEvent;",
- &g_MotionEvent_obtainAVME_AVME);
-
- jobject ret =
- env->CallStaticObjectMethod(MotionEvent_clazz(env),
- method_id, p0);
- jni_generator::CheckException(env);
- return base::android::ScopedJavaLocalRef<jobject>(env, ret);
-}
-
-static base::subtle::AtomicWord g_MotionEvent_obtainNoHistory = 0;
-static base::android::ScopedJavaLocalRef<jobject>
- Java_MotionEvent_obtainNoHistory(JNIEnv* env, jobject p0) __attribute__
- ((unused));
-static base::android::ScopedJavaLocalRef<jobject>
- Java_MotionEvent_obtainNoHistory(JNIEnv* env, jobject p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, MotionEvent_clazz(env),
- MotionEvent_clazz(env), NULL);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_STATIC>(
- env, MotionEvent_clazz(env),
- "obtainNoHistory",
- "(Landroid/view/MotionEvent;)Landroid/view/MotionEvent;",
- &g_MotionEvent_obtainNoHistory);
-
- jobject ret =
- env->CallStaticObjectMethod(MotionEvent_clazz(env),
- method_id, p0);
- jni_generator::CheckException(env);
- return base::android::ScopedJavaLocalRef<jobject>(env, ret);
-}
-
-static base::subtle::AtomicWord g_MotionEvent_recycle = 0;
-static void Java_MotionEvent_recycle(JNIEnv* env, jobject obj) __attribute__
- ((unused));
-static void Java_MotionEvent_recycle(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env));
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "recycle",
- "()V",
- &g_MotionEvent_recycle);
-
- env->CallVoidMethod(obj,
- method_id);
- jni_generator::CheckException(env);
-
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getDeviceId = 0;
-static jint Java_MotionEvent_getDeviceId(JNIEnv* env, jobject obj) __attribute__
- ((unused));
-static jint Java_MotionEvent_getDeviceId(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getDeviceId",
- "()I",
- &g_MotionEvent_getDeviceId);
-
- jint ret =
- env->CallIntMethod(obj,
- method_id);
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getSource = 0;
-static jint Java_MotionEvent_getSource(JNIEnv* env, jobject obj) __attribute__
- ((unused));
-static jint Java_MotionEvent_getSource(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getSource",
- "()I",
- &g_MotionEvent_getSource);
-
- jint ret =
- env->CallIntMethod(obj,
- method_id);
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_setSource = 0;
-static void Java_MotionEvent_setSource(JNIEnv* env, jobject obj, JniIntWrapper
- p0) __attribute__ ((unused));
-static void Java_MotionEvent_setSource(JNIEnv* env, jobject obj, JniIntWrapper
- p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env));
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "setSource",
- "(I)V",
- &g_MotionEvent_setSource);
-
- env->CallVoidMethod(obj,
- method_id, as_jint(p0));
- jni_generator::CheckException(env);
-
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getAction = 0;
-static jint Java_MotionEvent_getAction(JNIEnv* env, jobject obj) __attribute__
- ((unused));
-static jint Java_MotionEvent_getAction(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getAction",
- "()I",
- &g_MotionEvent_getAction);
-
- jint ret =
- env->CallIntMethod(obj,
- method_id);
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getActionMasked = 0;
-static jint Java_MotionEvent_getActionMasked(JNIEnv* env, jobject obj)
- __attribute__ ((unused));
-static jint Java_MotionEvent_getActionMasked(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getActionMasked",
- "()I",
- &g_MotionEvent_getActionMasked);
-
- jint ret =
- env->CallIntMethod(obj,
- method_id);
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getActionIndex = 0;
-static jint Java_MotionEvent_getActionIndex(JNIEnv* env, jobject obj)
- __attribute__ ((unused));
-static jint Java_MotionEvent_getActionIndex(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getActionIndex",
- "()I",
- &g_MotionEvent_getActionIndex);
-
- jint ret =
- env->CallIntMethod(obj,
- method_id);
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getFlags = 0;
-static jint Java_MotionEvent_getFlags(JNIEnv* env, jobject obj) __attribute__
- ((unused));
-static jint Java_MotionEvent_getFlags(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getFlags",
- "()I",
- &g_MotionEvent_getFlags);
-
- jint ret =
- env->CallIntMethod(obj,
- method_id);
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getDownTime = 0;
-static jlong Java_MotionEvent_getDownTime(JNIEnv* env, jobject obj)
- __attribute__ ((unused));
-static jlong Java_MotionEvent_getDownTime(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getDownTime",
- "()J",
- &g_MotionEvent_getDownTime);
-
- jlong ret =
- env->CallLongMethod(obj,
- method_id);
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getEventTime = 0;
-static jlong Java_MotionEvent_getEventTime(JNIEnv* env, jobject obj)
- __attribute__ ((unused));
-static jlong Java_MotionEvent_getEventTime(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getEventTime",
- "()J",
- &g_MotionEvent_getEventTime);
-
- jlong ret =
- env->CallLongMethod(obj,
- method_id);
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getXF = 0;
-static jfloat Java_MotionEvent_getXF(JNIEnv* env, jobject obj) __attribute__
- ((unused));
-static jfloat Java_MotionEvent_getXF(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getX",
- "()F",
- &g_MotionEvent_getXF);
-
- jfloat ret =
- env->CallFloatMethod(obj,
- method_id);
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getYF = 0;
-static jfloat Java_MotionEvent_getYF(JNIEnv* env, jobject obj) __attribute__
- ((unused));
-static jfloat Java_MotionEvent_getYF(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getY",
- "()F",
- &g_MotionEvent_getYF);
-
- jfloat ret =
- env->CallFloatMethod(obj,
- method_id);
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getPressureF = 0;
-static jfloat Java_MotionEvent_getPressureF(JNIEnv* env, jobject obj)
- __attribute__ ((unused));
-static jfloat Java_MotionEvent_getPressureF(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getPressure",
- "()F",
- &g_MotionEvent_getPressureF);
-
- jfloat ret =
- env->CallFloatMethod(obj,
- method_id);
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getSizeF = 0;
-static jfloat Java_MotionEvent_getSizeF(JNIEnv* env, jobject obj) __attribute__
- ((unused));
-static jfloat Java_MotionEvent_getSizeF(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getSize",
- "()F",
- &g_MotionEvent_getSizeF);
-
- jfloat ret =
- env->CallFloatMethod(obj,
- method_id);
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getTouchMajorF = 0;
-static jfloat Java_MotionEvent_getTouchMajorF(JNIEnv* env, jobject obj)
- __attribute__ ((unused));
-static jfloat Java_MotionEvent_getTouchMajorF(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getTouchMajor",
- "()F",
- &g_MotionEvent_getTouchMajorF);
-
- jfloat ret =
- env->CallFloatMethod(obj,
- method_id);
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getTouchMinorF = 0;
-static jfloat Java_MotionEvent_getTouchMinorF(JNIEnv* env, jobject obj)
- __attribute__ ((unused));
-static jfloat Java_MotionEvent_getTouchMinorF(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getTouchMinor",
- "()F",
- &g_MotionEvent_getTouchMinorF);
-
- jfloat ret =
- env->CallFloatMethod(obj,
- method_id);
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getToolMajorF = 0;
-static jfloat Java_MotionEvent_getToolMajorF(JNIEnv* env, jobject obj)
- __attribute__ ((unused));
-static jfloat Java_MotionEvent_getToolMajorF(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getToolMajor",
- "()F",
- &g_MotionEvent_getToolMajorF);
-
- jfloat ret =
- env->CallFloatMethod(obj,
- method_id);
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getToolMinorF = 0;
-static jfloat Java_MotionEvent_getToolMinorF(JNIEnv* env, jobject obj)
- __attribute__ ((unused));
-static jfloat Java_MotionEvent_getToolMinorF(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getToolMinor",
- "()F",
- &g_MotionEvent_getToolMinorF);
-
- jfloat ret =
- env->CallFloatMethod(obj,
- method_id);
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getOrientationF = 0;
-static jfloat Java_MotionEvent_getOrientationF(JNIEnv* env, jobject obj)
- __attribute__ ((unused));
-static jfloat Java_MotionEvent_getOrientationF(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getOrientation",
- "()F",
- &g_MotionEvent_getOrientationF);
-
- jfloat ret =
- env->CallFloatMethod(obj,
- method_id);
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getAxisValueF_I = 0;
-static jfloat Java_MotionEvent_getAxisValueF_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getAxisValueF_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getAxisValue",
- "(I)F",
- &g_MotionEvent_getAxisValueF_I);
-
- jfloat ret =
- env->CallFloatMethod(obj,
- method_id, as_jint(p0));
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getPointerCount = 0;
-static jint Java_MotionEvent_getPointerCount(JNIEnv* env, jobject obj)
- __attribute__ ((unused));
-static jint Java_MotionEvent_getPointerCount(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getPointerCount",
- "()I",
- &g_MotionEvent_getPointerCount);
-
- jint ret =
- env->CallIntMethod(obj,
- method_id);
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getPointerId = 0;
-static jint Java_MotionEvent_getPointerId(JNIEnv* env, jobject obj,
- JniIntWrapper p0) __attribute__ ((unused));
-static jint Java_MotionEvent_getPointerId(JNIEnv* env, jobject obj,
- JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getPointerId",
- "(I)I",
- &g_MotionEvent_getPointerId);
-
- jint ret =
- env->CallIntMethod(obj,
- method_id, as_jint(p0));
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getToolType = 0;
-static jint Java_MotionEvent_getToolType(JNIEnv* env, jobject obj, JniIntWrapper
- p0) __attribute__ ((unused));
-static jint Java_MotionEvent_getToolType(JNIEnv* env, jobject obj, JniIntWrapper
- p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getToolType",
- "(I)I",
- &g_MotionEvent_getToolType);
-
- jint ret =
- env->CallIntMethod(obj,
- method_id, as_jint(p0));
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_findPointerIndex = 0;
-static jint Java_MotionEvent_findPointerIndex(JNIEnv* env, jobject obj,
- JniIntWrapper p0) __attribute__ ((unused));
-static jint Java_MotionEvent_findPointerIndex(JNIEnv* env, jobject obj,
- JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "findPointerIndex",
- "(I)I",
- &g_MotionEvent_findPointerIndex);
-
- jint ret =
- env->CallIntMethod(obj,
- method_id, as_jint(p0));
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getXF_I = 0;
-static jfloat Java_MotionEvent_getXF_I(JNIEnv* env, jobject obj, JniIntWrapper
- p0) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getXF_I(JNIEnv* env, jobject obj, JniIntWrapper
- p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getX",
- "(I)F",
- &g_MotionEvent_getXF_I);
-
- jfloat ret =
- env->CallFloatMethod(obj,
- method_id, as_jint(p0));
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getYF_I = 0;
-static jfloat Java_MotionEvent_getYF_I(JNIEnv* env, jobject obj, JniIntWrapper
- p0) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getYF_I(JNIEnv* env, jobject obj, JniIntWrapper
- p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getY",
- "(I)F",
- &g_MotionEvent_getYF_I);
-
- jfloat ret =
- env->CallFloatMethod(obj,
- method_id, as_jint(p0));
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getPressureF_I = 0;
-static jfloat Java_MotionEvent_getPressureF_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getPressureF_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getPressure",
- "(I)F",
- &g_MotionEvent_getPressureF_I);
-
- jfloat ret =
- env->CallFloatMethod(obj,
- method_id, as_jint(p0));
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getSizeF_I = 0;
-static jfloat Java_MotionEvent_getSizeF_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getSizeF_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getSize",
- "(I)F",
- &g_MotionEvent_getSizeF_I);
-
- jfloat ret =
- env->CallFloatMethod(obj,
- method_id, as_jint(p0));
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getTouchMajorF_I = 0;
-static jfloat Java_MotionEvent_getTouchMajorF_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getTouchMajorF_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getTouchMajor",
- "(I)F",
- &g_MotionEvent_getTouchMajorF_I);
-
- jfloat ret =
- env->CallFloatMethod(obj,
- method_id, as_jint(p0));
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getTouchMinorF_I = 0;
-static jfloat Java_MotionEvent_getTouchMinorF_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getTouchMinorF_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getTouchMinor",
- "(I)F",
- &g_MotionEvent_getTouchMinorF_I);
-
- jfloat ret =
- env->CallFloatMethod(obj,
- method_id, as_jint(p0));
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getToolMajorF_I = 0;
-static jfloat Java_MotionEvent_getToolMajorF_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getToolMajorF_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getToolMajor",
- "(I)F",
- &g_MotionEvent_getToolMajorF_I);
-
- jfloat ret =
- env->CallFloatMethod(obj,
- method_id, as_jint(p0));
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getToolMinorF_I = 0;
-static jfloat Java_MotionEvent_getToolMinorF_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getToolMinorF_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getToolMinor",
- "(I)F",
- &g_MotionEvent_getToolMinorF_I);
-
- jfloat ret =
- env->CallFloatMethod(obj,
- method_id, as_jint(p0));
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getOrientationF_I = 0;
-static jfloat Java_MotionEvent_getOrientationF_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getOrientationF_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getOrientation",
- "(I)F",
- &g_MotionEvent_getOrientationF_I);
-
- jfloat ret =
- env->CallFloatMethod(obj,
- method_id, as_jint(p0));
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getAxisValueF_I_I = 0;
-static jfloat Java_MotionEvent_getAxisValueF_I_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0,
- JniIntWrapper p1) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getAxisValueF_I_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0,
- JniIntWrapper p1) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getAxisValue",
- "(II)F",
- &g_MotionEvent_getAxisValueF_I_I);
-
- jfloat ret =
- env->CallFloatMethod(obj,
- method_id, as_jint(p0), as_jint(p1));
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getPointerCoords = 0;
-static void Java_MotionEvent_getPointerCoords(JNIEnv* env, jobject obj,
- JniIntWrapper p0,
- jobject p1) __attribute__ ((unused));
-static void Java_MotionEvent_getPointerCoords(JNIEnv* env, jobject obj,
- JniIntWrapper p0,
- jobject p1) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env));
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getPointerCoords",
- "(ILandroid/view/MotionEvent$PointerCoords;)V",
- &g_MotionEvent_getPointerCoords);
-
- env->CallVoidMethod(obj,
- method_id, as_jint(p0), p1);
- jni_generator::CheckException(env);
-
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getPointerProperties = 0;
-static void Java_MotionEvent_getPointerProperties(JNIEnv* env, jobject obj,
- JniIntWrapper p0,
- jobject p1) __attribute__ ((unused));
-static void Java_MotionEvent_getPointerProperties(JNIEnv* env, jobject obj,
- JniIntWrapper p0,
- jobject p1) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env));
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getPointerProperties",
- "(ILandroid/view/MotionEvent$PointerProperties;)V",
- &g_MotionEvent_getPointerProperties);
-
- env->CallVoidMethod(obj,
- method_id, as_jint(p0), p1);
- jni_generator::CheckException(env);
-
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getMetaState = 0;
-static jint Java_MotionEvent_getMetaState(JNIEnv* env, jobject obj)
- __attribute__ ((unused));
-static jint Java_MotionEvent_getMetaState(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getMetaState",
- "()I",
- &g_MotionEvent_getMetaState);
-
- jint ret =
- env->CallIntMethod(obj,
- method_id);
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getButtonState = 0;
-static jint Java_MotionEvent_getButtonState(JNIEnv* env, jobject obj)
- __attribute__ ((unused));
-static jint Java_MotionEvent_getButtonState(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getButtonState",
- "()I",
- &g_MotionEvent_getButtonState);
-
- jint ret =
- env->CallIntMethod(obj,
- method_id);
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getRawX = 0;
-static jfloat Java_MotionEvent_getRawX(JNIEnv* env, jobject obj) __attribute__
- ((unused));
-static jfloat Java_MotionEvent_getRawX(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getRawX",
- "()F",
- &g_MotionEvent_getRawX);
-
- jfloat ret =
- env->CallFloatMethod(obj,
- method_id);
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getRawY = 0;
-static jfloat Java_MotionEvent_getRawY(JNIEnv* env, jobject obj) __attribute__
- ((unused));
-static jfloat Java_MotionEvent_getRawY(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getRawY",
- "()F",
- &g_MotionEvent_getRawY);
-
- jfloat ret =
- env->CallFloatMethod(obj,
- method_id);
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getXPrecision = 0;
-static jfloat Java_MotionEvent_getXPrecision(JNIEnv* env, jobject obj)
- __attribute__ ((unused));
-static jfloat Java_MotionEvent_getXPrecision(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getXPrecision",
- "()F",
- &g_MotionEvent_getXPrecision);
-
- jfloat ret =
- env->CallFloatMethod(obj,
- method_id);
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getYPrecision = 0;
-static jfloat Java_MotionEvent_getYPrecision(JNIEnv* env, jobject obj)
- __attribute__ ((unused));
-static jfloat Java_MotionEvent_getYPrecision(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getYPrecision",
- "()F",
- &g_MotionEvent_getYPrecision);
-
- jfloat ret =
- env->CallFloatMethod(obj,
- method_id);
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getHistorySize = 0;
-static jint Java_MotionEvent_getHistorySize(JNIEnv* env, jobject obj)
- __attribute__ ((unused));
-static jint Java_MotionEvent_getHistorySize(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getHistorySize",
- "()I",
- &g_MotionEvent_getHistorySize);
-
- jint ret =
- env->CallIntMethod(obj,
- method_id);
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getHistoricalEventTime = 0;
-static jlong Java_MotionEvent_getHistoricalEventTime(JNIEnv* env, jobject obj,
- JniIntWrapper p0) __attribute__ ((unused));
-static jlong Java_MotionEvent_getHistoricalEventTime(JNIEnv* env, jobject obj,
- JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getHistoricalEventTime",
- "(I)J",
- &g_MotionEvent_getHistoricalEventTime);
-
- jlong ret =
- env->CallLongMethod(obj,
- method_id, as_jint(p0));
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getHistoricalXF_I = 0;
-static jfloat Java_MotionEvent_getHistoricalXF_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getHistoricalXF_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getHistoricalX",
- "(I)F",
- &g_MotionEvent_getHistoricalXF_I);
-
- jfloat ret =
- env->CallFloatMethod(obj,
- method_id, as_jint(p0));
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getHistoricalYF_I = 0;
-static jfloat Java_MotionEvent_getHistoricalYF_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getHistoricalYF_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getHistoricalY",
- "(I)F",
- &g_MotionEvent_getHistoricalYF_I);
-
- jfloat ret =
- env->CallFloatMethod(obj,
- method_id, as_jint(p0));
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getHistoricalPressureF_I = 0;
-static jfloat Java_MotionEvent_getHistoricalPressureF_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getHistoricalPressureF_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getHistoricalPressure",
- "(I)F",
- &g_MotionEvent_getHistoricalPressureF_I);
-
- jfloat ret =
- env->CallFloatMethod(obj,
- method_id, as_jint(p0));
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getHistoricalSizeF_I = 0;
-static jfloat Java_MotionEvent_getHistoricalSizeF_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getHistoricalSizeF_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getHistoricalSize",
- "(I)F",
- &g_MotionEvent_getHistoricalSizeF_I);
-
- jfloat ret =
- env->CallFloatMethod(obj,
- method_id, as_jint(p0));
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getHistoricalTouchMajorF_I = 0;
-static jfloat Java_MotionEvent_getHistoricalTouchMajorF_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getHistoricalTouchMajorF_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getHistoricalTouchMajor",
- "(I)F",
- &g_MotionEvent_getHistoricalTouchMajorF_I);
-
- jfloat ret =
- env->CallFloatMethod(obj,
- method_id, as_jint(p0));
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getHistoricalTouchMinorF_I = 0;
-static jfloat Java_MotionEvent_getHistoricalTouchMinorF_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getHistoricalTouchMinorF_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getHistoricalTouchMinor",
- "(I)F",
- &g_MotionEvent_getHistoricalTouchMinorF_I);
-
- jfloat ret =
- env->CallFloatMethod(obj,
- method_id, as_jint(p0));
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getHistoricalToolMajorF_I = 0;
-static jfloat Java_MotionEvent_getHistoricalToolMajorF_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getHistoricalToolMajorF_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getHistoricalToolMajor",
- "(I)F",
- &g_MotionEvent_getHistoricalToolMajorF_I);
-
- jfloat ret =
- env->CallFloatMethod(obj,
- method_id, as_jint(p0));
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getHistoricalToolMinorF_I = 0;
-static jfloat Java_MotionEvent_getHistoricalToolMinorF_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getHistoricalToolMinorF_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getHistoricalToolMinor",
- "(I)F",
- &g_MotionEvent_getHistoricalToolMinorF_I);
-
- jfloat ret =
- env->CallFloatMethod(obj,
- method_id, as_jint(p0));
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getHistoricalOrientationF_I = 0;
-static jfloat Java_MotionEvent_getHistoricalOrientationF_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getHistoricalOrientationF_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getHistoricalOrientation",
- "(I)F",
- &g_MotionEvent_getHistoricalOrientationF_I);
-
- jfloat ret =
- env->CallFloatMethod(obj,
- method_id, as_jint(p0));
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getHistoricalAxisValueF_I_I = 0;
-static jfloat Java_MotionEvent_getHistoricalAxisValueF_I_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0,
- JniIntWrapper p1) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getHistoricalAxisValueF_I_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0,
- JniIntWrapper p1) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getHistoricalAxisValue",
- "(II)F",
- &g_MotionEvent_getHistoricalAxisValueF_I_I);
-
- jfloat ret =
- env->CallFloatMethod(obj,
- method_id, as_jint(p0), as_jint(p1));
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getHistoricalXF_I_I = 0;
-static jfloat Java_MotionEvent_getHistoricalXF_I_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0,
- JniIntWrapper p1) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getHistoricalXF_I_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0,
- JniIntWrapper p1) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getHistoricalX",
- "(II)F",
- &g_MotionEvent_getHistoricalXF_I_I);
-
- jfloat ret =
- env->CallFloatMethod(obj,
- method_id, as_jint(p0), as_jint(p1));
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getHistoricalYF_I_I = 0;
-static jfloat Java_MotionEvent_getHistoricalYF_I_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0,
- JniIntWrapper p1) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getHistoricalYF_I_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0,
- JniIntWrapper p1) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getHistoricalY",
- "(II)F",
- &g_MotionEvent_getHistoricalYF_I_I);
-
- jfloat ret =
- env->CallFloatMethod(obj,
- method_id, as_jint(p0), as_jint(p1));
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getHistoricalPressureF_I_I = 0;
-static jfloat Java_MotionEvent_getHistoricalPressureF_I_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0,
- JniIntWrapper p1) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getHistoricalPressureF_I_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0,
- JniIntWrapper p1) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getHistoricalPressure",
- "(II)F",
- &g_MotionEvent_getHistoricalPressureF_I_I);
-
- jfloat ret =
- env->CallFloatMethod(obj,
- method_id, as_jint(p0), as_jint(p1));
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getHistoricalSizeF_I_I = 0;
-static jfloat Java_MotionEvent_getHistoricalSizeF_I_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0,
- JniIntWrapper p1) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getHistoricalSizeF_I_I(JNIEnv* env, jobject obj,
- JniIntWrapper p0,
- JniIntWrapper p1) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getHistoricalSize",
- "(II)F",
- &g_MotionEvent_getHistoricalSizeF_I_I);
-
- jfloat ret =
- env->CallFloatMethod(obj,
- method_id, as_jint(p0), as_jint(p1));
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getHistoricalTouchMajorF_I_I = 0;
-static jfloat Java_MotionEvent_getHistoricalTouchMajorF_I_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0,
- JniIntWrapper p1) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getHistoricalTouchMajorF_I_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0,
- JniIntWrapper p1) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getHistoricalTouchMajor",
- "(II)F",
- &g_MotionEvent_getHistoricalTouchMajorF_I_I);
-
- jfloat ret =
- env->CallFloatMethod(obj,
- method_id, as_jint(p0), as_jint(p1));
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getHistoricalTouchMinorF_I_I = 0;
-static jfloat Java_MotionEvent_getHistoricalTouchMinorF_I_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0,
- JniIntWrapper p1) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getHistoricalTouchMinorF_I_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0,
- JniIntWrapper p1) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getHistoricalTouchMinor",
- "(II)F",
- &g_MotionEvent_getHistoricalTouchMinorF_I_I);
-
- jfloat ret =
- env->CallFloatMethod(obj,
- method_id, as_jint(p0), as_jint(p1));
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getHistoricalToolMajorF_I_I = 0;
-static jfloat Java_MotionEvent_getHistoricalToolMajorF_I_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0,
- JniIntWrapper p1) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getHistoricalToolMajorF_I_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0,
- JniIntWrapper p1) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getHistoricalToolMajor",
- "(II)F",
- &g_MotionEvent_getHistoricalToolMajorF_I_I);
-
- jfloat ret =
- env->CallFloatMethod(obj,
- method_id, as_jint(p0), as_jint(p1));
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getHistoricalToolMinorF_I_I = 0;
-static jfloat Java_MotionEvent_getHistoricalToolMinorF_I_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0,
- JniIntWrapper p1) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getHistoricalToolMinorF_I_I(JNIEnv* env, jobject
- obj, JniIntWrapper p0,
- JniIntWrapper p1) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getHistoricalToolMinor",
- "(II)F",
- &g_MotionEvent_getHistoricalToolMinorF_I_I);
-
- jfloat ret =
- env->CallFloatMethod(obj,
- method_id, as_jint(p0), as_jint(p1));
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getHistoricalOrientationF_I_I = 0;
-static jfloat Java_MotionEvent_getHistoricalOrientationF_I_I(JNIEnv* env,
- jobject obj, JniIntWrapper p0,
- JniIntWrapper p1) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getHistoricalOrientationF_I_I(JNIEnv* env,
- jobject obj, JniIntWrapper p0,
- JniIntWrapper p1) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getHistoricalOrientation",
- "(II)F",
- &g_MotionEvent_getHistoricalOrientationF_I_I);
-
- jfloat ret =
- env->CallFloatMethod(obj,
- method_id, as_jint(p0), as_jint(p1));
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getHistoricalAxisValueF_I_I_I = 0;
-static jfloat Java_MotionEvent_getHistoricalAxisValueF_I_I_I(JNIEnv* env,
- jobject obj, JniIntWrapper p0,
- JniIntWrapper p1,
- JniIntWrapper p2) __attribute__ ((unused));
-static jfloat Java_MotionEvent_getHistoricalAxisValueF_I_I_I(JNIEnv* env,
- jobject obj, JniIntWrapper p0,
- JniIntWrapper p1,
- JniIntWrapper p2) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getHistoricalAxisValue",
- "(III)F",
- &g_MotionEvent_getHistoricalAxisValueF_I_I_I);
-
- jfloat ret =
- env->CallFloatMethod(obj,
- method_id, as_jint(p0), as_jint(p1), as_jint(p2));
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getHistoricalPointerCoords = 0;
-static void Java_MotionEvent_getHistoricalPointerCoords(JNIEnv* env, jobject
- obj, JniIntWrapper p0,
- JniIntWrapper p1,
- jobject p2) __attribute__ ((unused));
-static void Java_MotionEvent_getHistoricalPointerCoords(JNIEnv* env, jobject
- obj, JniIntWrapper p0,
- JniIntWrapper p1,
- jobject p2) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env));
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getHistoricalPointerCoords",
- "(IILandroid/view/MotionEvent$PointerCoords;)V",
- &g_MotionEvent_getHistoricalPointerCoords);
-
- env->CallVoidMethod(obj,
- method_id, as_jint(p0), as_jint(p1), p2);
- jni_generator::CheckException(env);
-
-}
-
-static base::subtle::AtomicWord g_MotionEvent_getEdgeFlags = 0;
-static jint Java_MotionEvent_getEdgeFlags(JNIEnv* env, jobject obj)
- __attribute__ ((unused));
-static jint Java_MotionEvent_getEdgeFlags(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "getEdgeFlags",
- "()I",
- &g_MotionEvent_getEdgeFlags);
-
- jint ret =
- env->CallIntMethod(obj,
- method_id);
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_setEdgeFlags = 0;
-static void Java_MotionEvent_setEdgeFlags(JNIEnv* env, jobject obj,
- JniIntWrapper p0) __attribute__ ((unused));
-static void Java_MotionEvent_setEdgeFlags(JNIEnv* env, jobject obj,
- JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env));
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "setEdgeFlags",
- "(I)V",
- &g_MotionEvent_setEdgeFlags);
-
- env->CallVoidMethod(obj,
- method_id, as_jint(p0));
- jni_generator::CheckException(env);
-
-}
-
-static base::subtle::AtomicWord g_MotionEvent_setAction = 0;
-static void Java_MotionEvent_setAction(JNIEnv* env, jobject obj, JniIntWrapper
- p0) __attribute__ ((unused));
-static void Java_MotionEvent_setAction(JNIEnv* env, jobject obj, JniIntWrapper
- p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env));
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "setAction",
- "(I)V",
- &g_MotionEvent_setAction);
-
- env->CallVoidMethod(obj,
- method_id, as_jint(p0));
- jni_generator::CheckException(env);
-
-}
-
-static base::subtle::AtomicWord g_MotionEvent_offsetLocation = 0;
-static void Java_MotionEvent_offsetLocation(JNIEnv* env, jobject obj, jfloat p0,
- jfloat p1) __attribute__ ((unused));
-static void Java_MotionEvent_offsetLocation(JNIEnv* env, jobject obj, jfloat p0,
- jfloat p1) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env));
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "offsetLocation",
- "(FF)V",
- &g_MotionEvent_offsetLocation);
-
- env->CallVoidMethod(obj,
- method_id, p0, p1);
- jni_generator::CheckException(env);
-
-}
-
-static base::subtle::AtomicWord g_MotionEvent_setLocation = 0;
-static void Java_MotionEvent_setLocation(JNIEnv* env, jobject obj, jfloat p0,
- jfloat p1) __attribute__ ((unused));
-static void Java_MotionEvent_setLocation(JNIEnv* env, jobject obj, jfloat p0,
- jfloat p1) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env));
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "setLocation",
- "(FF)V",
- &g_MotionEvent_setLocation);
-
- env->CallVoidMethod(obj,
- method_id, p0, p1);
- jni_generator::CheckException(env);
-
-}
-
-static base::subtle::AtomicWord g_MotionEvent_transform = 0;
-static void Java_MotionEvent_transform(JNIEnv* env, jobject obj, jobject p0)
- __attribute__ ((unused));
-static void Java_MotionEvent_transform(JNIEnv* env, jobject obj, jobject p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env));
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "transform",
- "(Landroid/graphics/Matrix;)V",
- &g_MotionEvent_transform);
-
- env->CallVoidMethod(obj,
- method_id, p0);
- jni_generator::CheckException(env);
-
-}
-
-static base::subtle::AtomicWord g_MotionEvent_addBatchV_J_F_F_F_F_I = 0;
-static void Java_MotionEvent_addBatchV_J_F_F_F_F_I(JNIEnv* env, jobject obj,
- jlong p0,
- jfloat p1,
- jfloat p2,
- jfloat p3,
- jfloat p4,
- JniIntWrapper p5) __attribute__ ((unused));
-static void Java_MotionEvent_addBatchV_J_F_F_F_F_I(JNIEnv* env, jobject obj,
- jlong p0,
- jfloat p1,
- jfloat p2,
- jfloat p3,
- jfloat p4,
- JniIntWrapper p5) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env));
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "addBatch",
- "(JFFFFI)V",
- &g_MotionEvent_addBatchV_J_F_F_F_F_I);
-
- env->CallVoidMethod(obj,
- method_id, p0, p1, p2, p3, p4, as_jint(p5));
- jni_generator::CheckException(env);
-
-}
-
-static base::subtle::AtomicWord g_MotionEvent_addBatchV_J_LAVMEPC_I = 0;
-static void Java_MotionEvent_addBatchV_J_LAVMEPC_I(JNIEnv* env, jobject obj,
- jlong p0,
- jobjectArray p1,
- JniIntWrapper p2) __attribute__ ((unused));
-static void Java_MotionEvent_addBatchV_J_LAVMEPC_I(JNIEnv* env, jobject obj,
- jlong p0,
- jobjectArray p1,
- JniIntWrapper p2) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env));
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "addBatch",
- "(J[Landroid/view/MotionEvent$PointerCoords;I)V",
- &g_MotionEvent_addBatchV_J_LAVMEPC_I);
-
- env->CallVoidMethod(obj,
- method_id, p0, p1, as_jint(p2));
- jni_generator::CheckException(env);
-
-}
-
-static base::subtle::AtomicWord g_MotionEvent_toString = 0;
-static base::android::ScopedJavaLocalRef<jstring>
- Java_MotionEvent_toString(JNIEnv* env, jobject obj) __attribute__
- ((unused));
-static base::android::ScopedJavaLocalRef<jstring>
- Java_MotionEvent_toString(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env), NULL);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "toString",
- "()Ljava/lang/String;",
- &g_MotionEvent_toString);
-
- jstring ret =
- static_cast<jstring>(env->CallObjectMethod(obj,
- method_id));
- jni_generator::CheckException(env);
- return base::android::ScopedJavaLocalRef<jstring>(env, ret);
-}
-
-static base::subtle::AtomicWord g_MotionEvent_actionToString = 0;
-static base::android::ScopedJavaLocalRef<jstring>
- Java_MotionEvent_actionToString(JNIEnv* env, JniIntWrapper p0) __attribute__
- ((unused));
-static base::android::ScopedJavaLocalRef<jstring>
- Java_MotionEvent_actionToString(JNIEnv* env, JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, MotionEvent_clazz(env),
- MotionEvent_clazz(env), NULL);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_STATIC>(
- env, MotionEvent_clazz(env),
- "actionToString",
- "(I)Ljava/lang/String;",
- &g_MotionEvent_actionToString);
-
- jstring ret =
- static_cast<jstring>(env->CallStaticObjectMethod(MotionEvent_clazz(env),
- method_id, as_jint(p0)));
- jni_generator::CheckException(env);
- return base::android::ScopedJavaLocalRef<jstring>(env, ret);
-}
-
-static base::subtle::AtomicWord g_MotionEvent_axisToString = 0;
-static base::android::ScopedJavaLocalRef<jstring>
- Java_MotionEvent_axisToString(JNIEnv* env, JniIntWrapper p0) __attribute__
- ((unused));
-static base::android::ScopedJavaLocalRef<jstring>
- Java_MotionEvent_axisToString(JNIEnv* env, JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, MotionEvent_clazz(env),
- MotionEvent_clazz(env), NULL);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_STATIC>(
- env, MotionEvent_clazz(env),
- "axisToString",
- "(I)Ljava/lang/String;",
- &g_MotionEvent_axisToString);
-
- jstring ret =
- static_cast<jstring>(env->CallStaticObjectMethod(MotionEvent_clazz(env),
- method_id, as_jint(p0)));
- jni_generator::CheckException(env);
- return base::android::ScopedJavaLocalRef<jstring>(env, ret);
-}
-
-static base::subtle::AtomicWord g_MotionEvent_axisFromString = 0;
-static jint Java_MotionEvent_axisFromString(JNIEnv* env, jstring p0)
- __attribute__ ((unused));
-static jint Java_MotionEvent_axisFromString(JNIEnv* env, jstring p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, MotionEvent_clazz(env),
- MotionEvent_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_STATIC>(
- env, MotionEvent_clazz(env),
- "axisFromString",
- "(Ljava/lang/String;)I",
- &g_MotionEvent_axisFromString);
-
- jint ret =
- env->CallStaticIntMethod(MotionEvent_clazz(env),
- method_id, p0);
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_MotionEvent_writeToParcel = 0;
-static void Java_MotionEvent_writeToParcel(JNIEnv* env, jobject obj, jobject p0,
- JniIntWrapper p1) __attribute__ ((unused));
-static void Java_MotionEvent_writeToParcel(JNIEnv* env, jobject obj, jobject p0,
- JniIntWrapper p1) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- MotionEvent_clazz(env));
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, MotionEvent_clazz(env),
- "writeToParcel",
- "(Landroid/os/Parcel;I)V",
- &g_MotionEvent_writeToParcel);
-
- env->CallVoidMethod(obj,
- method_id, p0, as_jint(p1));
- jni_generator::CheckException(env);
-
-}
-
-// Step 3: RegisterNatives.
-
-static bool RegisterNativesImpl(JNIEnv* env) {
-
- g_MotionEvent_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
- base::android::GetClass(env, kMotionEventClassPath).obj()));
-
- return true;
-}
-
-} // namespace JNI_MotionEvent
-
-#endif // android_view_MotionEvent_JNI
diff --git a/base/android/jni_generator/testEagerCalledByNativesOption.golden b/base/android/jni_generator/testEagerCalledByNativesOption.golden
deleted file mode 100644
index 19108bfe68..0000000000
--- a/base/android/jni_generator/testEagerCalledByNativesOption.golden
+++ /dev/null
@@ -1,146 +0,0 @@
-// Copyright 2014 The Chromium 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.py
-// For
-// org/chromium/example/jni_generator/Test
-
-#ifndef org_chromium_example_jni_generator_Test_JNI
-#define org_chromium_example_jni_generator_Test_JNI
-
-#include <jni.h>
-
-#include "base/android/jni_generator/jni_generator_helper.h"
-
-#include "base/android/jni_int_wrapper.h"
-
-// Step 1: forward declarations.
-namespace {
-const char kTestClassPath[] = "org/chromium/example/jni_generator/Test";
-// Leaking this jclass as we cannot use LazyInstance from some threads.
-jclass g_Test_clazz = NULL;
-#define Test_clazz(env) g_Test_clazz
-jmethodID g_Test_testMethodWithParam = NULL;
-jmethodID g_Test_testStaticMethodWithParam = NULL;
-jmethodID g_Test_testMethodWithNoParam = NULL;
-jmethodID g_Test_testStaticMethodWithNoParam = NULL;
-} // namespace
-
-// Step 2: method stubs.
-static jint Method(JNIEnv* env, jobject jcaller,
- jlong nativeTest,
- jint arg1) {
- Test* native = reinterpret_cast<Test*>(nativeTest);
- CHECK_NATIVE_PTR(env, jcaller, native, "Method", 0);
- return native->Method(env, jcaller, arg1);
-}
-
-namespace {
-
-static void testMethodWithParam(JNIEnv* env, jobject obj, JniIntWrapper iParam)
- {
- env->CallVoidMethod(obj,
- g_Test_testMethodWithParam, as_jint(iParam));
-
-}
-
-static jint testStaticMethodWithParam(JNIEnv* env, JniIntWrapper iParam) {
- jint ret = env->CallStaticIntMethod(Test_clazz(env),
- g_Test_testStaticMethodWithParam, as_jint(iParam));
- return ret;
-}
-
-static jdouble testMethodWithNoParam(JNIEnv* env) {
- jdouble ret = env->CallStaticDoubleMethod(Test_clazz(env),
- g_Test_testMethodWithNoParam);
- return ret;
-}
-
-static base::android::ScopedJavaLocalRef<jstring>
- testStaticMethodWithNoParam(JNIEnv* env) {
- jstring ret =
- static_cast<jstring>(env->CallStaticObjectMethod(Test_clazz(env),
- g_Test_testStaticMethodWithNoParam));
- return base::android::ScopedJavaLocalRef<jstring>(env, ret);
-}
-} // namespace
-
-// Step 3: RegisterNatives.
-
-static const JNINativeMethod kMethodsTest[] = {
- { "nativeMethod",
-"("
-"J"
-"I"
-")"
-"I", reinterpret_cast<void*>(Method) },
-};
-
-static bool RegisterNativesImpl(JNIEnv* env, jclass clazz) {
-
- g_Test_clazz = static_cast<jclass>(env->NewWeakGlobalRef(clazz));
-
- const int kMethodsTestSize = arraysize(kMethodsTest);
-
- if (env->RegisterNatives(Test_clazz(env),
- kMethodsTest,
- kMethodsTestSize) < 0) {
- jni_generator::HandleRegistrationError(
- env, Test_clazz(env), __FILE__);
- return false;
- }
-
- g_Test_testMethodWithParam = env->GetMethodID(
- Test_clazz(env),
- "testMethodWithParam",
-"("
-"I"
-")"
-"V");
- if (g_Test_testMethodWithParam == NULL) {
- return false;
- }
-
- g_Test_testStaticMethodWithParam = env->GetStaticMethodID(
- Test_clazz(env),
- "testStaticMethodWithParam",
-"("
-"I"
-")"
-"I");
- if (g_Test_testStaticMethodWithParam == NULL) {
- return false;
- }
-
- g_Test_testMethodWithNoParam = env->GetStaticMethodID(
- Test_clazz(env),
- "testMethodWithNoParam",
-"("
-")"
-"D");
- if (g_Test_testMethodWithNoParam == NULL) {
- return false;
- }
-
- g_Test_testStaticMethodWithNoParam = env->GetStaticMethodID(
- Test_clazz(env),
- "testStaticMethodWithNoParam",
-"("
-")"
-"Ljava/lang/String;");
- if (g_Test_testStaticMethodWithNoParam == NULL) {
- return false;
- }
-
- return true;
-}
-
-extern "C" JNIEXPORT bool JNICALL
-Java_org_chromium_example_jni_generator_Test_nativeInitNativeClass(JNIEnv* env,
- jclass clazz) {
- return RegisterNativesImpl(env, clazz);
-}
-
-#endif // org_chromium_example_jni_generator_Test_JNI
diff --git a/base/android/jni_generator/testFromJavaP.golden b/base/android/jni_generator/testFromJavaP.golden
deleted file mode 100644
index b7276bc293..0000000000
--- a/base/android/jni_generator/testFromJavaP.golden
+++ /dev/null
@@ -1,267 +0,0 @@
-// Copyright 2014 The Chromium 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.py
-// For
-// java/io/InputStream
-
-#ifndef java_io_InputStream_JNI
-#define java_io_InputStream_JNI
-
-#include <jni.h>
-
-#include "base/android/jni_generator/jni_generator_helper.h"
-
-#include "base/android/jni_int_wrapper.h"
-
-// 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;
-#define InputStream_clazz(env) g_InputStream_clazz
-
-} // 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() */
- CHECK_CLAZZ(env, obj,
- InputStream_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, InputStream_clazz(env),
- "available",
- "()I",
- &g_InputStream_available);
-
- jint ret =
- env->CallIntMethod(obj,
- method_id);
- jni_generator::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() */
- CHECK_CLAZZ(env, obj,
- InputStream_clazz(env));
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, InputStream_clazz(env),
- "close",
- "()V",
- &g_InputStream_close);
-
- env->CallVoidMethod(obj,
- method_id);
- jni_generator::CheckException(env);
-
-}
-
-static base::subtle::AtomicWord g_InputStream_mark = 0;
-static void Java_InputStream_mark(JNIEnv* env, jobject obj, JniIntWrapper p0)
- __attribute__ ((unused));
-static void Java_InputStream_mark(JNIEnv* env, jobject obj, JniIntWrapper p0) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- InputStream_clazz(env));
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, InputStream_clazz(env),
- "mark",
- "(I)V",
- &g_InputStream_mark);
-
- env->CallVoidMethod(obj,
- method_id, as_jint(p0));
- jni_generator::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() */
- CHECK_CLAZZ(env, obj,
- InputStream_clazz(env), false);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, InputStream_clazz(env),
- "markSupported",
- "()Z",
- &g_InputStream_markSupported);
-
- jboolean ret =
- env->CallBooleanMethod(obj,
- method_id);
- jni_generator::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() */
- CHECK_CLAZZ(env, obj,
- InputStream_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, InputStream_clazz(env),
- "read",
- "()I",
- &g_InputStream_readI);
-
- jint ret =
- env->CallIntMethod(obj,
- method_id);
- jni_generator::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() */
- CHECK_CLAZZ(env, obj,
- InputStream_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, InputStream_clazz(env),
- "read",
- "([B)I",
- &g_InputStream_readI_AB);
-
- jint ret =
- env->CallIntMethod(obj,
- method_id, p0);
- jni_generator::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,
- JniIntWrapper p1,
- JniIntWrapper p2) __attribute__ ((unused));
-static jint Java_InputStream_readI_AB_I_I(JNIEnv* env, jobject obj, jbyteArray
- p0,
- JniIntWrapper p1,
- JniIntWrapper p2) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- InputStream_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, InputStream_clazz(env),
- "read",
- "([BII)I",
- &g_InputStream_readI_AB_I_I);
-
- jint ret =
- env->CallIntMethod(obj,
- method_id, p0, as_jint(p1), as_jint(p2));
- jni_generator::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() */
- CHECK_CLAZZ(env, obj,
- InputStream_clazz(env));
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, InputStream_clazz(env),
- "reset",
- "()V",
- &g_InputStream_reset);
-
- env->CallVoidMethod(obj,
- method_id);
- jni_generator::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() */
- CHECK_CLAZZ(env, obj,
- InputStream_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, InputStream_clazz(env),
- "skip",
- "(J)J",
- &g_InputStream_skip);
-
- jlong ret =
- env->CallLongMethod(obj,
- method_id, p0);
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_InputStream_Constructor = 0;
-static base::android::ScopedJavaLocalRef<jobject>
- Java_InputStream_Constructor(JNIEnv* env) __attribute__ ((unused));
-static base::android::ScopedJavaLocalRef<jobject>
- Java_InputStream_Constructor(JNIEnv* env) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, InputStream_clazz(env),
- InputStream_clazz(env), NULL);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, InputStream_clazz(env),
- "<init>",
- "()V",
- &g_InputStream_Constructor);
-
- jobject ret =
- env->NewObject(InputStream_clazz(env),
- method_id);
- jni_generator::CheckException(env);
- return base::android::ScopedJavaLocalRef<jobject>(env, ret);
-}
-
-// Step 3: RegisterNatives.
-
-static bool RegisterNativesImpl(JNIEnv* env) {
-
- g_InputStream_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
- base::android::GetClass(env, kInputStreamClassPath).obj()));
-
- return true;
-}
-
-} // namespace JNI_InputStream
-
-#endif // java_io_InputStream_JNI
diff --git a/base/android/jni_generator/testFromJavaPGenerics.golden b/base/android/jni_generator/testFromJavaPGenerics.golden
deleted file mode 100644
index 489872cace..0000000000
--- a/base/android/jni_generator/testFromJavaPGenerics.golden
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2014 The Chromium 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.py
-// For
-// java/util/HashSet
-
-#ifndef java_util_HashSet_JNI
-#define java_util_HashSet_JNI
-
-#include <jni.h>
-
-#include "base/android/jni_generator/jni_generator_helper.h"
-
-#include "base/android/jni_int_wrapper.h"
-
-// Step 1: forward declarations.
-namespace {
-const char kHashSetClassPath[] = "java/util/HashSet";
-// Leaking this jclass as we cannot use LazyInstance from some threads.
-jclass g_HashSet_clazz = NULL;
-#define HashSet_clazz(env) g_HashSet_clazz
-
-} // namespace
-
-namespace JNI_HashSet {
-
-// Step 2: method stubs.
-
-static base::subtle::AtomicWord g_HashSet_dummy = 0;
-static void Java_HashSet_dummy(JNIEnv* env, jobject obj) __attribute__
- ((unused));
-static void Java_HashSet_dummy(JNIEnv* env, jobject obj) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- HashSet_clazz(env));
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, HashSet_clazz(env),
- "dummy",
- "()V",
- &g_HashSet_dummy);
-
- env->CallVoidMethod(obj,
- method_id);
- jni_generator::CheckException(env);
-
-}
-
-// Step 3: RegisterNatives.
-
-static bool RegisterNativesImpl(JNIEnv* env) {
-
- g_HashSet_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
- base::android::GetClass(env, kHashSetClassPath).obj()));
-
- return true;
-}
-
-} // namespace JNI_HashSet
-
-#endif // java_util_HashSet_JNI
diff --git a/base/android/jni_generator/testInnerClassNatives.golden b/base/android/jni_generator/testInnerClassNatives.golden
deleted file mode 100644
index 5a525ef85e..0000000000
--- a/base/android/jni_generator/testInnerClassNatives.golden
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2014 The Chromium 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.py
-// For
-// org/chromium/TestJni
-
-#ifndef org_chromium_TestJni_JNI
-#define org_chromium_TestJni_JNI
-
-#include <jni.h>
-
-#include "base/android/jni_generator/jni_generator_helper.h"
-
-#include "base/android/jni_int_wrapper.h"
-
-// 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;
-#define TestJni_clazz(env) g_TestJni_clazz
-
-} // namespace
-
-static jint Init(JNIEnv* env, jobject jcaller);
-
-// Step 2: method stubs.
-
-// Step 3: RegisterNatives.
-
-static const JNINativeMethod kMethodsMyInnerClass[] = {
- { "nativeInit",
-"("
-")"
-"I", reinterpret_cast<void*>(Init) },
-};
-
-static bool RegisterNativesImpl(JNIEnv* env) {
-
- g_TestJni_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
- base::android::GetClass(env, kTestJniClassPath).obj()));
-
- const int kMethodsMyInnerClassSize = arraysize(kMethodsMyInnerClass);
-
- if (env->RegisterNatives(MyInnerClass_clazz(env),
- kMethodsMyInnerClass,
- kMethodsMyInnerClassSize) < 0) {
- jni_generator::HandleRegistrationError(
- env, MyInnerClass_clazz(env), __FILE__);
- return false;
- }
-
- return true;
-}
-
-#endif // org_chromium_TestJni_JNI
diff --git a/base/android/jni_generator/testInnerClassNativesBothInnerAndOuter.golden b/base/android/jni_generator/testInnerClassNativesBothInnerAndOuter.golden
deleted file mode 100644
index c8d4b3cdd4..0000000000
--- a/base/android/jni_generator/testInnerClassNativesBothInnerAndOuter.golden
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright 2014 The Chromium 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.py
-// For
-// org/chromium/TestJni
-
-#ifndef org_chromium_TestJni_JNI
-#define org_chromium_TestJni_JNI
-
-#include <jni.h>
-
-#include "base/android/jni_generator/jni_generator_helper.h"
-
-#include "base/android/jni_int_wrapper.h"
-
-// 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;
-#define TestJni_clazz(env) g_TestJni_clazz
-
-} // namespace
-
-static jint Init(JNIEnv* env, jobject jcaller);
-
-static jint Init(JNIEnv* env, jobject jcaller);
-
-// Step 2: method stubs.
-
-// Step 3: RegisterNatives.
-
-static const JNINativeMethod kMethodsMyOtherInnerClass[] = {
- { "nativeInit",
-"("
-")"
-"I", reinterpret_cast<void*>(Init) },
-};
-
-static const JNINativeMethod kMethodsTestJni[] = {
- { "nativeInit",
-"("
-")"
-"I", reinterpret_cast<void*>(Init) },
-};
-
-static bool RegisterNativesImpl(JNIEnv* env) {
-
- g_TestJni_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
- base::android::GetClass(env, kTestJniClassPath).obj()));
-
- const int kMethodsMyOtherInnerClassSize =
- arraysize(kMethodsMyOtherInnerClass);
-
- if (env->RegisterNatives(MyOtherInnerClass_clazz(env),
- kMethodsMyOtherInnerClass,
- kMethodsMyOtherInnerClassSize) < 0) {
- jni_generator::HandleRegistrationError(
- env, MyOtherInnerClass_clazz(env), __FILE__);
- return false;
- }
-
- const int kMethodsTestJniSize = arraysize(kMethodsTestJni);
-
- if (env->RegisterNatives(TestJni_clazz(env),
- kMethodsTestJni,
- kMethodsTestJniSize) < 0) {
- jni_generator::HandleRegistrationError(
- env, TestJni_clazz(env), __FILE__);
- return false;
- }
-
- return true;
-}
-
-#endif // org_chromium_TestJni_JNI
diff --git a/base/android/jni_generator/testInnerClassNativesMultiple.golden b/base/android/jni_generator/testInnerClassNativesMultiple.golden
deleted file mode 100644
index 42643ae32c..0000000000
--- a/base/android/jni_generator/testInnerClassNativesMultiple.golden
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2014 The Chromium 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.py
-// For
-// org/chromium/TestJni
-
-#ifndef org_chromium_TestJni_JNI
-#define org_chromium_TestJni_JNI
-
-#include <jni.h>
-
-#include "base/android/jni_generator/jni_generator_helper.h"
-
-#include "base/android/jni_int_wrapper.h"
-
-// 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;
-#define TestJni_clazz(env) g_TestJni_clazz
-
-} // namespace
-
-static jint Init(JNIEnv* env, jobject jcaller);
-
-static jint Init(JNIEnv* env, jobject jcaller);
-
-// Step 2: method stubs.
-
-// Step 3: RegisterNatives.
-
-static const JNINativeMethod kMethodsMyOtherInnerClass[] = {
- { "nativeInit",
-"("
-")"
-"I", reinterpret_cast<void*>(Init) },
-};
-
-static const JNINativeMethod kMethodsMyInnerClass[] = {
- { "nativeInit",
-"("
-")"
-"I", reinterpret_cast<void*>(Init) },
-};
-
-static bool RegisterNativesImpl(JNIEnv* env) {
-
- g_TestJni_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
- base::android::GetClass(env, kTestJniClassPath).obj()));
-
- const int kMethodsMyOtherInnerClassSize =
- arraysize(kMethodsMyOtherInnerClass);
-
- if (env->RegisterNatives(MyOtherInnerClass_clazz(env),
- kMethodsMyOtherInnerClass,
- kMethodsMyOtherInnerClassSize) < 0) {
- jni_generator::HandleRegistrationError(
- env, MyOtherInnerClass_clazz(env), __FILE__);
- return false;
- }
-
- const int kMethodsMyInnerClassSize = arraysize(kMethodsMyInnerClass);
-
- if (env->RegisterNatives(MyInnerClass_clazz(env),
- kMethodsMyInnerClass,
- kMethodsMyInnerClassSize) < 0) {
- jni_generator::HandleRegistrationError(
- env, MyInnerClass_clazz(env), __FILE__);
- return false;
- }
-
- return true;
-}
-
-#endif // org_chromium_TestJni_JNI
diff --git a/base/android/jni_generator/testInputStream.javap b/base/android/jni_generator/testInputStream.javap
deleted file mode 100644
index 50ab617a3c..0000000000
--- a/base/android/jni_generator/testInputStream.javap
+++ /dev/null
@@ -1,228 +0,0 @@
-Compiled from "InputStream.java"
-public abstract class java.io.InputStream extends java.lang.Object implements java.io.Closeable
- SourceFile: "InputStream.java"
- minor version: 0
- major version: 49
- Constant pool:
-const #1 = Method #6.#39; // java/lang/Object."<init>":()V
-const #2 = class #40; // java/lang/RuntimeException
-const #3 = String #41; // Stub!
-const #4 = Method #2.#42; // java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
-const #5 = class #43; // java/io/InputStream
-const #6 = class #44; // java/lang/Object
-const #7 = class #45; // java/io/Closeable
-const #8 = Asciz <init>;
-const #9 = Asciz ()V;
-const #10 = Asciz Code;
-const #11 = Asciz LineNumberTable;
-const #12 = Asciz LocalVariableTable;
-const #13 = Asciz this;
-const #14 = Asciz Ljava/io/InputStream;;
-const #15 = Asciz available;
-const #16 = Asciz ()I;
-const #17 = Asciz Exceptions;
-const #18 = class #46; // java/io/IOException
-const #19 = Asciz close;
-const #20 = Asciz mark;
-const #21 = Asciz (I)V;
-const #22 = Asciz readlimit;
-const #23 = Asciz I;
-const #24 = Asciz markSupported;
-const #25 = Asciz ()Z;
-const #26 = Asciz read;
-const #27 = Asciz ([B)I;
-const #28 = Asciz buffer;
-const #29 = Asciz [B;
-const #30 = Asciz ([BII)I;
-const #31 = Asciz byteOffset;
-const #32 = Asciz byteCount;
-const #33 = Asciz reset;
-const #34 = Asciz skip;
-const #35 = Asciz (J)J;
-const #36 = Asciz J;
-const #37 = Asciz SourceFile;
-const #38 = Asciz InputStream.java;
-const #39 = NameAndType #8:#9;// "<init>":()V
-const #40 = Asciz java/lang/RuntimeException;
-const #41 = Asciz Stub!;
-const #42 = NameAndType #8:#47;// "<init>":(Ljava/lang/String;)V
-const #43 = Asciz java/io/InputStream;
-const #44 = Asciz java/lang/Object;
-const #45 = Asciz java/io/Closeable;
-const #46 = Asciz java/io/IOException;
-const #47 = Asciz (Ljava/lang/String;)V;
-
-{
-public java.io.InputStream();
- Signature: ()V
- Code:
- Stack=3, Locals=1, Args_size=1
- 0: aload_0
- 1: invokespecial #1; //Method java/lang/Object."<init>":()V
- 4: new #2; //class java/lang/RuntimeException
- 7: dup
- 8: ldc #3; //String Stub!
- 10: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 13: athrow
- LineNumberTable:
- line 5: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 14 0 this Ljava/io/InputStream;
-
-
-public int available() throws java.io.IOException;
- Signature: ()I
- Code:
- Stack=3, Locals=1, Args_size=1
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 6: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Ljava/io/InputStream;
-
- Exceptions:
- throws java.io.IOException
-public void close() throws java.io.IOException;
- Signature: ()V
- Code:
- Stack=3, Locals=1, Args_size=1
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 7: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Ljava/io/InputStream;
-
- Exceptions:
- throws java.io.IOException
-public void mark(int);
- Signature: (I)V
- Code:
- Stack=3, Locals=2, Args_size=2
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 8: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Ljava/io/InputStream;
- 0 10 1 readlimit I
-
-
-public boolean markSupported();
- Signature: ()Z
- Code:
- Stack=3, Locals=1, Args_size=1
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 9: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Ljava/io/InputStream;
-
-
-public abstract int read() throws java.io.IOException;
- Signature: ()I
- Exceptions:
- throws java.io.IOException
-public int read(byte[]) throws java.io.IOException;
- Signature: ([B)I
- Code:
- Stack=3, Locals=2, Args_size=2
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 11: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Ljava/io/InputStream;
- 0 10 1 buffer [B
-
- Exceptions:
- throws java.io.IOException
-public int read(byte[], int, int) throws java.io.IOException;
- Signature: ([BII)I
- Code:
- Stack=3, Locals=4, Args_size=4
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 12: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Ljava/io/InputStream;
- 0 10 1 buffer [B
- 0 10 2 byteOffset I
- 0 10 3 byteCount I
-
- Exceptions:
- throws java.io.IOException
-public synchronized void reset() throws java.io.IOException;
- Signature: ()V
- Code:
- Stack=3, Locals=1, Args_size=1
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 13: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Ljava/io/InputStream;
-
- Exceptions:
- throws java.io.IOException
-public long skip(long) throws java.io.IOException;
- Signature: (J)J
- Code:
- Stack=3, Locals=3, Args_size=2
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 14: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Ljava/io/InputStream;
- 0 10 1 byteCount J
-
- Exceptions:
- throws java.io.IOException
-}
-
diff --git a/base/android/jni_generator/testJNIInitNativeNameOption.golden b/base/android/jni_generator/testJNIInitNativeNameOption.golden
deleted file mode 100644
index a0998daf26..0000000000
--- a/base/android/jni_generator/testJNIInitNativeNameOption.golden
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright 2014 The Chromium 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.py
-// For
-// org/chromium/example/jni_generator/Test
-
-#ifndef org_chromium_example_jni_generator_Test_JNI
-#define org_chromium_example_jni_generator_Test_JNI
-
-#include <jni.h>
-
-#include "base/android/jni_generator/jni_generator_helper.h"
-
-#include "base/android/jni_int_wrapper.h"
-
-// Step 1: forward declarations.
-namespace {
-const char kTestClassPath[] = "org/chromium/example/jni_generator/Test";
-// Leaking this jclass as we cannot use LazyInstance from some threads.
-jclass g_Test_clazz = NULL;
-#define Test_clazz(env) g_Test_clazz
-
-} // namespace
-
-// Step 2: method stubs.
-static jint Method(JNIEnv* env, jobject jcaller,
- jlong nativeTest,
- jint arg1) {
- Test* native = reinterpret_cast<Test*>(nativeTest);
- CHECK_NATIVE_PTR(env, jcaller, native, "Method", 0);
- return native->Method(env, jcaller, arg1);
-}
-
-// Step 3: RegisterNatives.
-
-static const JNINativeMethod kMethodsTest[] = {
- { "nativeMethod",
-"("
-"J"
-"I"
-")"
-"I", reinterpret_cast<void*>(Method) },
-};
-
-static bool RegisterNativesImpl(JNIEnv* env, jclass clazz) {
-
- g_Test_clazz = static_cast<jclass>(env->NewWeakGlobalRef(clazz));
-
- const int kMethodsTestSize = arraysize(kMethodsTest);
-
- if (env->RegisterNatives(Test_clazz(env),
- kMethodsTest,
- kMethodsTestSize) < 0) {
- jni_generator::HandleRegistrationError(
- env, Test_clazz(env), __FILE__);
- return false;
- }
-
- return true;
-}
-
-extern "C" JNIEXPORT bool JNICALL
-Java_org_chromium_example_jni_generator_Test_nativeInitNativeClass(JNIEnv* env,
- jclass clazz) {
- return RegisterNativesImpl(env, clazz);
-}
-
-#endif // org_chromium_example_jni_generator_Test_JNI
diff --git a/base/android/jni_generator/testJarJarRemapping.golden b/base/android/jni_generator/testJarJarRemapping.golden
deleted file mode 100644
index 2f85122a5f..0000000000
--- a/base/android/jni_generator/testJarJarRemapping.golden
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2014 The Chromium 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.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 <jni.h>
-
-#include "base/android/jni_generator/jni_generator_helper.h"
-
-#include "base/android/jni_int_wrapper.h"
-
-// 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;
-#define Example_clazz(env) g_Example_clazz
-
-} // namespace
-
-static void Test(JNIEnv* env, jclass jcaller,
- jobject t);
-
-static void Test2(JNIEnv* env, jclass jcaller,
- jobject t);
-
-static void Test3(JNIEnv* env, jclass jcaller,
- jobject t);
-
-static void Test4(JNIEnv* env, jclass jcaller,
- jobject t);
-
-// Step 2: method stubs.
-
-// Step 3: RegisterNatives.
-
-static const JNINativeMethod kMethodsExample[] = {
- { "nativeTest",
-"("
-"Lorg/test2/Test;"
-")"
-"V", reinterpret_cast<void*>(Test) },
- { "nativeTest2",
-"("
-"Lorg/chromium/example3/PrefixFoo;"
-")"
-"V", reinterpret_cast<void*>(Test2) },
- { "nativeTest3",
-"("
-"Lorg/test3/Test;"
-")"
-"V", reinterpret_cast<void*>(Test3) },
- { "nativeTest4",
-"("
-"Lorg/test3/TestBar$Inner;"
-")"
-"V", reinterpret_cast<void*>(Test4) },
-};
-
-static bool RegisterNativesImpl(JNIEnv* env) {
-
- g_Example_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
- base::android::GetClass(env, kExampleClassPath).obj()));
-
- const int kMethodsExampleSize = arraysize(kMethodsExample);
-
- if (env->RegisterNatives(Example_clazz(env),
- kMethodsExample,
- kMethodsExampleSize) < 0) {
- jni_generator::HandleRegistrationError(
- env, Example_clazz(env), __FILE__);
- return false;
- }
-
- return true;
-}
-
-#endif // org_chromium_example_jni_generator_Example_JNI
diff --git a/base/android/jni_generator/testMotionEvent.javap b/base/android/jni_generator/testMotionEvent.javap
deleted file mode 100644
index 0746943e6e..0000000000
--- a/base/android/jni_generator/testMotionEvent.javap
+++ /dev/null
@@ -1,2295 +0,0 @@
-Compiled from "MotionEvent.java"
-public final class android.view.MotionEvent extends android.view.InputEvent implements android.os.Parcelable
- SourceFile: "MotionEvent.java"
- InnerClass:
- public final #10= #9 of #6; //PointerProperties=class android/view/MotionEvent$PointerProperties of class android/view/MotionEvent
- public final #13= #12 of #6; //PointerCoords=class android/view/MotionEvent$PointerCoords of class android/view/MotionEvent
- public abstract #150= #149 of #8; //Creator=class android/os/Parcelable$Creator of class android/os/Parcelable
- minor version: 0
- major version: 49
- Constant pool:
-const #1 = Method #7.#293; // android/view/InputEvent."<init>":()V
-const #2 = class #294; // java/lang/RuntimeException
-const #3 = String #295; // Stub!
-const #4 = Method #2.#296; // java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
-const #5 = Field #6.#297; // android/view/MotionEvent.CREATOR:Landroid/os/Parcelable$Creator;
-const #6 = class #298; // android/view/MotionEvent
-const #7 = class #299; // android/view/InputEvent
-const #8 = class #300; // android/os/Parcelable
-const #9 = class #301; // android/view/MotionEvent$PointerProperties
-const #10 = Asciz PointerProperties;
-const #11 = Asciz InnerClasses;
-const #12 = class #302; // android/view/MotionEvent$PointerCoords
-const #13 = Asciz PointerCoords;
-const #14 = Asciz INVALID_POINTER_ID;
-const #15 = Asciz I;
-const #16 = Asciz ConstantValue;
-const #17 = int -1;
-const #18 = Asciz ACTION_MASK;
-const #19 = int 255;
-const #20 = Asciz ACTION_DOWN;
-const #21 = int 0;
-const #22 = Asciz ACTION_UP;
-const #23 = int 1;
-const #24 = Asciz ACTION_MOVE;
-const #25 = int 2;
-const #26 = Asciz ACTION_CANCEL;
-const #27 = int 3;
-const #28 = Asciz ACTION_OUTSIDE;
-const #29 = int 4;
-const #30 = Asciz ACTION_POINTER_DOWN;
-const #31 = int 5;
-const #32 = Asciz ACTION_POINTER_UP;
-const #33 = int 6;
-const #34 = Asciz ACTION_HOVER_MOVE;
-const #35 = int 7;
-const #36 = Asciz ACTION_SCROLL;
-const #37 = int 8;
-const #38 = Asciz ACTION_HOVER_ENTER;
-const #39 = int 9;
-const #40 = Asciz ACTION_HOVER_EXIT;
-const #41 = int 10;
-const #42 = Asciz ACTION_POINTER_INDEX_MASK;
-const #43 = int 65280;
-const #44 = Asciz ACTION_POINTER_INDEX_SHIFT;
-const #45 = Asciz ACTION_POINTER_1_DOWN;
-const #46 = Asciz Deprecated;
-const #47 = Asciz RuntimeVisibleAnnotations;
-const #48 = Asciz Ljava/lang/Deprecated;;
-const #49 = Asciz ACTION_POINTER_2_DOWN;
-const #50 = int 261;
-const #51 = Asciz ACTION_POINTER_3_DOWN;
-const #52 = int 517;
-const #53 = Asciz ACTION_POINTER_1_UP;
-const #54 = Asciz ACTION_POINTER_2_UP;
-const #55 = int 262;
-const #56 = Asciz ACTION_POINTER_3_UP;
-const #57 = int 518;
-const #58 = Asciz ACTION_POINTER_ID_MASK;
-const #59 = Asciz ACTION_POINTER_ID_SHIFT;
-const #60 = Asciz FLAG_WINDOW_IS_OBSCURED;
-const #61 = Asciz EDGE_TOP;
-const #62 = Asciz EDGE_BOTTOM;
-const #63 = Asciz EDGE_LEFT;
-const #64 = Asciz EDGE_RIGHT;
-const #65 = Asciz AXIS_X;
-const #66 = Asciz AXIS_Y;
-const #67 = Asciz AXIS_PRESSURE;
-const #68 = Asciz AXIS_SIZE;
-const #69 = Asciz AXIS_TOUCH_MAJOR;
-const #70 = Asciz AXIS_TOUCH_MINOR;
-const #71 = Asciz AXIS_TOOL_MAJOR;
-const #72 = Asciz AXIS_TOOL_MINOR;
-const #73 = Asciz AXIS_ORIENTATION;
-const #74 = Asciz AXIS_VSCROLL;
-const #75 = Asciz AXIS_HSCROLL;
-const #76 = Asciz AXIS_Z;
-const #77 = int 11;
-const #78 = Asciz AXIS_RX;
-const #79 = int 12;
-const #80 = Asciz AXIS_RY;
-const #81 = int 13;
-const #82 = Asciz AXIS_RZ;
-const #83 = int 14;
-const #84 = Asciz AXIS_HAT_X;
-const #85 = int 15;
-const #86 = Asciz AXIS_HAT_Y;
-const #87 = int 16;
-const #88 = Asciz AXIS_LTRIGGER;
-const #89 = int 17;
-const #90 = Asciz AXIS_RTRIGGER;
-const #91 = int 18;
-const #92 = Asciz AXIS_THROTTLE;
-const #93 = int 19;
-const #94 = Asciz AXIS_RUDDER;
-const #95 = int 20;
-const #96 = Asciz AXIS_WHEEL;
-const #97 = int 21;
-const #98 = Asciz AXIS_GAS;
-const #99 = int 22;
-const #100 = Asciz AXIS_BRAKE;
-const #101 = int 23;
-const #102 = Asciz AXIS_DISTANCE;
-const #103 = int 24;
-const #104 = Asciz AXIS_TILT;
-const #105 = int 25;
-const #106 = Asciz AXIS_GENERIC_1;
-const #107 = int 32;
-const #108 = Asciz AXIS_GENERIC_2;
-const #109 = int 33;
-const #110 = Asciz AXIS_GENERIC_3;
-const #111 = int 34;
-const #112 = Asciz AXIS_GENERIC_4;
-const #113 = int 35;
-const #114 = Asciz AXIS_GENERIC_5;
-const #115 = int 36;
-const #116 = Asciz AXIS_GENERIC_6;
-const #117 = int 37;
-const #118 = Asciz AXIS_GENERIC_7;
-const #119 = int 38;
-const #120 = Asciz AXIS_GENERIC_8;
-const #121 = int 39;
-const #122 = Asciz AXIS_GENERIC_9;
-const #123 = int 40;
-const #124 = Asciz AXIS_GENERIC_10;
-const #125 = int 41;
-const #126 = Asciz AXIS_GENERIC_11;
-const #127 = int 42;
-const #128 = Asciz AXIS_GENERIC_12;
-const #129 = int 43;
-const #130 = Asciz AXIS_GENERIC_13;
-const #131 = int 44;
-const #132 = Asciz AXIS_GENERIC_14;
-const #133 = int 45;
-const #134 = Asciz AXIS_GENERIC_15;
-const #135 = int 46;
-const #136 = Asciz AXIS_GENERIC_16;
-const #137 = int 47;
-const #138 = Asciz BUTTON_PRIMARY;
-const #139 = Asciz BUTTON_SECONDARY;
-const #140 = Asciz BUTTON_TERTIARY;
-const #141 = Asciz BUTTON_BACK;
-const #142 = Asciz BUTTON_FORWARD;
-const #143 = Asciz TOOL_TYPE_UNKNOWN;
-const #144 = Asciz TOOL_TYPE_FINGER;
-const #145 = Asciz TOOL_TYPE_STYLUS;
-const #146 = Asciz TOOL_TYPE_MOUSE;
-const #147 = Asciz TOOL_TYPE_ERASER;
-const #148 = Asciz CREATOR;
-const #149 = class #303; // android/os/Parcelable$Creator
-const #150 = Asciz Creator;
-const #151 = Asciz Landroid/os/Parcelable$Creator;;
-const #152 = Asciz Signature;
-const #153 = Asciz Landroid/os/Parcelable$Creator<Landroid/view/MotionEvent;>;;
-const #154 = Asciz <init>;
-const #155 = Asciz ()V;
-const #156 = Asciz Code;
-const #157 = Asciz LineNumberTable;
-const #158 = Asciz LocalVariableTable;
-const #159 = Asciz this;
-const #160 = Asciz Landroid/view/MotionEvent;;
-const #161 = Asciz finalize;
-const #162 = Asciz Exceptions;
-const #163 = class #304; // java/lang/Throwable
-const #164 = Asciz obtain;
-const #165 = Asciz (JJII[Landroid/view/MotionEvent$PointerProperties;[Landroid/view/MotionEvent$PointerCoords;IIFFIIII)Landroid/view/MotionEvent;;
-const #166 = Asciz downTime;
-const #167 = Asciz J;
-const #168 = Asciz eventTime;
-const #169 = Asciz action;
-const #170 = Asciz pointerCount;
-const #171 = Asciz pointerProperties;
-const #172 = Asciz [Landroid/view/MotionEvent$PointerProperties;;
-const #173 = Asciz pointerCoords;
-const #174 = Asciz [Landroid/view/MotionEvent$PointerCoords;;
-const #175 = Asciz metaState;
-const #176 = Asciz buttonState;
-const #177 = Asciz xPrecision;
-const #178 = Asciz F;
-const #179 = Asciz yPrecision;
-const #180 = Asciz deviceId;
-const #181 = Asciz edgeFlags;
-const #182 = Asciz source;
-const #183 = Asciz flags;
-const #184 = Asciz (JJII[I[Landroid/view/MotionEvent$PointerCoords;IFFIIII)Landroid/view/MotionEvent;;
-const #185 = Asciz pointerIds;
-const #186 = Asciz [I;
-const #187 = Asciz (JJIFFFFIFFII)Landroid/view/MotionEvent;;
-const #188 = Asciz x;
-const #189 = Asciz y;
-const #190 = Asciz pressure;
-const #191 = Asciz size;
-const #192 = Asciz (JJIIFFFFIFFII)Landroid/view/MotionEvent;;
-const #193 = Asciz (JJIFFI)Landroid/view/MotionEvent;;
-const #194 = Asciz (Landroid/view/MotionEvent;)Landroid/view/MotionEvent;;
-const #195 = Asciz other;
-const #196 = Asciz obtainNoHistory;
-const #197 = Asciz recycle;
-const #198 = Asciz getDeviceId;
-const #199 = Asciz ()I;
-const #200 = Asciz getSource;
-const #201 = Asciz setSource;
-const #202 = Asciz (I)V;
-const #203 = Asciz getAction;
-const #204 = Asciz getActionMasked;
-const #205 = Asciz getActionIndex;
-const #206 = Asciz getFlags;
-const #207 = Asciz getDownTime;
-const #208 = Asciz ()J;
-const #209 = Asciz getEventTime;
-const #210 = Asciz getX;
-const #211 = Asciz ()F;
-const #212 = Asciz getY;
-const #213 = Asciz getPressure;
-const #214 = Asciz getSize;
-const #215 = Asciz getTouchMajor;
-const #216 = Asciz getTouchMinor;
-const #217 = Asciz getToolMajor;
-const #218 = Asciz getToolMinor;
-const #219 = Asciz getOrientation;
-const #220 = Asciz getAxisValue;
-const #221 = Asciz (I)F;
-const #222 = Asciz axis;
-const #223 = Asciz getPointerCount;
-const #224 = Asciz getPointerId;
-const #225 = Asciz (I)I;
-const #226 = Asciz pointerIndex;
-const #227 = Asciz getToolType;
-const #228 = Asciz findPointerIndex;
-const #229 = Asciz pointerId;
-const #230 = Asciz (II)F;
-const #231 = Asciz getPointerCoords;
-const #232 = Asciz (ILandroid/view/MotionEvent$PointerCoords;)V;
-const #233 = Asciz outPointerCoords;
-const #234 = Asciz Landroid/view/MotionEvent$PointerCoords;;
-const #235 = Asciz getPointerProperties;
-const #236 = Asciz (ILandroid/view/MotionEvent$PointerProperties;)V;
-const #237 = Asciz outPointerProperties;
-const #238 = Asciz Landroid/view/MotionEvent$PointerProperties;;
-const #239 = Asciz getMetaState;
-const #240 = Asciz getButtonState;
-const #241 = Asciz getRawX;
-const #242 = Asciz getRawY;
-const #243 = Asciz getXPrecision;
-const #244 = Asciz getYPrecision;
-const #245 = Asciz getHistorySize;
-const #246 = Asciz getHistoricalEventTime;
-const #247 = Asciz (I)J;
-const #248 = Asciz pos;
-const #249 = Asciz getHistoricalX;
-const #250 = Asciz getHistoricalY;
-const #251 = Asciz getHistoricalPressure;
-const #252 = Asciz getHistoricalSize;
-const #253 = Asciz getHistoricalTouchMajor;
-const #254 = Asciz getHistoricalTouchMinor;
-const #255 = Asciz getHistoricalToolMajor;
-const #256 = Asciz getHistoricalToolMinor;
-const #257 = Asciz getHistoricalOrientation;
-const #258 = Asciz getHistoricalAxisValue;
-const #259 = Asciz (III)F;
-const #260 = Asciz getHistoricalPointerCoords;
-const #261 = Asciz (IILandroid/view/MotionEvent$PointerCoords;)V;
-const #262 = Asciz getEdgeFlags;
-const #263 = Asciz setEdgeFlags;
-const #264 = Asciz setAction;
-const #265 = Asciz offsetLocation;
-const #266 = Asciz (FF)V;
-const #267 = Asciz deltaX;
-const #268 = Asciz deltaY;
-const #269 = Asciz setLocation;
-const #270 = Asciz transform;
-const #271 = Asciz (Landroid/graphics/Matrix;)V;
-const #272 = Asciz matrix;
-const #273 = Asciz Landroid/graphics/Matrix;;
-const #274 = Asciz addBatch;
-const #275 = Asciz (JFFFFI)V;
-const #276 = Asciz (J[Landroid/view/MotionEvent$PointerCoords;I)V;
-const #277 = Asciz toString;
-const #278 = Asciz ()Ljava/lang/String;;
-const #279 = Asciz actionToString;
-const #280 = Asciz (I)Ljava/lang/String;;
-const #281 = Asciz axisToString;
-const #282 = Asciz axisFromString;
-const #283 = Asciz (Ljava/lang/String;)I;
-const #284 = Asciz symbolicName;
-const #285 = Asciz Ljava/lang/String;;
-const #286 = Asciz writeToParcel;
-const #287 = Asciz (Landroid/os/Parcel;I)V;
-const #288 = Asciz out;
-const #289 = Asciz Landroid/os/Parcel;;
-const #290 = Asciz <clinit>;
-const #291 = Asciz SourceFile;
-const #292 = Asciz MotionEvent.java;
-const #293 = NameAndType #154:#155;// "<init>":()V
-const #294 = Asciz java/lang/RuntimeException;
-const #295 = Asciz Stub!;
-const #296 = NameAndType #154:#305;// "<init>":(Ljava/lang/String;)V
-const #297 = NameAndType #148:#151;// CREATOR:Landroid/os/Parcelable$Creator;
-const #298 = Asciz android/view/MotionEvent;
-const #299 = Asciz android/view/InputEvent;
-const #300 = Asciz android/os/Parcelable;
-const #301 = Asciz android/view/MotionEvent$PointerProperties;
-const #302 = Asciz android/view/MotionEvent$PointerCoords;
-const #303 = Asciz android/os/Parcelable$Creator;
-const #304 = Asciz java/lang/Throwable;
-const #305 = Asciz (Ljava/lang/String;)V;
-
-{
-public static final int INVALID_POINTER_ID;
- Signature: I
- Constant value: int -1
-
-public static final int ACTION_MASK;
- Signature: I
- Constant value: int 255
-
-public static final int ACTION_DOWN;
- Signature: I
- Constant value: int 0
-
-public static final int ACTION_UP;
- Signature: I
- Constant value: int 1
-
-public static final int ACTION_MOVE;
- Signature: I
- Constant value: int 2
-
-public static final int ACTION_CANCEL;
- Signature: I
- Constant value: int 3
-
-public static final int ACTION_OUTSIDE;
- Signature: I
- Constant value: int 4
-
-public static final int ACTION_POINTER_DOWN;
- Signature: I
- Constant value: int 5
-
-public static final int ACTION_POINTER_UP;
- Signature: I
- Constant value: int 6
-
-public static final int ACTION_HOVER_MOVE;
- Signature: I
- Constant value: int 7
-
-public static final int ACTION_SCROLL;
- Signature: I
- Constant value: int 8
-
-public static final int ACTION_HOVER_ENTER;
- Signature: I
- Constant value: int 9
-
-public static final int ACTION_HOVER_EXIT;
- Signature: I
- Constant value: int 10
-
-public static final int ACTION_POINTER_INDEX_MASK;
- Signature: I
- Constant value: int 65280
-
-public static final int ACTION_POINTER_INDEX_SHIFT;
- Signature: I
- Constant value: int 8
-
-public static final int ACTION_POINTER_1_DOWN;
- Signature: I
- Constant value: int 5Deprecated: true
- RuntimeVisibleAnnotations: length = 0x6
- 00 01 00 30 00 00
-
-
-public static final int ACTION_POINTER_2_DOWN;
- Signature: I
- Constant value: int 261Deprecated: true
- RuntimeVisibleAnnotations: length = 0x6
- 00 01 00 30 00 00
-
-
-public static final int ACTION_POINTER_3_DOWN;
- Signature: I
- Constant value: int 517Deprecated: true
- RuntimeVisibleAnnotations: length = 0x6
- 00 01 00 30 00 00
-
-
-public static final int ACTION_POINTER_1_UP;
- Signature: I
- Constant value: int 6Deprecated: true
- RuntimeVisibleAnnotations: length = 0x6
- 00 01 00 30 00 00
-
-
-public static final int ACTION_POINTER_2_UP;
- Signature: I
- Constant value: int 262Deprecated: true
- RuntimeVisibleAnnotations: length = 0x6
- 00 01 00 30 00 00
-
-
-public static final int ACTION_POINTER_3_UP;
- Signature: I
- Constant value: int 518Deprecated: true
- RuntimeVisibleAnnotations: length = 0x6
- 00 01 00 30 00 00
-
-
-public static final int ACTION_POINTER_ID_MASK;
- Signature: I
- Constant value: int 65280Deprecated: true
- RuntimeVisibleAnnotations: length = 0x6
- 00 01 00 30 00 00
-
-
-public static final int ACTION_POINTER_ID_SHIFT;
- Signature: I
- Constant value: int 8Deprecated: true
- RuntimeVisibleAnnotations: length = 0x6
- 00 01 00 30 00 00
-
-
-public static final int FLAG_WINDOW_IS_OBSCURED;
- Signature: I
- Constant value: int 1
-
-public static final int EDGE_TOP;
- Signature: I
- Constant value: int 1
-
-public static final int EDGE_BOTTOM;
- Signature: I
- Constant value: int 2
-
-public static final int EDGE_LEFT;
- Signature: I
- Constant value: int 4
-
-public static final int EDGE_RIGHT;
- Signature: I
- Constant value: int 8
-
-public static final int AXIS_X;
- Signature: I
- Constant value: int 0
-
-public static final int AXIS_Y;
- Signature: I
- Constant value: int 1
-
-public static final int AXIS_PRESSURE;
- Signature: I
- Constant value: int 2
-
-public static final int AXIS_SIZE;
- Signature: I
- Constant value: int 3
-
-public static final int AXIS_TOUCH_MAJOR;
- Signature: I
- Constant value: int 4
-
-public static final int AXIS_TOUCH_MINOR;
- Signature: I
- Constant value: int 5
-
-public static final int AXIS_TOOL_MAJOR;
- Signature: I
- Constant value: int 6
-
-public static final int AXIS_TOOL_MINOR;
- Signature: I
- Constant value: int 7
-
-public static final int AXIS_ORIENTATION;
- Signature: I
- Constant value: int 8
-
-public static final int AXIS_VSCROLL;
- Signature: I
- Constant value: int 9
-
-public static final int AXIS_HSCROLL;
- Signature: I
- Constant value: int 10
-
-public static final int AXIS_Z;
- Signature: I
- Constant value: int 11
-
-public static final int AXIS_RX;
- Signature: I
- Constant value: int 12
-
-public static final int AXIS_RY;
- Signature: I
- Constant value: int 13
-
-public static final int AXIS_RZ;
- Signature: I
- Constant value: int 14
-
-public static final int AXIS_HAT_X;
- Signature: I
- Constant value: int 15
-
-public static final int AXIS_HAT_Y;
- Signature: I
- Constant value: int 16
-
-public static final int AXIS_LTRIGGER;
- Signature: I
- Constant value: int 17
-
-public static final int AXIS_RTRIGGER;
- Signature: I
- Constant value: int 18
-
-public static final int AXIS_THROTTLE;
- Signature: I
- Constant value: int 19
-
-public static final int AXIS_RUDDER;
- Signature: I
- Constant value: int 20
-
-public static final int AXIS_WHEEL;
- Signature: I
- Constant value: int 21
-
-public static final int AXIS_GAS;
- Signature: I
- Constant value: int 22
-
-public static final int AXIS_BRAKE;
- Signature: I
- Constant value: int 23
-
-public static final int AXIS_DISTANCE;
- Signature: I
- Constant value: int 24
-
-public static final int AXIS_TILT;
- Signature: I
- Constant value: int 25
-
-public static final int AXIS_GENERIC_1;
- Signature: I
- Constant value: int 32
-
-public static final int AXIS_GENERIC_2;
- Signature: I
- Constant value: int 33
-
-public static final int AXIS_GENERIC_3;
- Signature: I
- Constant value: int 34
-
-public static final int AXIS_GENERIC_4;
- Signature: I
- Constant value: int 35
-
-public static final int AXIS_GENERIC_5;
- Signature: I
- Constant value: int 36
-
-public static final int AXIS_GENERIC_6;
- Signature: I
- Constant value: int 37
-
-public static final int AXIS_GENERIC_7;
- Signature: I
- Constant value: int 38
-
-public static final int AXIS_GENERIC_8;
- Signature: I
- Constant value: int 39
-
-public static final int AXIS_GENERIC_9;
- Signature: I
- Constant value: int 40
-
-public static final int AXIS_GENERIC_10;
- Signature: I
- Constant value: int 41
-
-public static final int AXIS_GENERIC_11;
- Signature: I
- Constant value: int 42
-
-public static final int AXIS_GENERIC_12;
- Signature: I
- Constant value: int 43
-
-public static final int AXIS_GENERIC_13;
- Signature: I
- Constant value: int 44
-
-public static final int AXIS_GENERIC_14;
- Signature: I
- Constant value: int 45
-
-public static final int AXIS_GENERIC_15;
- Signature: I
- Constant value: int 46
-
-public static final int AXIS_GENERIC_16;
- Signature: I
- Constant value: int 47
-
-public static final int BUTTON_PRIMARY;
- Signature: I
- Constant value: int 1
-
-public static final int BUTTON_SECONDARY;
- Signature: I
- Constant value: int 2
-
-public static final int BUTTON_TERTIARY;
- Signature: I
- Constant value: int 4
-
-public static final int BUTTON_BACK;
- Signature: I
- Constant value: int 8
-
-public static final int BUTTON_FORWARD;
- Signature: I
- Constant value: int 16
-
-public static final int TOOL_TYPE_UNKNOWN;
- Signature: I
- Constant value: int 0
-
-public static final int TOOL_TYPE_FINGER;
- Signature: I
- Constant value: int 1
-
-public static final int TOOL_TYPE_STYLUS;
- Signature: I
- Constant value: int 2
-
-public static final int TOOL_TYPE_MOUSE;
- Signature: I
- Constant value: int 3
-
-public static final int TOOL_TYPE_ERASER;
- Signature: I
- Constant value: int 4
-
-public static final android.os.Parcelable$Creator CREATOR;
- Signature: Landroid/os/Parcelable$Creator;
- Signature: length = 0x2
- 00 FFFFFF99
-
-
-android.view.MotionEvent();
- Signature: ()V
- Code:
- Stack=3, Locals=1, Args_size=1
- 0: aload_0
- 1: invokespecial #1; //Method android/view/InputEvent."<init>":()V
- 4: new #2; //class java/lang/RuntimeException
- 7: dup
- 8: ldc #3; //String Stub!
- 10: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 13: athrow
- LineNumberTable:
- line 35: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 14 0 this Landroid/view/MotionEvent;
-
-
-protected void finalize() throws java.lang.Throwable;
- Signature: ()V
- Code:
- Stack=3, Locals=1, Args_size=1
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 36: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
- Exceptions:
- throws java.lang.Throwable
-public static android.view.MotionEvent obtain(long, long, int, int, android.view.MotionEvent$PointerProperties[], android.view.MotionEvent$PointerCoords[], int, int, float, float, int, int, int, int);
- Signature: (JJII[Landroid/view/MotionEvent$PointerProperties;[Landroid/view/MotionEvent$PointerCoords;IIFFIIII)Landroid/view/MotionEvent;
- Code:
- Stack=3, Locals=16, Args_size=14
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 37: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 downTime J
- 0 10 2 eventTime J
- 0 10 4 action I
- 0 10 5 pointerCount I
- 0 10 6 pointerProperties [Landroid/view/MotionEvent$PointerProperties;
- 0 10 7 pointerCoords [Landroid/view/MotionEvent$PointerCoords;
- 0 10 8 metaState I
- 0 10 9 buttonState I
- 0 10 10 xPrecision F
- 0 10 11 yPrecision F
- 0 10 12 deviceId I
- 0 10 13 edgeFlags I
- 0 10 14 source I
- 0 10 15 flags I
-
-
-public static android.view.MotionEvent obtain(long, long, int, int, int[], android.view.MotionEvent$PointerCoords[], int, float, float, int, int, int, int);
- Signature: (JJII[I[Landroid/view/MotionEvent$PointerCoords;IFFIIII)Landroid/view/MotionEvent;
- Code:
- Stack=3, Locals=15, Args_size=13
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 39: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 downTime J
- 0 10 2 eventTime J
- 0 10 4 action I
- 0 10 5 pointerCount I
- 0 10 6 pointerIds [I
- 0 10 7 pointerCoords [Landroid/view/MotionEvent$PointerCoords;
- 0 10 8 metaState I
- 0 10 9 xPrecision F
- 0 10 10 yPrecision F
- 0 10 11 deviceId I
- 0 10 12 edgeFlags I
- 0 10 13 source I
- 0 10 14 flags I
-
- Deprecated: true
- RuntimeVisibleAnnotations: length = 0x6
- 00 01 00 30 00 00
-
-public static android.view.MotionEvent obtain(long, long, int, float, float, float, float, int, float, float, int, int);
- Signature: (JJIFFFFIFFII)Landroid/view/MotionEvent;
- Code:
- Stack=3, Locals=14, Args_size=12
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 40: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 downTime J
- 0 10 2 eventTime J
- 0 10 4 action I
- 0 10 5 x F
- 0 10 6 y F
- 0 10 7 pressure F
- 0 10 8 size F
- 0 10 9 metaState I
- 0 10 10 xPrecision F
- 0 10 11 yPrecision F
- 0 10 12 deviceId I
- 0 10 13 edgeFlags I
-
-
-public static android.view.MotionEvent obtain(long, long, int, int, float, float, float, float, int, float, float, int, int);
- Signature: (JJIIFFFFIFFII)Landroid/view/MotionEvent;
- Code:
- Stack=3, Locals=15, Args_size=13
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 42: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 downTime J
- 0 10 2 eventTime J
- 0 10 4 action I
- 0 10 5 pointerCount I
- 0 10 6 x F
- 0 10 7 y F
- 0 10 8 pressure F
- 0 10 9 size F
- 0 10 10 metaState I
- 0 10 11 xPrecision F
- 0 10 12 yPrecision F
- 0 10 13 deviceId I
- 0 10 14 edgeFlags I
-
- Deprecated: true
- RuntimeVisibleAnnotations: length = 0x6
- 00 01 00 30 00 00
-
-public static android.view.MotionEvent obtain(long, long, int, float, float, int);
- Signature: (JJIFFI)Landroid/view/MotionEvent;
- Code:
- Stack=3, Locals=8, Args_size=6
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 43: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 downTime J
- 0 10 2 eventTime J
- 0 10 4 action I
- 0 10 5 x F
- 0 10 6 y F
- 0 10 7 metaState I
-
-
-public static android.view.MotionEvent obtain(android.view.MotionEvent);
- Signature: (Landroid/view/MotionEvent;)Landroid/view/MotionEvent;
- Code:
- Stack=3, Locals=1, Args_size=1
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 44: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 other Landroid/view/MotionEvent;
-
-
-public static android.view.MotionEvent obtainNoHistory(android.view.MotionEvent);
- Signature: (Landroid/view/MotionEvent;)Landroid/view/MotionEvent;
- Code:
- Stack=3, Locals=1, Args_size=1
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 45: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 other Landroid/view/MotionEvent;
-
-
-public final void recycle();
- Signature: ()V
- Code:
- Stack=3, Locals=1, Args_size=1
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 46: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
-
-public final int getDeviceId();
- Signature: ()I
- Code:
- Stack=3, Locals=1, Args_size=1
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 47: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
-
-public final int getSource();
- Signature: ()I
- Code:
- Stack=3, Locals=1, Args_size=1
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 48: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
-
-public final void setSource(int);
- Signature: (I)V
- Code:
- Stack=3, Locals=2, Args_size=2
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 49: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 source I
-
-
-public final int getAction();
- Signature: ()I
- Code:
- Stack=3, Locals=1, Args_size=1
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 50: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
-
-public final int getActionMasked();
- Signature: ()I
- Code:
- Stack=3, Locals=1, Args_size=1
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 51: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
-
-public final int getActionIndex();
- Signature: ()I
- Code:
- Stack=3, Locals=1, Args_size=1
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 52: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
-
-public final int getFlags();
- Signature: ()I
- Code:
- Stack=3, Locals=1, Args_size=1
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 53: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
-
-public final long getDownTime();
- Signature: ()J
- Code:
- Stack=3, Locals=1, Args_size=1
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 54: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
-
-public final long getEventTime();
- Signature: ()J
- Code:
- Stack=3, Locals=1, Args_size=1
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 55: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
-
-public final float getX();
- Signature: ()F
- Code:
- Stack=3, Locals=1, Args_size=1
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 56: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
-
-public final float getY();
- Signature: ()F
- Code:
- Stack=3, Locals=1, Args_size=1
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 57: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
-
-public final float getPressure();
- Signature: ()F
- Code:
- Stack=3, Locals=1, Args_size=1
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 58: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
-
-public final float getSize();
- Signature: ()F
- Code:
- Stack=3, Locals=1, Args_size=1
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 59: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
-
-public final float getTouchMajor();
- Signature: ()F
- Code:
- Stack=3, Locals=1, Args_size=1
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 60: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
-
-public final float getTouchMinor();
- Signature: ()F
- Code:
- Stack=3, Locals=1, Args_size=1
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 61: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
-
-public final float getToolMajor();
- Signature: ()F
- Code:
- Stack=3, Locals=1, Args_size=1
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 62: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
-
-public final float getToolMinor();
- Signature: ()F
- Code:
- Stack=3, Locals=1, Args_size=1
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 63: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
-
-public final float getOrientation();
- Signature: ()F
- Code:
- Stack=3, Locals=1, Args_size=1
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 64: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
-
-public final float getAxisValue(int);
- Signature: (I)F
- Code:
- Stack=3, Locals=2, Args_size=2
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 65: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 axis I
-
-
-public final int getPointerCount();
- Signature: ()I
- Code:
- Stack=3, Locals=1, Args_size=1
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 66: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
-
-public final int getPointerId(int);
- Signature: (I)I
- Code:
- Stack=3, Locals=2, Args_size=2
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 67: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
-
-
-public final int getToolType(int);
- Signature: (I)I
- Code:
- Stack=3, Locals=2, Args_size=2
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 68: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
-
-
-public final int findPointerIndex(int);
- Signature: (I)I
- Code:
- Stack=3, Locals=2, Args_size=2
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 69: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerId I
-
-
-public final float getX(int);
- Signature: (I)F
- Code:
- Stack=3, Locals=2, Args_size=2
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 70: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
-
-
-public final float getY(int);
- Signature: (I)F
- Code:
- Stack=3, Locals=2, Args_size=2
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 71: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
-
-
-public final float getPressure(int);
- Signature: (I)F
- Code:
- Stack=3, Locals=2, Args_size=2
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 72: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
-
-
-public final float getSize(int);
- Signature: (I)F
- Code:
- Stack=3, Locals=2, Args_size=2
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 73: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
-
-
-public final float getTouchMajor(int);
- Signature: (I)F
- Code:
- Stack=3, Locals=2, Args_size=2
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 74: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
-
-
-public final float getTouchMinor(int);
- Signature: (I)F
- Code:
- Stack=3, Locals=2, Args_size=2
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 75: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
-
-
-public final float getToolMajor(int);
- Signature: (I)F
- Code:
- Stack=3, Locals=2, Args_size=2
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 76: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
-
-
-public final float getToolMinor(int);
- Signature: (I)F
- Code:
- Stack=3, Locals=2, Args_size=2
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 77: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
-
-
-public final float getOrientation(int);
- Signature: (I)F
- Code:
- Stack=3, Locals=2, Args_size=2
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 78: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
-
-
-public final float getAxisValue(int, int);
- Signature: (II)F
- Code:
- Stack=3, Locals=3, Args_size=3
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 79: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 axis I
- 0 10 2 pointerIndex I
-
-
-public final void getPointerCoords(int, android.view.MotionEvent$PointerCoords);
- Signature: (ILandroid/view/MotionEvent$PointerCoords;)V
- Code:
- Stack=3, Locals=3, Args_size=3
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 80: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
- 0 10 2 outPointerCoords Landroid/view/MotionEvent$PointerCoords;
-
-
-public final void getPointerProperties(int, android.view.MotionEvent$PointerProperties);
- Signature: (ILandroid/view/MotionEvent$PointerProperties;)V
- Code:
- Stack=3, Locals=3, Args_size=3
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 81: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
- 0 10 2 outPointerProperties Landroid/view/MotionEvent$PointerProperties;
-
-
-public final int getMetaState();
- Signature: ()I
- Code:
- Stack=3, Locals=1, Args_size=1
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 82: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
-
-public final int getButtonState();
- Signature: ()I
- Code:
- Stack=3, Locals=1, Args_size=1
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 83: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
-
-public final float getRawX();
- Signature: ()F
- Code:
- Stack=3, Locals=1, Args_size=1
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 84: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
-
-public final float getRawY();
- Signature: ()F
- Code:
- Stack=3, Locals=1, Args_size=1
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 85: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
-
-public final float getXPrecision();
- Signature: ()F
- Code:
- Stack=3, Locals=1, Args_size=1
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 86: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
-
-public final float getYPrecision();
- Signature: ()F
- Code:
- Stack=3, Locals=1, Args_size=1
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 87: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
-
-public final int getHistorySize();
- Signature: ()I
- Code:
- Stack=3, Locals=1, Args_size=1
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 88: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
-
-public final long getHistoricalEventTime(int);
- Signature: (I)J
- Code:
- Stack=3, Locals=2, Args_size=2
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 89: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pos I
-
-
-public final float getHistoricalX(int);
- Signature: (I)F
- Code:
- Stack=3, Locals=2, Args_size=2
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 90: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pos I
-
-
-public final float getHistoricalY(int);
- Signature: (I)F
- Code:
- Stack=3, Locals=2, Args_size=2
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 91: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pos I
-
-
-public final float getHistoricalPressure(int);
- Signature: (I)F
- Code:
- Stack=3, Locals=2, Args_size=2
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 92: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pos I
-
-
-public final float getHistoricalSize(int);
- Signature: (I)F
- Code:
- Stack=3, Locals=2, Args_size=2
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 93: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pos I
-
-
-public final float getHistoricalTouchMajor(int);
- Signature: (I)F
- Code:
- Stack=3, Locals=2, Args_size=2
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 94: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pos I
-
-
-public final float getHistoricalTouchMinor(int);
- Signature: (I)F
- Code:
- Stack=3, Locals=2, Args_size=2
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 95: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pos I
-
-
-public final float getHistoricalToolMajor(int);
- Signature: (I)F
- Code:
- Stack=3, Locals=2, Args_size=2
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 96: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pos I
-
-
-public final float getHistoricalToolMinor(int);
- Signature: (I)F
- Code:
- Stack=3, Locals=2, Args_size=2
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 97: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pos I
-
-
-public final float getHistoricalOrientation(int);
- Signature: (I)F
- Code:
- Stack=3, Locals=2, Args_size=2
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 98: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pos I
-
-
-public final float getHistoricalAxisValue(int, int);
- Signature: (II)F
- Code:
- Stack=3, Locals=3, Args_size=3
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 99: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 axis I
- 0 10 2 pos I
-
-
-public final float getHistoricalX(int, int);
- Signature: (II)F
- Code:
- Stack=3, Locals=3, Args_size=3
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 100: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
- 0 10 2 pos I
-
-
-public final float getHistoricalY(int, int);
- Signature: (II)F
- Code:
- Stack=3, Locals=3, Args_size=3
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 101: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
- 0 10 2 pos I
-
-
-public final float getHistoricalPressure(int, int);
- Signature: (II)F
- Code:
- Stack=3, Locals=3, Args_size=3
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 102: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
- 0 10 2 pos I
-
-
-public final float getHistoricalSize(int, int);
- Signature: (II)F
- Code:
- Stack=3, Locals=3, Args_size=3
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 103: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
- 0 10 2 pos I
-
-
-public final float getHistoricalTouchMajor(int, int);
- Signature: (II)F
- Code:
- Stack=3, Locals=3, Args_size=3
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 104: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
- 0 10 2 pos I
-
-
-public final float getHistoricalTouchMinor(int, int);
- Signature: (II)F
- Code:
- Stack=3, Locals=3, Args_size=3
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 105: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
- 0 10 2 pos I
-
-
-public final float getHistoricalToolMajor(int, int);
- Signature: (II)F
- Code:
- Stack=3, Locals=3, Args_size=3
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 106: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
- 0 10 2 pos I
-
-
-public final float getHistoricalToolMinor(int, int);
- Signature: (II)F
- Code:
- Stack=3, Locals=3, Args_size=3
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 107: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
- 0 10 2 pos I
-
-
-public final float getHistoricalOrientation(int, int);
- Signature: (II)F
- Code:
- Stack=3, Locals=3, Args_size=3
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 108: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
- 0 10 2 pos I
-
-
-public final float getHistoricalAxisValue(int, int, int);
- Signature: (III)F
- Code:
- Stack=3, Locals=4, Args_size=4
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 109: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 axis I
- 0 10 2 pointerIndex I
- 0 10 3 pos I
-
-
-public final void getHistoricalPointerCoords(int, int, android.view.MotionEvent$PointerCoords);
- Signature: (IILandroid/view/MotionEvent$PointerCoords;)V
- Code:
- Stack=3, Locals=4, Args_size=4
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 110: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
- 0 10 2 pos I
- 0 10 3 outPointerCoords Landroid/view/MotionEvent$PointerCoords;
-
-
-public final int getEdgeFlags();
- Signature: ()I
- Code:
- Stack=3, Locals=1, Args_size=1
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 111: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
-
-public final void setEdgeFlags(int);
- Signature: (I)V
- Code:
- Stack=3, Locals=2, Args_size=2
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 112: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 flags I
-
-
-public final void setAction(int);
- Signature: (I)V
- Code:
- Stack=3, Locals=2, Args_size=2
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 113: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 action I
-
-
-public final void offsetLocation(float, float);
- Signature: (FF)V
- Code:
- Stack=3, Locals=3, Args_size=3
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 114: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 deltaX F
- 0 10 2 deltaY F
-
-
-public final void setLocation(float, float);
- Signature: (FF)V
- Code:
- Stack=3, Locals=3, Args_size=3
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 115: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 x F
- 0 10 2 y F
-
-
-public final void transform(android.graphics.Matrix);
- Signature: (Landroid/graphics/Matrix;)V
- Code:
- Stack=3, Locals=2, Args_size=2
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 116: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 matrix Landroid/graphics/Matrix;
-
-
-public final void addBatch(long, float, float, float, float, int);
- Signature: (JFFFFI)V
- Code:
- Stack=3, Locals=8, Args_size=7
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 117: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 eventTime J
- 0 10 3 x F
- 0 10 4 y F
- 0 10 5 pressure F
- 0 10 6 size F
- 0 10 7 metaState I
-
-
-public final void addBatch(long, android.view.MotionEvent$PointerCoords[], int);
- Signature: (J[Landroid/view/MotionEvent$PointerCoords;I)V
- Code:
- Stack=3, Locals=5, Args_size=4
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 118: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 eventTime J
- 0 10 3 pointerCoords [Landroid/view/MotionEvent$PointerCoords;
- 0 10 4 metaState I
-
-
-public java.lang.String toString();
- Signature: ()Ljava/lang/String;
- Code:
- Stack=3, Locals=1, Args_size=1
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 119: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
-
-public static java.lang.String actionToString(int);
- Signature: (I)Ljava/lang/String;
- Code:
- Stack=3, Locals=1, Args_size=1
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 120: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 action I
-
-
-public static java.lang.String axisToString(int);
- Signature: (I)Ljava/lang/String;
- Code:
- Stack=3, Locals=1, Args_size=1
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 121: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 axis I
-
-
-public static int axisFromString(java.lang.String);
- Signature: (Ljava/lang/String;)I
- Code:
- Stack=3, Locals=1, Args_size=1
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 122: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 symbolicName Ljava/lang/String;
-
-
-public void writeToParcel(android.os.Parcel, int);
- Signature: (Landroid/os/Parcel;I)V
- Code:
- Stack=3, Locals=3, Args_size=3
- 0: new #2; //class java/lang/RuntimeException
- 3: dup
- 4: ldc #3; //String Stub!
- 6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 123: 0
-
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 out Landroid/os/Parcel;
- 0 10 2 flags I
-
-
-static {};
- Signature: ()V
- Code:
- Stack=1, Locals=0, Args_size=0
- 0: aconst_null
- 1: putstatic #5; //Field CREATOR:Landroid/os/Parcelable$Creator;
- 4: return
- LineNumberTable:
- line 213: 0
-
-
-}
-
diff --git a/base/android/jni_generator/testMotionEvent.javap7 b/base/android/jni_generator/testMotionEvent.javap7
deleted file mode 100644
index f4f5444369..0000000000
--- a/base/android/jni_generator/testMotionEvent.javap7
+++ /dev/null
@@ -1,2370 +0,0 @@
-Classfile out_android/Debug/gen/content/jni/android/view/MotionEvent.class
- Last modified Feb 27, 2014; size 13369 bytes
- MD5 checksum 3718d77a994cb8aceb7b35c5df3c4dd1
- Compiled from "MotionEvent.java"
-public final class android.view.MotionEvent extends android.view.InputEvent implements android.os.Parcelable
- SourceFile: "MotionEvent.java"
- InnerClasses:
- public static final #10= #9 of #6; //PointerProperties=class android/view/MotionEvent$PointerProperties of class android/view/MotionEvent
- public static final #13= #12 of #6; //PointerCoords=class android/view/MotionEvent$PointerCoords of class android/view/MotionEvent
- public static #150= #149 of #8; //Creator=class android/os/Parcelable$Creator of class android/os/Parcelable
- minor version: 0
- major version: 49
- flags: ACC_PUBLIC, ACC_FINAL, ACC_SUPER
-Constant pool:
- #1 = Methodref #7.#293 // android/view/InputEvent."<init>":()V
- #2 = Class #294 // java/lang/RuntimeException
- #3 = String #295 // Stub!
- #4 = Methodref #2.#296 // java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- #5 = Fieldref #6.#297 // android/view/MotionEvent.CREATOR:Landroid/os/Parcelable$Creator;
- #6 = Class #298 // android/view/MotionEvent
- #7 = Class #299 // android/view/InputEvent
- #8 = Class #300 // android/os/Parcelable
- #9 = Class #301 // android/view/MotionEvent$PointerProperties
- #10 = Utf8 PointerProperties
- #11 = Utf8 InnerClasses
- #12 = Class #302 // android/view/MotionEvent$PointerCoords
- #13 = Utf8 PointerCoords
- #14 = Utf8 INVALID_POINTER_ID
- #15 = Utf8 I
- #16 = Utf8 ConstantValue
- #17 = Integer -1
- #18 = Utf8 ACTION_MASK
- #19 = Integer 255
- #20 = Utf8 ACTION_DOWN
- #21 = Integer 0
- #22 = Utf8 ACTION_UP
- #23 = Integer 1
- #24 = Utf8 ACTION_MOVE
- #25 = Integer 2
- #26 = Utf8 ACTION_CANCEL
- #27 = Integer 3
- #28 = Utf8 ACTION_OUTSIDE
- #29 = Integer 4
- #30 = Utf8 ACTION_POINTER_DOWN
- #31 = Integer 5
- #32 = Utf8 ACTION_POINTER_UP
- #33 = Integer 6
- #34 = Utf8 ACTION_HOVER_MOVE
- #35 = Integer 7
- #36 = Utf8 ACTION_SCROLL
- #37 = Integer 8
- #38 = Utf8 ACTION_HOVER_ENTER
- #39 = Integer 9
- #40 = Utf8 ACTION_HOVER_EXIT
- #41 = Integer 10
- #42 = Utf8 ACTION_POINTER_INDEX_MASK
- #43 = Integer 65280
- #44 = Utf8 ACTION_POINTER_INDEX_SHIFT
- #45 = Utf8 ACTION_POINTER_1_DOWN
- #46 = Utf8 Deprecated
- #47 = Utf8 RuntimeVisibleAnnotations
- #48 = Utf8 Ljava/lang/Deprecated;
- #49 = Utf8 ACTION_POINTER_2_DOWN
- #50 = Integer 261
- #51 = Utf8 ACTION_POINTER_3_DOWN
- #52 = Integer 517
- #53 = Utf8 ACTION_POINTER_1_UP
- #54 = Utf8 ACTION_POINTER_2_UP
- #55 = Integer 262
- #56 = Utf8 ACTION_POINTER_3_UP
- #57 = Integer 518
- #58 = Utf8 ACTION_POINTER_ID_MASK
- #59 = Utf8 ACTION_POINTER_ID_SHIFT
- #60 = Utf8 FLAG_WINDOW_IS_OBSCURED
- #61 = Utf8 EDGE_TOP
- #62 = Utf8 EDGE_BOTTOM
- #63 = Utf8 EDGE_LEFT
- #64 = Utf8 EDGE_RIGHT
- #65 = Utf8 AXIS_X
- #66 = Utf8 AXIS_Y
- #67 = Utf8 AXIS_PRESSURE
- #68 = Utf8 AXIS_SIZE
- #69 = Utf8 AXIS_TOUCH_MAJOR
- #70 = Utf8 AXIS_TOUCH_MINOR
- #71 = Utf8 AXIS_TOOL_MAJOR
- #72 = Utf8 AXIS_TOOL_MINOR
- #73 = Utf8 AXIS_ORIENTATION
- #74 = Utf8 AXIS_VSCROLL
- #75 = Utf8 AXIS_HSCROLL
- #76 = Utf8 AXIS_Z
- #77 = Integer 11
- #78 = Utf8 AXIS_RX
- #79 = Integer 12
- #80 = Utf8 AXIS_RY
- #81 = Integer 13
- #82 = Utf8 AXIS_RZ
- #83 = Integer 14
- #84 = Utf8 AXIS_HAT_X
- #85 = Integer 15
- #86 = Utf8 AXIS_HAT_Y
- #87 = Integer 16
- #88 = Utf8 AXIS_LTRIGGER
- #89 = Integer 17
- #90 = Utf8 AXIS_RTRIGGER
- #91 = Integer 18
- #92 = Utf8 AXIS_THROTTLE
- #93 = Integer 19
- #94 = Utf8 AXIS_RUDDER
- #95 = Integer 20
- #96 = Utf8 AXIS_WHEEL
- #97 = Integer 21
- #98 = Utf8 AXIS_GAS
- #99 = Integer 22
- #100 = Utf8 AXIS_BRAKE
- #101 = Integer 23
- #102 = Utf8 AXIS_DISTANCE
- #103 = Integer 24
- #104 = Utf8 AXIS_TILT
- #105 = Integer 25
- #106 = Utf8 AXIS_GENERIC_1
- #107 = Integer 32
- #108 = Utf8 AXIS_GENERIC_2
- #109 = Integer 33
- #110 = Utf8 AXIS_GENERIC_3
- #111 = Integer 34
- #112 = Utf8 AXIS_GENERIC_4
- #113 = Integer 35
- #114 = Utf8 AXIS_GENERIC_5
- #115 = Integer 36
- #116 = Utf8 AXIS_GENERIC_6
- #117 = Integer 37
- #118 = Utf8 AXIS_GENERIC_7
- #119 = Integer 38
- #120 = Utf8 AXIS_GENERIC_8
- #121 = Integer 39
- #122 = Utf8 AXIS_GENERIC_9
- #123 = Integer 40
- #124 = Utf8 AXIS_GENERIC_10
- #125 = Integer 41
- #126 = Utf8 AXIS_GENERIC_11
- #127 = Integer 42
- #128 = Utf8 AXIS_GENERIC_12
- #129 = Integer 43
- #130 = Utf8 AXIS_GENERIC_13
- #131 = Integer 44
- #132 = Utf8 AXIS_GENERIC_14
- #133 = Integer 45
- #134 = Utf8 AXIS_GENERIC_15
- #135 = Integer 46
- #136 = Utf8 AXIS_GENERIC_16
- #137 = Integer 47
- #138 = Utf8 BUTTON_PRIMARY
- #139 = Utf8 BUTTON_SECONDARY
- #140 = Utf8 BUTTON_TERTIARY
- #141 = Utf8 BUTTON_BACK
- #142 = Utf8 BUTTON_FORWARD
- #143 = Utf8 TOOL_TYPE_UNKNOWN
- #144 = Utf8 TOOL_TYPE_FINGER
- #145 = Utf8 TOOL_TYPE_STYLUS
- #146 = Utf8 TOOL_TYPE_MOUSE
- #147 = Utf8 TOOL_TYPE_ERASER
- #148 = Utf8 CREATOR
- #149 = Class #303 // android/os/Parcelable$Creator
- #150 = Utf8 Creator
- #151 = Utf8 Landroid/os/Parcelable$Creator;
- #152 = Utf8 Signature
- #153 = Utf8 Landroid/os/Parcelable$Creator<Landroid/view/MotionEvent;>;
- #154 = Utf8 <init>
- #155 = Utf8 ()V
- #156 = Utf8 Code
- #157 = Utf8 LineNumberTable
- #158 = Utf8 LocalVariableTable
- #159 = Utf8 this
- #160 = Utf8 Landroid/view/MotionEvent;
- #161 = Utf8 finalize
- #162 = Utf8 Exceptions
- #163 = Class #304 // java/lang/Throwable
- #164 = Utf8 obtain
- #165 = Utf8 (JJII[Landroid/view/MotionEvent$PointerProperties;[Landroid/view/MotionEvent$PointerCoords;IIFFIIII)Landroid/view/MotionEvent;
- #166 = Utf8 downTime
- #167 = Utf8 J
- #168 = Utf8 eventTime
- #169 = Utf8 action
- #170 = Utf8 pointerCount
- #171 = Utf8 pointerProperties
- #172 = Utf8 [Landroid/view/MotionEvent$PointerProperties;
- #173 = Utf8 pointerCoords
- #174 = Utf8 [Landroid/view/MotionEvent$PointerCoords;
- #175 = Utf8 metaState
- #176 = Utf8 buttonState
- #177 = Utf8 xPrecision
- #178 = Utf8 F
- #179 = Utf8 yPrecision
- #180 = Utf8 deviceId
- #181 = Utf8 edgeFlags
- #182 = Utf8 source
- #183 = Utf8 flags
- #184 = Utf8 (JJII[I[Landroid/view/MotionEvent$PointerCoords;IFFIIII)Landroid/view/MotionEvent;
- #185 = Utf8 pointerIds
- #186 = Utf8 [I
- #187 = Utf8 (JJIFFFFIFFII)Landroid/view/MotionEvent;
- #188 = Utf8 x
- #189 = Utf8 y
- #190 = Utf8 pressure
- #191 = Utf8 size
- #192 = Utf8 (JJIIFFFFIFFII)Landroid/view/MotionEvent;
- #193 = Utf8 (JJIFFI)Landroid/view/MotionEvent;
- #194 = Utf8 (Landroid/view/MotionEvent;)Landroid/view/MotionEvent;
- #195 = Utf8 other
- #196 = Utf8 obtainNoHistory
- #197 = Utf8 recycle
- #198 = Utf8 getDeviceId
- #199 = Utf8 ()I
- #200 = Utf8 getSource
- #201 = Utf8 setSource
- #202 = Utf8 (I)V
- #203 = Utf8 getAction
- #204 = Utf8 getActionMasked
- #205 = Utf8 getActionIndex
- #206 = Utf8 getFlags
- #207 = Utf8 getDownTime
- #208 = Utf8 ()J
- #209 = Utf8 getEventTime
- #210 = Utf8 getX
- #211 = Utf8 ()F
- #212 = Utf8 getY
- #213 = Utf8 getPressure
- #214 = Utf8 getSize
- #215 = Utf8 getTouchMajor
- #216 = Utf8 getTouchMinor
- #217 = Utf8 getToolMajor
- #218 = Utf8 getToolMinor
- #219 = Utf8 getOrientation
- #220 = Utf8 getAxisValue
- #221 = Utf8 (I)F
- #222 = Utf8 axis
- #223 = Utf8 getPointerCount
- #224 = Utf8 getPointerId
- #225 = Utf8 (I)I
- #226 = Utf8 pointerIndex
- #227 = Utf8 getToolType
- #228 = Utf8 findPointerIndex
- #229 = Utf8 pointerId
- #230 = Utf8 (II)F
- #231 = Utf8 getPointerCoords
- #232 = Utf8 (ILandroid/view/MotionEvent$PointerCoords;)V
- #233 = Utf8 outPointerCoords
- #234 = Utf8 Landroid/view/MotionEvent$PointerCoords;
- #235 = Utf8 getPointerProperties
- #236 = Utf8 (ILandroid/view/MotionEvent$PointerProperties;)V
- #237 = Utf8 outPointerProperties
- #238 = Utf8 Landroid/view/MotionEvent$PointerProperties;
- #239 = Utf8 getMetaState
- #240 = Utf8 getButtonState
- #241 = Utf8 getRawX
- #242 = Utf8 getRawY
- #243 = Utf8 getXPrecision
- #244 = Utf8 getYPrecision
- #245 = Utf8 getHistorySize
- #246 = Utf8 getHistoricalEventTime
- #247 = Utf8 (I)J
- #248 = Utf8 pos
- #249 = Utf8 getHistoricalX
- #250 = Utf8 getHistoricalY
- #251 = Utf8 getHistoricalPressure
- #252 = Utf8 getHistoricalSize
- #253 = Utf8 getHistoricalTouchMajor
- #254 = Utf8 getHistoricalTouchMinor
- #255 = Utf8 getHistoricalToolMajor
- #256 = Utf8 getHistoricalToolMinor
- #257 = Utf8 getHistoricalOrientation
- #258 = Utf8 getHistoricalAxisValue
- #259 = Utf8 (III)F
- #260 = Utf8 getHistoricalPointerCoords
- #261 = Utf8 (IILandroid/view/MotionEvent$PointerCoords;)V
- #262 = Utf8 getEdgeFlags
- #263 = Utf8 setEdgeFlags
- #264 = Utf8 setAction
- #265 = Utf8 offsetLocation
- #266 = Utf8 (FF)V
- #267 = Utf8 deltaX
- #268 = Utf8 deltaY
- #269 = Utf8 setLocation
- #270 = Utf8 transform
- #271 = Utf8 (Landroid/graphics/Matrix;)V
- #272 = Utf8 matrix
- #273 = Utf8 Landroid/graphics/Matrix;
- #274 = Utf8 addBatch
- #275 = Utf8 (JFFFFI)V
- #276 = Utf8 (J[Landroid/view/MotionEvent$PointerCoords;I)V
- #277 = Utf8 toString
- #278 = Utf8 ()Ljava/lang/String;
- #279 = Utf8 actionToString
- #280 = Utf8 (I)Ljava/lang/String;
- #281 = Utf8 axisToString
- #282 = Utf8 axisFromString
- #283 = Utf8 (Ljava/lang/String;)I
- #284 = Utf8 symbolicName
- #285 = Utf8 Ljava/lang/String;
- #286 = Utf8 writeToParcel
- #287 = Utf8 (Landroid/os/Parcel;I)V
- #288 = Utf8 out
- #289 = Utf8 Landroid/os/Parcel;
- #290 = Utf8 <clinit>
- #291 = Utf8 SourceFile
- #292 = Utf8 MotionEvent.java
- #293 = NameAndType #154:#155 // "<init>":()V
- #294 = Utf8 java/lang/RuntimeException
- #295 = Utf8 Stub!
- #296 = NameAndType #154:#305 // "<init>":(Ljava/lang/String;)V
- #297 = NameAndType #148:#151 // CREATOR:Landroid/os/Parcelable$Creator;
- #298 = Utf8 android/view/MotionEvent
- #299 = Utf8 android/view/InputEvent
- #300 = Utf8 android/os/Parcelable
- #301 = Utf8 android/view/MotionEvent$PointerProperties
- #302 = Utf8 android/view/MotionEvent$PointerCoords
- #303 = Utf8 android/os/Parcelable$Creator
- #304 = Utf8 java/lang/Throwable
- #305 = Utf8 (Ljava/lang/String;)V
-{
- public static final int INVALID_POINTER_ID;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int -1
-
-
- public static final int ACTION_MASK;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 255
-
-
- public static final int ACTION_DOWN;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 0
-
-
- public static final int ACTION_UP;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 1
-
-
- public static final int ACTION_MOVE;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 2
-
-
- public static final int ACTION_CANCEL;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 3
-
-
- public static final int ACTION_OUTSIDE;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 4
-
-
- public static final int ACTION_POINTER_DOWN;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 5
-
-
- public static final int ACTION_POINTER_UP;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 6
-
-
- public static final int ACTION_HOVER_MOVE;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 7
-
-
- public static final int ACTION_SCROLL;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 8
-
-
- public static final int ACTION_HOVER_ENTER;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 9
-
-
- public static final int ACTION_HOVER_EXIT;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 10
-
-
- public static final int ACTION_POINTER_INDEX_MASK;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 65280
-
-
- public static final int ACTION_POINTER_INDEX_SHIFT;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 8
-
-
- public static final int ACTION_POINTER_1_DOWN;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 5
- Deprecated: true
- RuntimeVisibleAnnotations:
- 0: #48()
-
-
- public static final int ACTION_POINTER_2_DOWN;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 261
- Deprecated: true
- RuntimeVisibleAnnotations:
- 0: #48()
-
-
- public static final int ACTION_POINTER_3_DOWN;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 517
- Deprecated: true
- RuntimeVisibleAnnotations:
- 0: #48()
-
-
- public static final int ACTION_POINTER_1_UP;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 6
- Deprecated: true
- RuntimeVisibleAnnotations:
- 0: #48()
-
-
- public static final int ACTION_POINTER_2_UP;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 262
- Deprecated: true
- RuntimeVisibleAnnotations:
- 0: #48()
-
-
- public static final int ACTION_POINTER_3_UP;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 518
- Deprecated: true
- RuntimeVisibleAnnotations:
- 0: #48()
-
-
- public static final int ACTION_POINTER_ID_MASK;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 65280
- Deprecated: true
- RuntimeVisibleAnnotations:
- 0: #48()
-
-
- public static final int ACTION_POINTER_ID_SHIFT;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 8
- Deprecated: true
- RuntimeVisibleAnnotations:
- 0: #48()
-
-
- public static final int FLAG_WINDOW_IS_OBSCURED;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 1
-
-
- public static final int EDGE_TOP;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 1
-
-
- public static final int EDGE_BOTTOM;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 2
-
-
- public static final int EDGE_LEFT;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 4
-
-
- public static final int EDGE_RIGHT;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 8
-
-
- public static final int AXIS_X;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 0
-
-
- public static final int AXIS_Y;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 1
-
-
- public static final int AXIS_PRESSURE;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 2
-
-
- public static final int AXIS_SIZE;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 3
-
-
- public static final int AXIS_TOUCH_MAJOR;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 4
-
-
- public static final int AXIS_TOUCH_MINOR;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 5
-
-
- public static final int AXIS_TOOL_MAJOR;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 6
-
-
- public static final int AXIS_TOOL_MINOR;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 7
-
-
- public static final int AXIS_ORIENTATION;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 8
-
-
- public static final int AXIS_VSCROLL;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 9
-
-
- public static final int AXIS_HSCROLL;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 10
-
-
- public static final int AXIS_Z;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 11
-
-
- public static final int AXIS_RX;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 12
-
-
- public static final int AXIS_RY;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 13
-
-
- public static final int AXIS_RZ;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 14
-
-
- public static final int AXIS_HAT_X;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 15
-
-
- public static final int AXIS_HAT_Y;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 16
-
-
- public static final int AXIS_LTRIGGER;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 17
-
-
- public static final int AXIS_RTRIGGER;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 18
-
-
- public static final int AXIS_THROTTLE;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 19
-
-
- public static final int AXIS_RUDDER;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 20
-
-
- public static final int AXIS_WHEEL;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 21
-
-
- public static final int AXIS_GAS;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 22
-
-
- public static final int AXIS_BRAKE;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 23
-
-
- public static final int AXIS_DISTANCE;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 24
-
-
- public static final int AXIS_TILT;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 25
-
-
- public static final int AXIS_GENERIC_1;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 32
-
-
- public static final int AXIS_GENERIC_2;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 33
-
-
- public static final int AXIS_GENERIC_3;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 34
-
-
- public static final int AXIS_GENERIC_4;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 35
-
-
- public static final int AXIS_GENERIC_5;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 36
-
-
- public static final int AXIS_GENERIC_6;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 37
-
-
- public static final int AXIS_GENERIC_7;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 38
-
-
- public static final int AXIS_GENERIC_8;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 39
-
-
- public static final int AXIS_GENERIC_9;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 40
-
-
- public static final int AXIS_GENERIC_10;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 41
-
-
- public static final int AXIS_GENERIC_11;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 42
-
-
- public static final int AXIS_GENERIC_12;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 43
-
-
- public static final int AXIS_GENERIC_13;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 44
-
-
- public static final int AXIS_GENERIC_14;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 45
-
-
- public static final int AXIS_GENERIC_15;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 46
-
-
- public static final int AXIS_GENERIC_16;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 47
-
-
- public static final int BUTTON_PRIMARY;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 1
-
-
- public static final int BUTTON_SECONDARY;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 2
-
-
- public static final int BUTTON_TERTIARY;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 4
-
-
- public static final int BUTTON_BACK;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 8
-
-
- public static final int BUTTON_FORWARD;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 16
-
-
- public static final int TOOL_TYPE_UNKNOWN;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 0
-
-
- public static final int TOOL_TYPE_FINGER;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 1
-
-
- public static final int TOOL_TYPE_STYLUS;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 2
-
-
- public static final int TOOL_TYPE_MOUSE;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 3
-
-
- public static final int TOOL_TYPE_ERASER;
- Signature: I
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- ConstantValue: int 4
-
-
- public static final android.os.Parcelable$Creator<android.view.MotionEvent> CREATOR;
- Signature: Landroid/os/Parcelable$Creator;
- flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
- Signature: #153 // Landroid/os/Parcelable$Creator<Landroid/view/MotionEvent;>;
-
-
- android.view.MotionEvent();
- Signature: ()V
- flags:
- Code:
- stack=3, locals=1, args_size=1
- 0: aload_0
- 1: invokespecial #1 // Method android/view/InputEvent."<init>":()V
- 4: new #2 // class java/lang/RuntimeException
- 7: dup
- 8: ldc #3 // String Stub!
- 10: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 13: athrow
- LineNumberTable:
- line 35: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 14 0 this Landroid/view/MotionEvent;
-
- protected void finalize() throws java.lang.Throwable;
- Signature: ()V
- flags: ACC_PROTECTED
- Code:
- stack=3, locals=1, args_size=1
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 36: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- Exceptions:
- throws java.lang.Throwable
-
- public static android.view.MotionEvent obtain(long, long, int, int, android.view.MotionEvent$PointerProperties[], android.view.MotionEvent$PointerCoords[], int, int, float, float, int, int, int, int);
- Signature: (JJII[Landroid/view/MotionEvent$PointerProperties;[Landroid/view/MotionEvent$PointerCoords;IIFFIIII)Landroid/view/MotionEvent;
- flags: ACC_PUBLIC, ACC_STATIC
- Code:
- stack=3, locals=16, args_size=14
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 37: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 downTime J
- 0 10 2 eventTime J
- 0 10 4 action I
- 0 10 5 pointerCount I
- 0 10 6 pointerProperties [Landroid/view/MotionEvent$PointerProperties;
- 0 10 7 pointerCoords [Landroid/view/MotionEvent$PointerCoords;
- 0 10 8 metaState I
- 0 10 9 buttonState I
- 0 10 10 xPrecision F
- 0 10 11 yPrecision F
- 0 10 12 deviceId I
- 0 10 13 edgeFlags I
- 0 10 14 source I
- 0 10 15 flags I
-
- public static android.view.MotionEvent obtain(long, long, int, int, int[], android.view.MotionEvent$PointerCoords[], int, float, float, int, int, int, int);
- Signature: (JJII[I[Landroid/view/MotionEvent$PointerCoords;IFFIIII)Landroid/view/MotionEvent;
- flags: ACC_PUBLIC, ACC_STATIC
- Code:
- stack=3, locals=15, args_size=13
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 39: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 downTime J
- 0 10 2 eventTime J
- 0 10 4 action I
- 0 10 5 pointerCount I
- 0 10 6 pointerIds [I
- 0 10 7 pointerCoords [Landroid/view/MotionEvent$PointerCoords;
- 0 10 8 metaState I
- 0 10 9 xPrecision F
- 0 10 10 yPrecision F
- 0 10 11 deviceId I
- 0 10 12 edgeFlags I
- 0 10 13 source I
- 0 10 14 flags I
- Deprecated: true
- RuntimeVisibleAnnotations:
- 0: #48()
-
- public static android.view.MotionEvent obtain(long, long, int, float, float, float, float, int, float, float, int, int);
- Signature: (JJIFFFFIFFII)Landroid/view/MotionEvent;
- flags: ACC_PUBLIC, ACC_STATIC
- Code:
- stack=3, locals=14, args_size=12
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 40: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 downTime J
- 0 10 2 eventTime J
- 0 10 4 action I
- 0 10 5 x F
- 0 10 6 y F
- 0 10 7 pressure F
- 0 10 8 size F
- 0 10 9 metaState I
- 0 10 10 xPrecision F
- 0 10 11 yPrecision F
- 0 10 12 deviceId I
- 0 10 13 edgeFlags I
-
- public static android.view.MotionEvent obtain(long, long, int, int, float, float, float, float, int, float, float, int, int);
- Signature: (JJIIFFFFIFFII)Landroid/view/MotionEvent;
- flags: ACC_PUBLIC, ACC_STATIC
- Code:
- stack=3, locals=15, args_size=13
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 42: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 downTime J
- 0 10 2 eventTime J
- 0 10 4 action I
- 0 10 5 pointerCount I
- 0 10 6 x F
- 0 10 7 y F
- 0 10 8 pressure F
- 0 10 9 size F
- 0 10 10 metaState I
- 0 10 11 xPrecision F
- 0 10 12 yPrecision F
- 0 10 13 deviceId I
- 0 10 14 edgeFlags I
- Deprecated: true
- RuntimeVisibleAnnotations:
- 0: #48()
-
- public static android.view.MotionEvent obtain(long, long, int, float, float, int);
- Signature: (JJIFFI)Landroid/view/MotionEvent;
- flags: ACC_PUBLIC, ACC_STATIC
- Code:
- stack=3, locals=8, args_size=6
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 43: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 downTime J
- 0 10 2 eventTime J
- 0 10 4 action I
- 0 10 5 x F
- 0 10 6 y F
- 0 10 7 metaState I
-
- public static android.view.MotionEvent obtain(android.view.MotionEvent);
- Signature: (Landroid/view/MotionEvent;)Landroid/view/MotionEvent;
- flags: ACC_PUBLIC, ACC_STATIC
- Code:
- stack=3, locals=1, args_size=1
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 44: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 other Landroid/view/MotionEvent;
-
- public static android.view.MotionEvent obtainNoHistory(android.view.MotionEvent);
- Signature: (Landroid/view/MotionEvent;)Landroid/view/MotionEvent;
- flags: ACC_PUBLIC, ACC_STATIC
- Code:
- stack=3, locals=1, args_size=1
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 45: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 other Landroid/view/MotionEvent;
-
- public final void recycle();
- Signature: ()V
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=1, args_size=1
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 46: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
- public final int getDeviceId();
- Signature: ()I
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=1, args_size=1
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 47: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
- public final int getSource();
- Signature: ()I
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=1, args_size=1
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 48: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
- public final void setSource(int);
- Signature: (I)V
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=2, args_size=2
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 49: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 source I
-
- public final int getAction();
- Signature: ()I
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=1, args_size=1
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 50: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
- public final int getActionMasked();
- Signature: ()I
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=1, args_size=1
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 51: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
- public final int getActionIndex();
- Signature: ()I
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=1, args_size=1
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 52: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
- public final int getFlags();
- Signature: ()I
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=1, args_size=1
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 53: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
- public final long getDownTime();
- Signature: ()J
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=1, args_size=1
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 54: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
- public final long getEventTime();
- Signature: ()J
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=1, args_size=1
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 55: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
- public final float getX();
- Signature: ()F
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=1, args_size=1
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 56: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
- public final float getY();
- Signature: ()F
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=1, args_size=1
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 57: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
- public final float getPressure();
- Signature: ()F
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=1, args_size=1
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 58: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
- public final float getSize();
- Signature: ()F
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=1, args_size=1
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 59: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
- public final float getTouchMajor();
- Signature: ()F
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=1, args_size=1
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 60: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
- public final float getTouchMinor();
- Signature: ()F
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=1, args_size=1
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 61: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
- public final float getToolMajor();
- Signature: ()F
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=1, args_size=1
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 62: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
- public final float getToolMinor();
- Signature: ()F
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=1, args_size=1
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 63: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
- public final float getOrientation();
- Signature: ()F
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=1, args_size=1
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 64: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
- public final float getAxisValue(int);
- Signature: (I)F
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=2, args_size=2
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 65: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 axis I
-
- public final int getPointerCount();
- Signature: ()I
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=1, args_size=1
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 66: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
- public final int getPointerId(int);
- Signature: (I)I
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=2, args_size=2
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 67: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
-
- public final int getToolType(int);
- Signature: (I)I
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=2, args_size=2
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 68: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
-
- public final int findPointerIndex(int);
- Signature: (I)I
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=2, args_size=2
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 69: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerId I
-
- public final float getX(int);
- Signature: (I)F
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=2, args_size=2
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 70: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
-
- public final float getY(int);
- Signature: (I)F
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=2, args_size=2
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 71: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
-
- public final float getPressure(int);
- Signature: (I)F
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=2, args_size=2
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 72: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
-
- public final float getSize(int);
- Signature: (I)F
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=2, args_size=2
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 73: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
-
- public final float getTouchMajor(int);
- Signature: (I)F
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=2, args_size=2
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 74: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
-
- public final float getTouchMinor(int);
- Signature: (I)F
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=2, args_size=2
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 75: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
-
- public final float getToolMajor(int);
- Signature: (I)F
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=2, args_size=2
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 76: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
-
- public final float getToolMinor(int);
- Signature: (I)F
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=2, args_size=2
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 77: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
-
- public final float getOrientation(int);
- Signature: (I)F
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=2, args_size=2
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 78: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
-
- public final float getAxisValue(int, int);
- Signature: (II)F
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=3, args_size=3
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 79: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 axis I
- 0 10 2 pointerIndex I
-
- public final void getPointerCoords(int, android.view.MotionEvent$PointerCoords);
- Signature: (ILandroid/view/MotionEvent$PointerCoords;)V
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=3, args_size=3
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 80: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
- 0 10 2 outPointerCoords Landroid/view/MotionEvent$PointerCoords;
-
- public final void getPointerProperties(int, android.view.MotionEvent$PointerProperties);
- Signature: (ILandroid/view/MotionEvent$PointerProperties;)V
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=3, args_size=3
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 81: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
- 0 10 2 outPointerProperties Landroid/view/MotionEvent$PointerProperties;
-
- public final int getMetaState();
- Signature: ()I
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=1, args_size=1
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 82: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
- public final int getButtonState();
- Signature: ()I
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=1, args_size=1
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 83: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
- public final float getRawX();
- Signature: ()F
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=1, args_size=1
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 84: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
- public final float getRawY();
- Signature: ()F
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=1, args_size=1
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 85: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
- public final float getXPrecision();
- Signature: ()F
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=1, args_size=1
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 86: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
- public final float getYPrecision();
- Signature: ()F
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=1, args_size=1
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 87: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
- public final int getHistorySize();
- Signature: ()I
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=1, args_size=1
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 88: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
- public final long getHistoricalEventTime(int);
- Signature: (I)J
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=2, args_size=2
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 89: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pos I
-
- public final float getHistoricalX(int);
- Signature: (I)F
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=2, args_size=2
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 90: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pos I
-
- public final float getHistoricalY(int);
- Signature: (I)F
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=2, args_size=2
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 91: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pos I
-
- public final float getHistoricalPressure(int);
- Signature: (I)F
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=2, args_size=2
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 92: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pos I
-
- public final float getHistoricalSize(int);
- Signature: (I)F
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=2, args_size=2
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 93: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pos I
-
- public final float getHistoricalTouchMajor(int);
- Signature: (I)F
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=2, args_size=2
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 94: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pos I
-
- public final float getHistoricalTouchMinor(int);
- Signature: (I)F
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=2, args_size=2
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 95: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pos I
-
- public final float getHistoricalToolMajor(int);
- Signature: (I)F
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=2, args_size=2
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 96: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pos I
-
- public final float getHistoricalToolMinor(int);
- Signature: (I)F
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=2, args_size=2
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 97: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pos I
-
- public final float getHistoricalOrientation(int);
- Signature: (I)F
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=2, args_size=2
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 98: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pos I
-
- public final float getHistoricalAxisValue(int, int);
- Signature: (II)F
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=3, args_size=3
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 99: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 axis I
- 0 10 2 pos I
-
- public final float getHistoricalX(int, int);
- Signature: (II)F
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=3, args_size=3
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 100: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
- 0 10 2 pos I
-
- public final float getHistoricalY(int, int);
- Signature: (II)F
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=3, args_size=3
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 101: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
- 0 10 2 pos I
-
- public final float getHistoricalPressure(int, int);
- Signature: (II)F
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=3, args_size=3
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 102: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
- 0 10 2 pos I
-
- public final float getHistoricalSize(int, int);
- Signature: (II)F
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=3, args_size=3
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 103: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
- 0 10 2 pos I
-
- public final float getHistoricalTouchMajor(int, int);
- Signature: (II)F
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=3, args_size=3
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 104: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
- 0 10 2 pos I
-
- public final float getHistoricalTouchMinor(int, int);
- Signature: (II)F
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=3, args_size=3
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 105: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
- 0 10 2 pos I
-
- public final float getHistoricalToolMajor(int, int);
- Signature: (II)F
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=3, args_size=3
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 106: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
- 0 10 2 pos I
-
- public final float getHistoricalToolMinor(int, int);
- Signature: (II)F
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=3, args_size=3
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 107: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
- 0 10 2 pos I
-
- public final float getHistoricalOrientation(int, int);
- Signature: (II)F
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=3, args_size=3
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 108: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
- 0 10 2 pos I
-
- public final float getHistoricalAxisValue(int, int, int);
- Signature: (III)F
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=4, args_size=4
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 109: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 axis I
- 0 10 2 pointerIndex I
- 0 10 3 pos I
-
- public final void getHistoricalPointerCoords(int, int, android.view.MotionEvent$PointerCoords);
- Signature: (IILandroid/view/MotionEvent$PointerCoords;)V
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=4, args_size=4
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 110: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 pointerIndex I
- 0 10 2 pos I
- 0 10 3 outPointerCoords Landroid/view/MotionEvent$PointerCoords;
-
- public final int getEdgeFlags();
- Signature: ()I
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=1, args_size=1
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 111: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
- public final void setEdgeFlags(int);
- Signature: (I)V
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=2, args_size=2
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 112: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 flags I
-
- public final void setAction(int);
- Signature: (I)V
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=2, args_size=2
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 113: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 action I
-
- public final void offsetLocation(float, float);
- Signature: (FF)V
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=3, args_size=3
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 114: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 deltaX F
- 0 10 2 deltaY F
-
- public final void setLocation(float, float);
- Signature: (FF)V
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=3, args_size=3
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 115: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 x F
- 0 10 2 y F
-
- public final void transform(android.graphics.Matrix);
- Signature: (Landroid/graphics/Matrix;)V
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=2, args_size=2
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 116: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 matrix Landroid/graphics/Matrix;
-
- public final void addBatch(long, float, float, float, float, int);
- Signature: (JFFFFI)V
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=8, args_size=7
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 117: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 eventTime J
- 0 10 3 x F
- 0 10 4 y F
- 0 10 5 pressure F
- 0 10 6 size F
- 0 10 7 metaState I
-
- public final void addBatch(long, android.view.MotionEvent$PointerCoords[], int);
- Signature: (J[Landroid/view/MotionEvent$PointerCoords;I)V
- flags: ACC_PUBLIC, ACC_FINAL
- Code:
- stack=3, locals=5, args_size=4
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 118: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 eventTime J
- 0 10 3 pointerCoords [Landroid/view/MotionEvent$PointerCoords;
- 0 10 4 metaState I
-
- public java.lang.String toString();
- Signature: ()Ljava/lang/String;
- flags: ACC_PUBLIC
- Code:
- stack=3, locals=1, args_size=1
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 119: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
-
- public static java.lang.String actionToString(int);
- Signature: (I)Ljava/lang/String;
- flags: ACC_PUBLIC, ACC_STATIC
- Code:
- stack=3, locals=1, args_size=1
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 120: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 action I
-
- public static java.lang.String axisToString(int);
- Signature: (I)Ljava/lang/String;
- flags: ACC_PUBLIC, ACC_STATIC
- Code:
- stack=3, locals=1, args_size=1
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 121: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 axis I
-
- public static int axisFromString(java.lang.String);
- Signature: (Ljava/lang/String;)I
- flags: ACC_PUBLIC, ACC_STATIC
- Code:
- stack=3, locals=1, args_size=1
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 122: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 symbolicName Ljava/lang/String;
-
- public void writeToParcel(android.os.Parcel, int);
- Signature: (Landroid/os/Parcel;I)V
- flags: ACC_PUBLIC
- Code:
- stack=3, locals=3, args_size=3
- 0: new #2 // class java/lang/RuntimeException
- 3: dup
- 4: ldc #3 // String Stub!
- 6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
- LineNumberTable:
- line 123: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Landroid/view/MotionEvent;
- 0 10 1 out Landroid/os/Parcel;
- 0 10 2 flags I
-
- static {};
- Signature: ()V
- flags: ACC_STATIC
- Code:
- stack=1, locals=0, args_size=0
- 0: aconst_null
- 1: putstatic #5 // Field CREATOR:Landroid/os/Parcelable$Creator;
- 4: return
- LineNumberTable:
- line 213: 0
-}
diff --git a/base/android/jni_generator/testMultipleJNIAdditionalImport.golden b/base/android/jni_generator/testMultipleJNIAdditionalImport.golden
deleted file mode 100644
index b0db9dd772..0000000000
--- a/base/android/jni_generator/testMultipleJNIAdditionalImport.golden
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright 2014 The Chromium 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.py
-// For
-// org/chromium/foo/Foo
-
-#ifndef org_chromium_foo_Foo_JNI
-#define org_chromium_foo_Foo_JNI
-
-#include <jni.h>
-
-#include "base/android/jni_generator/jni_generator_helper.h"
-
-#include "base/android/jni_int_wrapper.h"
-
-// Step 1: forward declarations.
-namespace {
-const char kFooClassPath[] = "org/chromium/foo/Foo";
-// Leaking this jclass as we cannot use LazyInstance from some threads.
-jclass g_Foo_clazz = NULL;
-#define Foo_clazz(env) g_Foo_clazz
-
-} // namespace
-
-static void DoSomething(JNIEnv* env, jclass jcaller,
- jobject callback1,
- jobject callback2);
-
-// Step 2: method stubs.
-
-static base::subtle::AtomicWord g_Foo_calledByNative = 0;
-static void Java_Foo_calledByNative(JNIEnv* env, jobject callback1,
- jobject callback2) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, Foo_clazz(env),
- Foo_clazz(env));
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_STATIC>(
- env, Foo_clazz(env),
- "calledByNative",
-
-"("
-"Lorg/chromium/foo/Bar1$Callback;"
-"Lorg/chromium/foo/Bar2$Callback;"
-")"
-"V",
- &g_Foo_calledByNative);
-
- env->CallStaticVoidMethod(Foo_clazz(env),
- method_id, callback1, callback2);
- jni_generator::CheckException(env);
-
-}
-
-// Step 3: RegisterNatives.
-
-static const JNINativeMethod kMethodsFoo[] = {
- { "nativeDoSomething",
-"("
-"Lorg/chromium/foo/Bar1$Callback;"
-"Lorg/chromium/foo/Bar2$Callback;"
-")"
-"V", reinterpret_cast<void*>(DoSomething) },
-};
-
-static bool RegisterNativesImpl(JNIEnv* env) {
-
- g_Foo_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
- base::android::GetClass(env, kFooClassPath).obj()));
-
- const int kMethodsFooSize = arraysize(kMethodsFoo);
-
- if (env->RegisterNatives(Foo_clazz(env),
- kMethodsFoo,
- kMethodsFooSize) < 0) {
- jni_generator::HandleRegistrationError(
- env, Foo_clazz(env), __FILE__);
- return false;
- }
-
- return true;
-}
-
-#endif // org_chromium_foo_Foo_JNI
diff --git a/base/android/jni_generator/testNativeExportsOption.golden b/base/android/jni_generator/testNativeExportsOption.golden
deleted file mode 100644
index 395fc390e3..0000000000
--- a/base/android/jni_generator/testNativeExportsOption.golden
+++ /dev/null
@@ -1,219 +0,0 @@
-// Copyright 2014 The Chromium 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.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 <jni.h>
-
-#include "base/android/jni_generator/jni_generator_helper.h"
-
-#include "base/android/jni_int_wrapper.h"
-
-// Step 1: forward declarations.
-namespace {
-const char kSampleForTestsClassPath[] =
- "org/chromium/example/jni_generator/SampleForTests";
-// Leaking this jclass as we cannot use LazyInstance from some threads.
-base::subtle::AtomicWord g_SampleForTests_clazz __attribute__((unused)) = 0;
-#define SampleForTests_clazz(env) base::android::LazyGetClass(env, kSampleForTestsClassPath, &g_SampleForTests_clazz)
-
-} // namespace
-
-extern "C" {
-
-static jint Init(JNIEnv* env, jobject jcaller);
-
-__attribute__((visibility("default")))
-jint
- Java_org_chromium_example_jni_1generator_SampleForTests_00024MyInnerClass_nativeInit(JNIEnv*
- env, jobject jcaller) {
- return Init(env, jcaller);
-}
-
-static jint Init(JNIEnv* env, jobject jcaller);
-
-__attribute__((visibility("default")))
-jint
- Java_org_chromium_example_jni_1generator_SampleForTests_00024MyOtherInnerClass_nativeInit(JNIEnv*
- env, jobject jcaller) {
- return Init(env, jcaller);
-}
-
-}; // extern "C"
-
-// Step 2: method stubs.
-
-extern "C" {
-__attribute__((visibility("default")))
-jint
- Java_org_chromium_example_jni_1generator_SampleForTests_nativeStaticMethod(JNIEnv*
- env,
- jobject jcaller,
- jlong nativeTest,
- jint arg1) {
- Test* native = reinterpret_cast<Test*>(nativeTest);
- CHECK_NATIVE_PTR(env, jcaller, native, "StaticMethod", 0);
- return native->StaticMethod(env, jcaller, arg1);
-}
-
-__attribute__((visibility("default")))
-jint
- Java_org_chromium_example_jni_1generator_SampleForTests_nativeMethod(JNIEnv*
- env,
- jobject jcaller,
- jlong nativeTest,
- jint arg1) {
- Test* native = reinterpret_cast<Test*>(nativeTest);
- CHECK_NATIVE_PTR(env, jcaller, native, "Method", 0);
- return native->Method(env, jcaller, arg1);
-}
-
-static base::subtle::AtomicWord g_SampleForTests_testMethodWithParam = 0;
-static void Java_SampleForTests_testMethodWithParam(JNIEnv* env, jobject obj,
- JniIntWrapper iParam) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- SampleForTests_clazz(env));
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, SampleForTests_clazz(env),
- "testMethodWithParam",
-
-"("
-"I"
-")"
-"V",
- &g_SampleForTests_testMethodWithParam);
-
- env->CallVoidMethod(obj,
- method_id, as_jint(iParam));
- jni_generator::CheckException(env);
-
-}
-
-static base::subtle::AtomicWord g_SampleForTests_testMethodWithParamAndReturn =
- 0;
-static base::android::ScopedJavaLocalRef<jstring>
- Java_SampleForTests_testMethodWithParamAndReturn(JNIEnv* env, jobject obj,
- JniIntWrapper iParam) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- SampleForTests_clazz(env), NULL);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, SampleForTests_clazz(env),
- "testMethodWithParamAndReturn",
-
-"("
-"I"
-")"
-"Ljava/lang/String;",
- &g_SampleForTests_testMethodWithParamAndReturn);
-
- jstring ret =
- static_cast<jstring>(env->CallObjectMethod(obj,
- method_id, as_jint(iParam)));
- jni_generator::CheckException(env);
- return base::android::ScopedJavaLocalRef<jstring>(env, ret);
-}
-
-static base::subtle::AtomicWord g_SampleForTests_testStaticMethodWithParam = 0;
-static jint Java_SampleForTests_testStaticMethodWithParam(JNIEnv* env,
- JniIntWrapper iParam) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, SampleForTests_clazz(env),
- SampleForTests_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_STATIC>(
- env, SampleForTests_clazz(env),
- "testStaticMethodWithParam",
-
-"("
-"I"
-")"
-"I",
- &g_SampleForTests_testStaticMethodWithParam);
-
- jint ret =
- env->CallStaticIntMethod(SampleForTests_clazz(env),
- method_id, as_jint(iParam));
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_SampleForTests_testMethodWithNoParam = 0;
-static jdouble Java_SampleForTests_testMethodWithNoParam(JNIEnv* env) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, SampleForTests_clazz(env),
- SampleForTests_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_STATIC>(
- env, SampleForTests_clazz(env),
- "testMethodWithNoParam",
-
-"("
-")"
-"D",
- &g_SampleForTests_testMethodWithNoParam);
-
- jdouble ret =
- env->CallStaticDoubleMethod(SampleForTests_clazz(env),
- method_id);
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_SampleForTests_testStaticMethodWithNoParam =
- 0;
-static base::android::ScopedJavaLocalRef<jstring>
- Java_SampleForTests_testStaticMethodWithNoParam(JNIEnv* env) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, SampleForTests_clazz(env),
- SampleForTests_clazz(env), NULL);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_STATIC>(
- env, SampleForTests_clazz(env),
- "testStaticMethodWithNoParam",
-
-"("
-")"
-"Ljava/lang/String;",
- &g_SampleForTests_testStaticMethodWithNoParam);
-
- jstring ret =
-static_cast<jstring>(env->CallStaticObjectMethod(SampleForTests_clazz(env),
- method_id));
- jni_generator::CheckException(env);
- return base::android::ScopedJavaLocalRef<jstring>(env, ret);
-}
-}; // extern "C"
-
-// Step 3: RegisterNatives.
-
-static bool RegisterNativesImpl(JNIEnv* env, jclass clazz) {
-
- base::subtle::Release_Store(&g_SampleForTests_clazz,
- static_cast<base::subtle::AtomicWord>(env->NewWeakGlobalRef(clazz));
-
- return true;
-}
-
-extern "C" JNIEXPORT bool JNICALL
-Java_org_chromium_example_jni_1generator_SampleForTests_nativeInitNativeClass(JNIEnv*
- env, jclass clazz) {
- return RegisterNativesImpl(env, clazz);
-}
-
-#endif // org_chromium_example_jni_generator_SampleForTests_JNI
diff --git a/base/android/jni_generator/testNativeExportsOptionalOption.golden b/base/android/jni_generator/testNativeExportsOptionalOption.golden
deleted file mode 100644
index f47cb98e18..0000000000
--- a/base/android/jni_generator/testNativeExportsOptionalOption.golden
+++ /dev/null
@@ -1,288 +0,0 @@
-// Copyright 2014 The Chromium 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.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 <jni.h>
-
-#include "base/android/jni_generator/jni_generator_helper.h"
-
-#include "base/android/jni_int_wrapper.h"
-
-// Step 1: forward declarations.
-namespace {
-const char kSampleForTestsClassPath[] =
- "org/chromium/example/jni_generator/SampleForTests";
-// Leaking this jclass as we cannot use LazyInstance from some threads.
-base::subtle::AtomicWord g_SampleForTests_clazz __attribute__((unused)) = 0;
-#define SampleForTests_clazz(env) base::android::LazyGetClass(env, kSampleForTestsClassPath, &g_SampleForTests_clazz)
-
-} // namespace
-
-extern "C" {
-
-static jint Init(JNIEnv* env, jobject jcaller);
-
-__attribute__((visibility("default")))
-jint
- Java_org_chromium_example_jni_1generator_SampleForTests_00024MyInnerClass_nativeInit(JNIEnv*
- env, jobject jcaller) {
- return Init(env, jcaller);
-}
-
-static jint Init(JNIEnv* env, jobject jcaller);
-
-__attribute__((visibility("default")))
-jint
- Java_org_chromium_example_jni_1generator_SampleForTests_00024MyOtherInnerClass_nativeInit(JNIEnv*
- env, jobject jcaller) {
- return Init(env, jcaller);
-}
-
-}; // extern "C"
-
-// Step 2: method stubs.
-
-extern "C" {
-__attribute__((visibility("default")))
-jint
- Java_org_chromium_example_jni_1generator_SampleForTests_nativeStaticMethod(JNIEnv*
- env,
- jobject jcaller,
- jlong nativeTest,
- jint arg1) {
- Test* native = reinterpret_cast<Test*>(nativeTest);
- CHECK_NATIVE_PTR(env, jcaller, native, "StaticMethod", 0);
- return native->StaticMethod(env, jcaller, arg1);
-}
-
-__attribute__((visibility("default")))
-jint
- Java_org_chromium_example_jni_1generator_SampleForTests_nativeMethod(JNIEnv*
- env,
- jobject jcaller,
- jlong nativeTest,
- jint arg1) {
- Test* native = reinterpret_cast<Test*>(nativeTest);
- CHECK_NATIVE_PTR(env, jcaller, native, "Method", 0);
- return native->Method(env, jcaller, arg1);
-}
-
-static base::subtle::AtomicWord g_SampleForTests_testMethodWithParam = 0;
-static void Java_SampleForTests_testMethodWithParam(JNIEnv* env, jobject obj,
- JniIntWrapper iParam) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- SampleForTests_clazz(env));
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, SampleForTests_clazz(env),
- "testMethodWithParam",
-
-"("
-"I"
-")"
-"V",
- &g_SampleForTests_testMethodWithParam);
-
- env->CallVoidMethod(obj,
- method_id, as_jint(iParam));
- jni_generator::CheckException(env);
-
-}
-
-static base::subtle::AtomicWord g_SampleForTests_testMethodWithParamAndReturn =
- 0;
-static base::android::ScopedJavaLocalRef<jstring>
- Java_SampleForTests_testMethodWithParamAndReturn(JNIEnv* env, jobject obj,
- JniIntWrapper iParam) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, obj,
- SampleForTests_clazz(env), NULL);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_INSTANCE>(
- env, SampleForTests_clazz(env),
- "testMethodWithParamAndReturn",
-
-"("
-"I"
-")"
-"Ljava/lang/String;",
- &g_SampleForTests_testMethodWithParamAndReturn);
-
- jstring ret =
- static_cast<jstring>(env->CallObjectMethod(obj,
- method_id, as_jint(iParam)));
- jni_generator::CheckException(env);
- return base::android::ScopedJavaLocalRef<jstring>(env, ret);
-}
-
-static base::subtle::AtomicWord g_SampleForTests_testStaticMethodWithParam = 0;
-static jint Java_SampleForTests_testStaticMethodWithParam(JNIEnv* env,
- JniIntWrapper iParam) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, SampleForTests_clazz(env),
- SampleForTests_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_STATIC>(
- env, SampleForTests_clazz(env),
- "testStaticMethodWithParam",
-
-"("
-"I"
-")"
-"I",
- &g_SampleForTests_testStaticMethodWithParam);
-
- jint ret =
- env->CallStaticIntMethod(SampleForTests_clazz(env),
- method_id, as_jint(iParam));
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_SampleForTests_testMethodWithNoParam = 0;
-static jdouble Java_SampleForTests_testMethodWithNoParam(JNIEnv* env) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, SampleForTests_clazz(env),
- SampleForTests_clazz(env), 0);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_STATIC>(
- env, SampleForTests_clazz(env),
- "testMethodWithNoParam",
-
-"("
-")"
-"D",
- &g_SampleForTests_testMethodWithNoParam);
-
- jdouble ret =
- env->CallStaticDoubleMethod(SampleForTests_clazz(env),
- method_id);
- jni_generator::CheckException(env);
- return ret;
-}
-
-static base::subtle::AtomicWord g_SampleForTests_testStaticMethodWithNoParam =
- 0;
-static base::android::ScopedJavaLocalRef<jstring>
- Java_SampleForTests_testStaticMethodWithNoParam(JNIEnv* env) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, SampleForTests_clazz(env),
- SampleForTests_clazz(env), NULL);
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_STATIC>(
- env, SampleForTests_clazz(env),
- "testStaticMethodWithNoParam",
-
-"("
-")"
-"Ljava/lang/String;",
- &g_SampleForTests_testStaticMethodWithNoParam);
-
- jstring ret =
-static_cast<jstring>(env->CallStaticObjectMethod(SampleForTests_clazz(env),
- method_id));
- jni_generator::CheckException(env);
- return base::android::ScopedJavaLocalRef<jstring>(env, ret);
-}
-}; // extern "C"
-
-// Step 3: RegisterNatives.
-
-static const JNINativeMethod kMethodsMyOtherInnerClass[] = {
- { "nativeInit",
-"("
-")"
-"I",
- reinterpret_cast<void*>(Java_org_chromium_example_jni_1generator_SampleForTests_00024MyOtherInnerClass_nativeInit)
- },
-};
-
-static const JNINativeMethod kMethodsMyInnerClass[] = {
- { "nativeInit",
-"("
-")"
-"I",
- reinterpret_cast<void*>(Java_org_chromium_example_jni_1generator_SampleForTests_00024MyInnerClass_nativeInit)
- },
-};
-
-static const JNINativeMethod kMethodsSampleForTests[] = {
- { "nativeStaticMethod",
-"("
-"J"
-"I"
-")"
-"I",
- reinterpret_cast<void*>(Java_org_chromium_example_jni_1generator_SampleForTests_nativeStaticMethod)
- },
- { "nativeMethod",
-"("
-"J"
-"I"
-")"
-"I",
- reinterpret_cast<void*>(Java_org_chromium_example_jni_1generator_SampleForTests_nativeMethod)
- },
-};
-
-static bool RegisterNativesImpl(JNIEnv* env, jclass clazz) {
- if (base::android::IsManualJniRegistrationDisabled()) return true;
-
- base::subtle::Release_Store(&g_SampleForTests_clazz,
- static_cast<base::subtle::AtomicWord>(env->NewWeakGlobalRef(clazz));
-
- const int kMethodsMyOtherInnerClassSize =
- arraysize(kMethodsMyOtherInnerClass);
-
- if (env->RegisterNatives(MyOtherInnerClass_clazz(env),
- kMethodsMyOtherInnerClass,
- kMethodsMyOtherInnerClassSize) < 0) {
- jni_generator::HandleRegistrationError(
- env, MyOtherInnerClass_clazz(env), __FILE__);
- return false;
- }
-
- const int kMethodsMyInnerClassSize = arraysize(kMethodsMyInnerClass);
-
- if (env->RegisterNatives(MyInnerClass_clazz(env),
- kMethodsMyInnerClass,
- kMethodsMyInnerClassSize) < 0) {
- jni_generator::HandleRegistrationError(
- env, MyInnerClass_clazz(env), __FILE__);
- return false;
- }
-
- const int kMethodsSampleForTestsSize = arraysize(kMethodsSampleForTests);
-
- if (env->RegisterNatives(SampleForTests_clazz(env),
- kMethodsSampleForTests,
- kMethodsSampleForTestsSize) < 0) {
- jni_generator::HandleRegistrationError(
- env, SampleForTests_clazz(env), __FILE__);
- return false;
- }
-
- return true;
-}
-
-extern "C" JNIEXPORT bool JNICALL
-Java_org_chromium_example_jni_1generator_SampleForTests_nativeInitNativeClass(JNIEnv*
- env, jclass clazz) {
- return RegisterNativesImpl(env, clazz);
-}
-
-#endif // org_chromium_example_jni_generator_SampleForTests_JNI
diff --git a/base/android/jni_generator/testNatives.golden b/base/android/jni_generator/testNatives.golden
deleted file mode 100644
index e5a4fab732..0000000000
--- a/base/android/jni_generator/testNatives.golden
+++ /dev/null
@@ -1,218 +0,0 @@
-// Copyright 2014 The Chromium 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.py
-// For
-// org/chromium/TestJni
-
-#ifndef org_chromium_TestJni_JNI
-#define org_chromium_TestJni_JNI
-
-#include <jni.h>
-
-#include "base/android/jni_generator/jni_generator_helper.h"
-
-#include "base/android/jni_int_wrapper.h"
-
-// 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;
-#define TestJni_clazz(env) g_TestJni_clazz
-
-} // namespace
-
-static jint Init(JNIEnv* env, jobject jcaller);
-
-static jstring GetDomainAndRegistry(JNIEnv* env, jclass jcaller,
- jstring url);
-
-static void CreateHistoricalTabFromState(JNIEnv* env, jclass jcaller,
- jbyteArray state,
- jint tab_index);
-
-static jbyteArray GetStateAsByteArray(JNIEnv* env, jobject jcaller,
- jobject view);
-
-static jobjectArray GetAutofillProfileGUIDs(JNIEnv* env, jclass jcaller);
-
-static void SetRecognitionResults(JNIEnv* env, jobject jcaller,
- jint sessionId,
- jobjectArray results);
-
-static jint FindAll(JNIEnv* env, jobject jcaller,
- jstring find);
-
-static jobject GetInnerClass(JNIEnv* env, jclass jcaller);
-
-// Step 2: method stubs.
-static void Destroy(JNIEnv* env, jobject jcaller,
- jint nativeChromeBrowserProvider) {
- ChromeBrowserProvider* native =
- reinterpret_cast<ChromeBrowserProvider*>(nativeChromeBrowserProvider);
- CHECK_NATIVE_PTR(env, jcaller, native, "Destroy");
- return native->Destroy(env, jcaller);
-}
-
-static jlong AddBookmark(JNIEnv* env, jobject jcaller,
- jint nativeChromeBrowserProvider,
- jstring url,
- jstring title,
- jboolean isFolder,
- jlong parentId) {
- ChromeBrowserProvider* native =
- reinterpret_cast<ChromeBrowserProvider*>(nativeChromeBrowserProvider);
- CHECK_NATIVE_PTR(env, jcaller, native, "AddBookmark", 0);
- return native->AddBookmark(env, jcaller, url, title, isFolder, parentId);
-}
-
-static jlong AddBookmarkFromAPI(JNIEnv* env, jobject jcaller,
- jint nativeChromeBrowserProvider,
- jstring url,
- jobject created,
- jobject isBookmark,
- jobject date,
- jbyteArray favicon,
- jstring title,
- jobject visits) {
- ChromeBrowserProvider* native =
- reinterpret_cast<ChromeBrowserProvider*>(nativeChromeBrowserProvider);
- CHECK_NATIVE_PTR(env, jcaller, native, "AddBookmarkFromAPI", 0);
- return native->AddBookmarkFromAPI(env, jcaller, url, created, isBookmark,
- date, favicon, title, visits);
-}
-
-static jobject QueryBitmap(JNIEnv* env, jobject jcaller,
- jint nativeChromeBrowserProvider,
- jobjectArray projection,
- jstring selection,
- jobjectArray selectionArgs,
- jstring sortOrder) {
- ChromeBrowserProvider* native =
- reinterpret_cast<ChromeBrowserProvider*>(nativeChromeBrowserProvider);
- CHECK_NATIVE_PTR(env, jcaller, native, "QueryBitmap", NULL);
- return native->QueryBitmap(env, jcaller, projection, selection, selectionArgs,
- sortOrder).Release();
-}
-
-static void GotOrientation(JNIEnv* env, jobject jcaller,
- jint nativeDataFetcherImplAndroid,
- jdouble alpha,
- jdouble beta,
- jdouble gamma) {
- DataFetcherImplAndroid* native =
- reinterpret_cast<DataFetcherImplAndroid*>(nativeDataFetcherImplAndroid);
- CHECK_NATIVE_PTR(env, jcaller, native, "GotOrientation");
- return native->GotOrientation(env, jcaller, alpha, beta, gamma);
-}
-
-// Step 3: RegisterNatives.
-
-static const JNINativeMethod kMethodsTestJni[] = {
- { "nativeInit",
-"("
-")"
-"I", reinterpret_cast<void*>(Init) },
- { "nativeDestroy",
-"("
-"I"
-")"
-"V", reinterpret_cast<void*>(Destroy) },
- { "nativeAddBookmark",
-"("
-"I"
-"Ljava/lang/String;"
-"Ljava/lang/String;"
-"Z"
-"J"
-")"
-"J", reinterpret_cast<void*>(AddBookmark) },
- { "nativeGetDomainAndRegistry",
-"("
-"Ljava/lang/String;"
-")"
-"Ljava/lang/String;", reinterpret_cast<void*>(GetDomainAndRegistry) },
- { "nativeCreateHistoricalTabFromState",
-"("
-"[B"
-"I"
-")"
-"V", reinterpret_cast<void*>(CreateHistoricalTabFromState) },
- { "nativeGetStateAsByteArray",
-"("
-"Landroid/view/View;"
-")"
-"[B", reinterpret_cast<void*>(GetStateAsByteArray) },
- { "nativeGetAutofillProfileGUIDs",
-"("
-")"
-"[Ljava/lang/String;", reinterpret_cast<void*>(GetAutofillProfileGUIDs) },
- { "nativeSetRecognitionResults",
-"("
-"I"
-"[Ljava/lang/String;"
-")"
-"V", reinterpret_cast<void*>(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<void*>(AddBookmarkFromAPI) },
- { "nativeFindAll",
-"("
-"Ljava/lang/String;"
-")"
-"I", reinterpret_cast<void*>(FindAll) },
- { "nativeGetInnerClass",
-"("
-")"
-"Lorg/chromium/example/jni_generator/SampleForTests$OnFrameAvailableListener;",
- reinterpret_cast<void*>(GetInnerClass) },
- { "nativeQueryBitmap",
-"("
-"I"
-"[Ljava/lang/String;"
-"Ljava/lang/String;"
-"[Ljava/lang/String;"
-"Ljava/lang/String;"
-")"
-"Landroid/graphics/Bitmap;", reinterpret_cast<void*>(QueryBitmap) },
- { "nativeGotOrientation",
-"("
-"I"
-"D"
-"D"
-"D"
-")"
-"V", reinterpret_cast<void*>(GotOrientation) },
-};
-
-static bool RegisterNativesImpl(JNIEnv* env) {
-
- g_TestJni_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
- base::android::GetClass(env, kTestJniClassPath).obj()));
-
- const int kMethodsTestJniSize = arraysize(kMethodsTestJni);
-
- if (env->RegisterNatives(TestJni_clazz(env),
- kMethodsTestJni,
- kMethodsTestJniSize) < 0) {
- jni_generator::HandleRegistrationError(
- env, TestJni_clazz(env), __FILE__);
- return false;
- }
-
- return true;
-}
-
-#endif // org_chromium_TestJni_JNI
diff --git a/base/android/jni_generator/testNativesLong.golden b/base/android/jni_generator/testNativesLong.golden
deleted file mode 100644
index 5fa901c86e..0000000000
--- a/base/android/jni_generator/testNativesLong.golden
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2014 The Chromium 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.py
-// For
-// org/chromium/TestJni
-
-#ifndef org_chromium_TestJni_JNI
-#define org_chromium_TestJni_JNI
-
-#include <jni.h>
-
-#include "base/android/jni_generator/jni_generator_helper.h"
-
-#include "base/android/jni_int_wrapper.h"
-
-// 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;
-#define TestJni_clazz(env) g_TestJni_clazz
-
-} // namespace
-
-// Step 2: method stubs.
-static void Destroy(JNIEnv* env, jobject jcaller,
- jlong nativeChromeBrowserProvider) {
- ChromeBrowserProvider* native =
- reinterpret_cast<ChromeBrowserProvider*>(nativeChromeBrowserProvider);
- CHECK_NATIVE_PTR(env, jcaller, native, "Destroy");
- return native->Destroy(env, jcaller);
-}
-
-// Step 3: RegisterNatives.
-
-static const JNINativeMethod kMethodsTestJni[] = {
- { "nativeDestroy",
-"("
-"J"
-")"
-"V", reinterpret_cast<void*>(Destroy) },
-};
-
-static bool RegisterNativesImpl(JNIEnv* env) {
-
- g_TestJni_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
- base::android::GetClass(env, kTestJniClassPath).obj()));
-
- const int kMethodsTestJniSize = arraysize(kMethodsTestJni);
-
- if (env->RegisterNatives(TestJni_clazz(env),
- kMethodsTestJni,
- kMethodsTestJniSize) < 0) {
- jni_generator::HandleRegistrationError(
- env, TestJni_clazz(env), __FILE__);
- return false;
- }
-
- return true;
-}
-
-#endif // org_chromium_TestJni_JNI
diff --git a/base/android/jni_generator/testPureNativeMethodsOption.golden b/base/android/jni_generator/testPureNativeMethodsOption.golden
deleted file mode 100644
index ad63cca626..0000000000
--- a/base/android/jni_generator/testPureNativeMethodsOption.golden
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 2014 The Chromium 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.py
-// For
-// org/chromium/example/jni_generator/Test
-
-#ifndef org_chromium_example_jni_generator_Test_JNI
-#define org_chromium_example_jni_generator_Test_JNI
-
-#include <jni.h>
-
-#include "base/android/jni_generator/jni_generator_helper.h"
-
-#include "base/android/jni_int_wrapper.h"
-
-// Step 1: forward declarations.
-namespace {
-const char kTestClassPath[] = "org/chromium/example/jni_generator/Test";
-// Leaking this jclass as we cannot use LazyInstance from some threads.
-jclass g_Test_clazz = NULL;
-#define Test_clazz(env) g_Test_clazz
-
-} // namespace
-
-// Step 2: method stubs.
-static jlong Method(JNIEnv* env, jobject jcaller,
- jlong nativeTest,
- jint arg1) {
- Test* native = reinterpret_cast<Test*>(nativeTest);
- CHECK_NATIVE_PTR(env, jcaller, native, "Method", 0);
- return native->Method(arg1);
-}
-
-// Step 3: RegisterNatives.
-
-static const JNINativeMethod kMethodsTest[] = {
- { "nativeMethod",
-"("
-"J"
-"I"
-")"
-"J", reinterpret_cast<void*>(Method) },
-};
-
-static bool RegisterNativesImpl(JNIEnv* env) {
-
- g_Test_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
- base::android::GetClass(env, kTestClassPath).obj()));
-
- const int kMethodsTestSize = arraysize(kMethodsTest);
-
- if (env->RegisterNatives(Test_clazz(env),
- kMethodsTest,
- kMethodsTestSize) < 0) {
- jni_generator::HandleRegistrationError(
- env, Test_clazz(env), __FILE__);
- return false;
- }
-
- return true;
-}
-
-#endif // org_chromium_example_jni_generator_Test_JNI
diff --git a/base/android/jni_generator/testSingleJNIAdditionalImport.golden b/base/android/jni_generator/testSingleJNIAdditionalImport.golden
deleted file mode 100644
index 1cf6554205..0000000000
--- a/base/android/jni_generator/testSingleJNIAdditionalImport.golden
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright 2014 The Chromium 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.py
-// For
-// org/chromium/foo/Foo
-
-#ifndef org_chromium_foo_Foo_JNI
-#define org_chromium_foo_Foo_JNI
-
-#include <jni.h>
-
-#include "base/android/jni_generator/jni_generator_helper.h"
-
-#include "base/android/jni_int_wrapper.h"
-
-// Step 1: forward declarations.
-namespace {
-const char kFooClassPath[] = "org/chromium/foo/Foo";
-// Leaking this jclass as we cannot use LazyInstance from some threads.
-jclass g_Foo_clazz = NULL;
-#define Foo_clazz(env) g_Foo_clazz
-
-} // namespace
-
-static void DoSomething(JNIEnv* env, jclass jcaller,
- jobject callback);
-
-// Step 2: method stubs.
-
-static base::subtle::AtomicWord g_Foo_calledByNative = 0;
-static void Java_Foo_calledByNative(JNIEnv* env, jobject callback) {
- /* Must call RegisterNativesImpl() */
- CHECK_CLAZZ(env, Foo_clazz(env),
- Foo_clazz(env));
- jmethodID method_id =
- base::android::MethodID::LazyGet<
- base::android::MethodID::TYPE_STATIC>(
- env, Foo_clazz(env),
- "calledByNative",
-
-"("
-"Lorg/chromium/foo/Bar$Callback;"
-")"
-"V",
- &g_Foo_calledByNative);
-
- env->CallStaticVoidMethod(Foo_clazz(env),
- method_id, callback);
- jni_generator::CheckException(env);
-
-}
-
-// Step 3: RegisterNatives.
-
-static const JNINativeMethod kMethodsFoo[] = {
- { "nativeDoSomething",
-"("
-"Lorg/chromium/foo/Bar$Callback;"
-")"
-"V", reinterpret_cast<void*>(DoSomething) },
-};
-
-static bool RegisterNativesImpl(JNIEnv* env) {
-
- g_Foo_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
- base::android::GetClass(env, kFooClassPath).obj()));
-
- const int kMethodsFooSize = arraysize(kMethodsFoo);
-
- if (env->RegisterNatives(Foo_clazz(env),
- kMethodsFoo,
- kMethodsFooSize) < 0) {
- jni_generator::HandleRegistrationError(
- env, Foo_clazz(env), __FILE__);
- return false;
- }
-
- return true;
-}
-
-#endif // org_chromium_foo_Foo_JNI
diff --git a/base/android/jni_int_wrapper.h b/base/android/jni_int_wrapper.h
deleted file mode 100644
index fa0f3d5d54..0000000000
--- a/base/android/jni_int_wrapper.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2014 The Chromium Authors. All 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_INT_WRAPPER_H_
-#define BASE_ANDROID_JNI_INT_WRAPPER_H_
-
-// Wrapper used to receive int when calling Java from native.
-// The wrapper disallows automatic conversion of long to int.
-// This is to avoid a common anti-pattern where a Java int is used
-// to receive a native pointer. Please use a Java long to receive
-// native pointers, so that the code works on both 32-bit and 64-bit
-// platforms. Note the wrapper allows other lossy conversions into
-// jint that could be consider anti-patterns, such as from size_t.
-
-// Checking is only done in debugging builds.
-
-#ifdef NDEBUG
-
-typedef jint JniIntWrapper;
-
-// This inline is sufficiently trivial that it does not change the
-// final code generated by g++.
-inline jint as_jint(JniIntWrapper wrapper) {
- return wrapper;
-}
-
-#else
-
-class JniIntWrapper {
- public:
- JniIntWrapper() : i_(0) {}
- JniIntWrapper(int i) : i_(i) {}
- JniIntWrapper(const JniIntWrapper& ji) : i_(ji.i_) {}
- template <class T> JniIntWrapper(const T& t) : i_(t) {}
- jint as_jint() const { return i_; }
- private:
- // If you get an "is private" error at the line below it is because you used
- // an implicit conversion to convert a long to an int when calling Java.
- // We disallow this, as a common anti-pattern allows converting a native
- // pointer (intptr_t) to a Java int. Please use a Java long to represent
- // a native pointer. If you want a lossy conversion, please use an
- // explicit conversion in your C++ code. Note an error is only seen when
- // compiling on a 64-bit platform, as intptr_t is indistinguishable from
- // int on 32-bit platforms.
- JniIntWrapper(long);
- jint i_;
-};
-
-inline jint as_jint(const JniIntWrapper& wrapper) {
- return wrapper.as_jint();
-}
-
-#endif // NDEBUG
-
-#endif // BASE_ANDROID_JNI_INT_WRAPPER_H_
diff --git a/base/android/junit/src/org/chromium/base/BaseChromiumApplicationTest.java b/base/android/junit/src/org/chromium/base/BaseChromiumApplicationTest.java
deleted file mode 100644
index d3441f7895..0000000000
--- a/base/android/junit/src/org/chromium/base/BaseChromiumApplicationTest.java
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright 2015 The Chromium 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 static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-import android.app.Activity;
-import android.view.KeyEvent;
-
-import junit.framework.Assert;
-
-import org.chromium.base.BaseChromiumApplication.WindowFocusChangedListener;
-import org.chromium.testing.local.LocalRobolectricTestRunner;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.Robolectric;
-import org.robolectric.annotation.Config;
-import org.robolectric.annotation.Implementation;
-import org.robolectric.annotation.Implements;
-import org.robolectric.shadows.ShadowActivity;
-import org.robolectric.util.ActivityController;
-
-/** Unit tests for {@link BaseChromiumApplication}. */
-@RunWith(LocalRobolectricTestRunner.class)
-@Config(manifest = Config.NONE, application = BaseChromiumApplication.class,
- shadows = {BaseChromiumApplicationTest.TrackingShadowActivity.class})
-public class BaseChromiumApplicationTest {
-
- @Implements(Activity.class)
- public static class TrackingShadowActivity extends ShadowActivity {
- private int mWindowFocusCalls;
- private int mDispatchKeyEventCalls;
- private boolean mReturnValueForKeyDispatch;
-
- @Implementation
- public void onWindowFocusChanged(@SuppressWarnings("unused") boolean hasFocus) {
- mWindowFocusCalls++;
- }
-
- @Implementation
- public boolean dispatchKeyEvent(@SuppressWarnings("unused") KeyEvent event) {
- mDispatchKeyEventCalls++;
- return mReturnValueForKeyDispatch;
- }
- }
-
- @Test
- public void testWindowsFocusChanged() throws Exception {
- BaseChromiumApplication app = (BaseChromiumApplication) Robolectric.application;
-
- WindowFocusChangedListener mock = mock(WindowFocusChangedListener.class);
- app.registerWindowFocusChangedListener(mock);
-
- ActivityController<Activity> controller =
- Robolectric.buildActivity(Activity.class).create().start().visible();
- TrackingShadowActivity shadow =
- (TrackingShadowActivity) Robolectric.shadowOf(controller.get());
-
- controller.get().getWindow().getCallback().onWindowFocusChanged(true);
- // Assert that listeners were notified.
- verify(mock).onWindowFocusChanged(controller.get(), true);
- // Also ensure that the original activity is forwarded the notification.
- Assert.assertEquals(1, shadow.mWindowFocusCalls);
- }
-
- @Test
- public void testDispatchKeyEvent() throws Exception {
- ActivityController<Activity> controller =
- Robolectric.buildActivity(Activity.class).create().start().visible();
- TrackingShadowActivity shadow =
- (TrackingShadowActivity) Robolectric.shadowOf(controller.get());
-
- final KeyEvent menuKey = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU);
-
- // Ensure that key events are forwarded.
- Assert.assertFalse(controller.get().getWindow().getCallback().dispatchKeyEvent(menuKey));
- // This gets called twice - once to see if the activity is swallowing it, and again to
- // dispatch it.
- Assert.assertEquals(2, shadow.mDispatchKeyEventCalls);
-
- // Ensure that our activity can swallow the event.
- shadow.mReturnValueForKeyDispatch = true;
- Assert.assertTrue(controller.get().getWindow().getCallback().dispatchKeyEvent(menuKey));
- Assert.assertEquals(3, shadow.mDispatchKeyEventCalls);
-
- // A non-enter key only dispatches once.
- Assert.assertTrue(controller.get().getWindow().getCallback().dispatchKeyEvent(
- new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_SPACE)));
- Assert.assertEquals(4, shadow.mDispatchKeyEventCalls);
- }
-}
diff --git a/base/android/junit/src/org/chromium/base/LogTest.java b/base/android/junit/src/org/chromium/base/LogTest.java
deleted file mode 100644
index ac98001e87..0000000000
--- a/base/android/junit/src/org/chromium/base/LogTest.java
+++ /dev/null
@@ -1,226 +0,0 @@
-// Copyright 2015 The Chromium 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 static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-import org.chromium.testing.local.LocalRobolectricTestRunner;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.annotation.Config;
-import org.robolectric.annotation.Implementation;
-import org.robolectric.annotation.Implements;
-import org.robolectric.shadows.ShadowLog;
-
-import java.util.List;
-
-/** Unit tests for {@link Log}. */
-@RunWith(LocalRobolectricTestRunner.class)
-@Config(manifest = Config.NONE, shadows = {LogTest.PermissiveShadowLog.class})
-public class LogTest {
- /** Test method for {@link Log#makeTag(String)} */
- @Test
- public void testMakeTag() {
- assertEquals("cr.Foo", Log.makeTag("Foo"));
- assertEquals("cr", Log.makeTag(null));
- assertEquals("cr", Log.makeTag(""));
- }
-
- /** Test method for {@link Log#makeTag(String)} */
- @Test(expected = IllegalArgumentException.class)
- public void testMakeTagFailure() {
- Log.makeTag("ThisIs21Char.....Long");
- }
-
- /** Tests that the computed call origin is the correct one. */
- @Test
- public void callOriginTest() {
- Log.d("Foo", "Bar");
-
- List<ShadowLog.LogItem> logs = ShadowLog.getLogs();
- assertEquals("Only one log should be written", 1, logs.size());
-
- assertTrue("The origin of the log message (" + logs.get(0).msg + ") looks wrong.",
- logs.get(0).msg.matches("\\[LogTest.java:\\d+\\].*"));
- }
-
- /** Tests that exceptions provided to the log functions are properly recognized and printed. */
- @Test
- public void exceptionLoggingTest() {
- Throwable t = new Throwable() {
- @Override
- public String toString() {
- return "MyThrowable";
- }
- };
-
- Throwable t2 = new Throwable() {
- @Override
- public String toString() {
- return "MyOtherThrowable";
- }
- };
-
- List<ShadowLog.LogItem> logs = ShadowLog.getLogs();
-
- // The throwable gets printed out
- Log.i("Foo", "Bar", t);
- assertEquals(t, logs.get(logs.size() - 1).throwable);
- assertEquals("Bar", logs.get(logs.size() - 1).msg);
-
- // The throwable can be both added to the message itself and printed out
- Log.i("Foo", "Bar %s", t);
- assertEquals(t, logs.get(logs.size() - 1).throwable);
- assertEquals("Bar MyThrowable", logs.get(logs.size() - 1).msg);
-
- // Non throwable are properly identified
- Log.i("Foo", "Bar %s", t, "Baz");
- assertNull(logs.get(logs.size() - 1).throwable);
- assertEquals("Bar MyThrowable", logs.get(logs.size() - 1).msg);
-
- // The last throwable is the one used that is going to be printed out
- Log.i("Foo", "Bar %s %s", t, t2);
- assertEquals(t2, logs.get(logs.size() - 1).throwable);
- assertEquals("Bar MyThrowable MyOtherThrowable", logs.get(logs.size() - 1).msg);
- }
-
- public void verboseLoggingTest() {
- PermissiveShadowLog.setLevel(Log.VERBOSE);
- List<ShadowLog.LogItem> logs = ShadowLog.getLogs();
-
- Log.wtf("Foo", "Bar");
- Log.e("Foo", "Bar");
- Log.w("Foo", "Bar");
- Log.i("Foo", "Bar");
- Log.d("Foo", "Bar");
- Log.v("Foo", "Bar");
-
- assertEquals(Log.ASSERT, logs.get(0).type);
- assertEquals(Log.ERROR, logs.get(1).type);
- assertEquals(Log.WARN, logs.get(2).type);
- assertEquals(Log.INFO, logs.get(3).type);
- assertEquals(Log.DEBUG, logs.get(4).type);
- assertEquals(Log.VERBOSE, logs.get(5).type);
- assertEquals(6, logs.size());
- }
-
- @Test
- public void debugLoggingTest() {
- PermissiveShadowLog.setLevel(Log.DEBUG);
- List<ShadowLog.LogItem> logs = ShadowLog.getLogs();
-
- Log.wtf("Foo", "Bar");
- Log.e("Foo", "Bar");
- Log.w("Foo", "Bar");
- Log.i("Foo", "Bar");
- Log.d("Foo", "Bar");
- Log.v("Foo", "Bar");
-
- assertEquals(Log.ASSERT, logs.get(0).type);
- assertEquals(Log.ERROR, logs.get(1).type);
- assertEquals(Log.WARN, logs.get(2).type);
- assertEquals(Log.INFO, logs.get(3).type);
- assertEquals(Log.DEBUG, logs.get(4).type);
- assertEquals(5, logs.size());
- }
-
- @Test
- public void infoLoggingTest() {
- PermissiveShadowLog.setLevel(Log.INFO);
- List<ShadowLog.LogItem> logs = ShadowLog.getLogs();
-
- Log.wtf("Foo", "Bar");
- Log.e("Foo", "Bar");
- Log.w("Foo", "Bar");
- Log.i("Foo", "Bar");
- Log.d("Foo", "Bar");
- Log.v("Foo", "Bar");
-
- assertEquals(Log.ASSERT, logs.get(0).type);
- assertEquals(Log.ERROR, logs.get(1).type);
- assertEquals(Log.WARN, logs.get(2).type);
- assertEquals(Log.INFO, logs.get(3).type);
- assertEquals(4, logs.size());
- }
-
- @Test
- public void warnLoggingTest() {
- PermissiveShadowLog.setLevel(Log.WARN);
- List<ShadowLog.LogItem> logs = ShadowLog.getLogs();
-
- Log.wtf("Foo", "Bar");
- Log.e("Foo", "Bar");
- Log.w("Foo", "Bar");
- Log.i("Foo", "Bar");
- Log.d("Foo", "Bar");
- Log.v("Foo", "Bar");
-
- assertEquals(Log.ASSERT, logs.get(0).type);
- assertEquals(Log.ERROR, logs.get(1).type);
- assertEquals(Log.WARN, logs.get(2).type);
- assertEquals(3, logs.size());
- }
-
- @Test
- public void errorLoggingTest() {
- PermissiveShadowLog.setLevel(Log.ERROR);
- List<ShadowLog.LogItem> logs = ShadowLog.getLogs();
-
- Log.wtf("Foo", "Bar");
- Log.e("Foo", "Bar");
- Log.w("Foo", "Bar");
- Log.i("Foo", "Bar");
- Log.d("Foo", "Bar");
- Log.v("Foo", "Bar");
-
- assertEquals(Log.ASSERT, logs.get(0).type);
- assertEquals(Log.ERROR, logs.get(1).type);
- assertEquals(2, logs.size());
- }
-
- @Test
- public void assertLoggingTest() {
- PermissiveShadowLog.setLevel(Log.ASSERT);
- List<ShadowLog.LogItem> logs = ShadowLog.getLogs();
-
- Log.wtf("Foo", "Bar");
- Log.e("Foo", "Bar");
- Log.w("Foo", "Bar");
- Log.i("Foo", "Bar");
- Log.d("Foo", "Bar");
- Log.v("Foo", "Bar");
-
- assertEquals(Log.ASSERT, logs.get(0).type);
- assertEquals(1, logs.size());
- }
-
- @Before
- public void beforeTest() {
- PermissiveShadowLog.reset();
- }
-
- /** Needed to allow debug/verbose logging that is disabled by default. */
- @Implements(android.util.Log.class)
- public static class PermissiveShadowLog extends ShadowLog {
- private static int sLevel = Log.VERBOSE;
-
- /** Sets the log level for all tags. */
- public static void setLevel(int level) {
- sLevel = level;
- }
-
- @Implementation
- public static boolean isLoggable(String tag, int level) {
- return level >= sLevel;
- }
-
- public static void reset() {
- sLevel = Log.VERBOSE;
- }
- }
-}
diff --git a/base/android/library_loader/library_load_from_apk_status_codes.h b/base/android/library_loader/library_load_from_apk_status_codes.h
deleted file mode 100644
index 8910d4800d..0000000000
--- a/base/android/library_loader/library_load_from_apk_status_codes.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2014 The Chromium Authors. All 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_LIBRARY_LOADER_LIBRARY_LOAD_FROM_APK_STATUS_CODES_H_
-#define BASE_ANDROID_LIBRARY_LOADER_LIBRARY_LOAD_FROM_APK_STATUS_CODES_H_
-
-namespace base {
-namespace android {
-
-namespace {
-
-// This enum must be kept in sync with the LibraryLoadFromApkStatus enum in
-// tools/metrics/histograms/histograms.xml.
-// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.base.library_loader
-enum LibraryLoadFromApkStatusCodes {
- // The loader was unable to determine whether the functionality is supported.
- LIBRARY_LOAD_FROM_APK_STATUS_CODES_UNKNOWN = 0,
-
- // The device does not support loading a library directly from the APK file
- // (obsolete).
- LIBRARY_LOAD_FROM_APK_STATUS_CODES_NOT_SUPPORTED_OBSOLETE = 1,
-
- // The device supports loading a library directly from the APK file.
- // (obsolete).
- LIBRARY_LOAD_FROM_APK_STATUS_CODES_SUPPORTED_OBSOLETE = 2,
-
- // The Chromium library was successfully loaded directly from the APK file.
- LIBRARY_LOAD_FROM_APK_STATUS_CODES_SUCCESSFUL = 3,
-
- // The Chromium library was successfully loaded using the unpack library
- // fallback because it was compressed or not page aligned in the APK file.
- LIBRARY_LOAD_FROM_APK_STATUS_CODES_USED_UNPACK_LIBRARY_FALLBACK = 4,
-
- // The Chromium library was successfully loaded using the no map executable
- // support fallback (obsolete).
- LIBRARY_LOAD_FROM_APK_STATUS_CODES_USED_NO_MAP_EXEC_SUPPORT_FALLBACK_OBSOLETE
- = 5,
-
- // End sentinel.
- LIBRARY_LOAD_FROM_APK_STATUS_CODES_MAX = 6,
-};
-
-} // namespace
-
-} // namespace android
-} // namespace base
-
-#endif // BASE_ANDROID_LIBRARY_LOADER_LIBRARY_LOAD_FROM_APK_STATUS_CODES_H_
diff --git a/base/android/linker/BUILD.gn b/base/android/linker/BUILD.gn
deleted file mode 100644
index 190ea4776d..0000000000
--- a/base/android/linker/BUILD.gn
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright 2014 The Chromium 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("//build/config/android/config.gni")
-
-assert(is_android)
-
-# GYP: //base/base.gyp:chromium_android_linker
-shared_library("chromium_android_linker") {
- sources = [
- "linker_jni.cc",
- ]
-
- # The NDK contains the crazy_linker here:
- # '<(android_ndk_root)/crazy_linker.gyp:crazy_linker'
- # However, we use our own fork. See bug 384700.
- deps = [
- "//third_party/android_crazy_linker",
- ]
-
- # TODO(GYP):
- # The crazy linker is never instrumented.
- #'cflags!': [
- #'-finstrument-functions',
- #],
-}
diff --git a/base/android/linker/DEPS b/base/android/linker/DEPS
deleted file mode 100644
index 15c3afb866..0000000000
--- a/base/android/linker/DEPS
+++ /dev/null
@@ -1,4 +0,0 @@
-include_rules = [
- # This code cannot depend on anything from base/
- "-base",
-]
diff --git a/base/android/linker/config.gni b/base/android/linker/config.gni
deleted file mode 100644
index 99cbcf0e25..0000000000
--- a/base/android/linker/config.gni
+++ /dev/null
@@ -1,8 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# TODO(GYP) add "|| profiling_full_stack_frames
-# Only enable the chromium linker on regular builds, since the
-# component build crashes on Android 4.4. See b/11379966
-chromium_linker_supported = !is_component_build
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/async_socket_io_handler.h b/base/async_socket_io_handler.h
deleted file mode 100644
index a22c29d907..0000000000
--- a/base/async_socket_io_handler.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_ASYNC_SOCKET_IO_HANDLER_H_
-#define BASE_ASYNC_SOCKET_IO_HANDLER_H_
-
-#include "base/message_loop/message_loop.h"
-#include "base/sync_socket.h"
-#include "base/threading/non_thread_safe.h"
-
-namespace base {
-
-// Extends the CancelableSyncSocket class to allow reading from a socket
-// asynchronously on a TYPE_IO message loop thread. This makes it easy to share
-// a thread that uses a message loop (e.g. for IPC and other things) and not
-// require a separate thread to read from the socket.
-//
-// Example usage (also see the unit tests):
-//
-// class SocketReader {
-// public:
-// SocketReader(base::CancelableSyncSocket* socket)
-// : socket_(socket), buffer_() {
-// io_handler.Initialize(socket_->handle(),
-// base::Bind(&SocketReader::OnDataAvailable,
-// base::Unretained(this));
-// }
-//
-// void AsyncRead() {
-// CHECK(io_handler.Read(&buffer_[0], sizeof(buffer_)));
-// }
-//
-// private:
-// void OnDataAvailable(int bytes_read) {
-// if (ProcessData(&buffer_[0], bytes_read)) {
-// // Issue another read.
-// CHECK(io_handler.Read(&buffer_[0], sizeof(buffer_)));
-// }
-// }
-//
-// base::AsyncSocketIoHandler io_handler;
-// base::CancelableSyncSocket* socket_;
-// char buffer_[kBufferSize];
-// };
-//
-class BASE_EXPORT AsyncSocketIoHandler
- : public NON_EXPORTED_BASE(base::NonThreadSafe),
-// The message loop callback interface is different based on platforms.
-#if defined(OS_WIN)
- public NON_EXPORTED_BASE(base::MessageLoopForIO::IOHandler) {
-#else
- public NON_EXPORTED_BASE(base::MessageLoopForIO::Watcher) {
-#endif
- public:
- AsyncSocketIoHandler();
- ~AsyncSocketIoHandler() override;
-
- // Type definition for the callback. The parameter tells how many
- // bytes were read and is 0 if an error occurred.
- typedef base::Callback<void(int)> ReadCompleteCallback;
-
- // Initializes the AsyncSocketIoHandler by hooking it up to the current
- // thread's message loop (must be TYPE_IO), to do async reads from the socket
- // on the current thread. The |callback| will be invoked whenever a Read()
- // has completed.
- bool Initialize(base::SyncSocket::Handle socket,
- const ReadCompleteCallback& callback);
-
- // Attempts to read from the socket. The return value will be |false|
- // if an error occurred and |true| if data was read or a pending read
- // was issued. Regardless of async or sync operation, the
- // ReadCompleteCallback (see above) will be called when data is available.
- bool Read(char* buffer, int buffer_len);
-
- private:
-#if defined(OS_WIN)
- // Implementation of IOHandler on Windows.
- void OnIOCompleted(base::MessageLoopForIO::IOContext* context,
- DWORD bytes_transfered,
- DWORD error) override;
-#elif defined(OS_POSIX)
- // Implementation of base::MessageLoopForIO::Watcher.
- void OnFileCanWriteWithoutBlocking(int socket) override {}
- void OnFileCanReadWithoutBlocking(int socket) override;
-
- void EnsureWatchingSocket();
-#endif
-
- base::SyncSocket::Handle socket_;
-#if defined(OS_WIN)
- base::MessageLoopForIO::IOContext* context_;
- bool is_pending_;
-#elif defined(OS_POSIX)
- base::MessageLoopForIO::FileDescriptorWatcher socket_watcher_;
- // |pending_buffer_| and |pending_buffer_len_| are valid only between
- // Read() and OnFileCanReadWithoutBlocking().
- char* pending_buffer_;
- int pending_buffer_len_;
- // |true| iff the message loop is watching the socket for IO events.
- bool is_watching_;
-#endif
- ReadCompleteCallback read_complete_;
-
- DISALLOW_COPY_AND_ASSIGN(AsyncSocketIoHandler);
-};
-
-} // namespace base.
-
-#endif // BASE_ASYNC_SOCKET_IO_HANDLER_H_
diff --git a/base/at_exit.h b/base/at_exit.h
index 6fe7361a85..04e3f76422 100644
--- a/base/at_exit.h
+++ b/base/at_exit.h
@@ -8,8 +8,8 @@
#include <stack>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/callback.h"
+#include "base/macros.h"
#include "base/synchronization/lock.h"
namespace base {
diff --git a/base/atomic_sequence_num.h b/base/atomic_sequence_num.h
index 7bf2778991..59b0d2551a 100644
--- a/base/atomic_sequence_num.h
+++ b/base/atomic_sequence_num.h
@@ -6,7 +6,7 @@
#define BASE_ATOMIC_SEQUENCE_NUM_H_
#include "base/atomicops.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
namespace base {
diff --git a/base/atomicops.h b/base/atomicops.h
index 6a5371c75c..3428fe87ab 100644
--- a/base/atomicops.h
+++ b/base/atomicops.h
@@ -144,65 +144,13 @@ Atomic64 Release_Load(volatile const Atomic64* ptr);
} // namespace subtle
} // namespace base
-// The following x86 CPU features are used in atomicops_internals_x86_gcc.h, but
-// this file is duplicated inside of Chrome: protobuf and tcmalloc rely on the
-// struct being present at link time. Some parts of Chrome can currently use the
-// portable interface whereas others still use GCC one. The include guards are
-// the same as in atomicops_internals_x86_gcc.cc.
-#if defined(__i386__) || defined(__x86_64__)
-// 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.
- // The following fields are unused by Chrome's base implementation but are
- // still used by copies of the same code in other parts of the code base. This
- // causes an ODR violation, and the other code is likely reading invalid
- // memory.
- // TODO(jfb) Delete these fields once the rest of the Chrome code base doesn't
- // depend on them.
- bool has_sse2; // Processor has SSE2.
- bool has_cmpxchg16b; // Processor supports cmpxchg16b instruction.
-};
-BASE_EXPORT extern struct AtomicOps_x86CPUFeatureStruct
- AtomicOps_Internalx86CPUFeatures;
-#endif
-
-// Try to use a portable implementation based on C++11 atomics.
-//
-// Some toolchains support C++11 language features without supporting library
-// features (recent compiler, older STL). Whitelist libstdc++ and libc++ that we
-// know will have <atomic> when compiling C++11.
-#if ((__cplusplus >= 201103L) && \
- ((defined(__GLIBCXX__) && (__GLIBCXX__ > 20110216)) || \
- (defined(_LIBCPP_VERSION) && (_LIBCPP_STD_VER >= 11))))
+#if defined(OS_WIN)
+// TODO(jfb): The MSVC header includes windows.h, which other files end up
+// relying on. Fix this as part of crbug.com/559247.
+# include "base/atomicops_internals_x86_msvc.h"
+#else
# include "base/atomicops_internals_portable.h"
-#else // Otherwise use a platform specific implementation.
-# if defined(THREAD_SANITIZER)
-# error "Thread sanitizer must use the portable atomic operations"
-# 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_ARMEL)
-# include "base/atomicops_internals_arm_gcc.h"
-# elif defined(COMPILER_GCC) && defined(ARCH_CPU_ARM64)
-# include "base/atomicops_internals_arm64_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) || defined(ARCH_CPU_MIPS64_FAMILY)))
-# include "base/atomicops_internals_mips_gcc.h"
-# else
-# error "Atomic operations are not supported on your platform"
-# endif
-#endif // Portable / non-portable includes.
+#endif
// On some platforms we need additional declarations to make
// AtomicWord compatible with our other Atomic* types.
diff --git a/base/atomicops_internals_arm64_gcc.h b/base/atomicops_internals_arm64_gcc.h
deleted file mode 100644
index ddcfec901f..0000000000
--- a/base/atomicops_internals_arm64_gcc.h
+++ /dev/null
@@ -1,307 +0,0 @@
-// Copyright 2014 The Chromium 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.
-
-// TODO(rmcilroy): Investigate whether we can use __sync__ intrinsics instead of
-// the hand coded assembly without introducing perf regressions.
-// TODO(rmcilroy): Investigate whether we can use acquire / release versions of
-// exclusive load / store assembly instructions and do away with
-// the barriers.
-
-#ifndef BASE_ATOMICOPS_INTERNALS_ARM64_GCC_H_
-#define BASE_ATOMICOPS_INTERNALS_ARM64_GCC_H_
-
-#if defined(OS_QNX)
-#include <sys/cpuinline.h>
-#endif
-
-namespace base {
-namespace subtle {
-
-inline void MemoryBarrier() {
- __asm__ __volatile__ ("dmb ish" ::: "memory"); // NOLINT
-}
-
-// NoBarrier versions of the operation include "memory" in the clobber list.
-// This is not required for direct usage of the NoBarrier versions of the
-// operations. However this is required for correctness when they are used as
-// part of the Acquire or Release versions, to ensure that nothing from outside
-// the call is reordered between the operation and the memory barrier. This does
-// not change the code generated, so has no or minimal impact on the
-// NoBarrier operations.
-
-inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
- Atomic32 old_value,
- Atomic32 new_value) {
- Atomic32 prev;
- int32_t temp;
-
- __asm__ __volatile__ ( // NOLINT
- "0: \n\t"
- "ldxr %w[prev], %[ptr] \n\t" // Load the previous value.
- "cmp %w[prev], %w[old_value] \n\t"
- "bne 1f \n\t"
- "stxr %w[temp], %w[new_value], %[ptr] \n\t" // Try to store the new value.
- "cbnz %w[temp], 0b \n\t" // Retry if it did not work.
- "1: \n\t"
- : [prev]"=&r" (prev),
- [temp]"=&r" (temp),
- [ptr]"+Q" (*ptr)
- : [old_value]"IJr" (old_value),
- [new_value]"r" (new_value)
- : "cc", "memory"
- ); // NOLINT
-
- return prev;
-}
-
-inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
- Atomic32 new_value) {
- Atomic32 result;
- int32_t temp;
-
- __asm__ __volatile__ ( // NOLINT
- "0: \n\t"
- "ldxr %w[result], %[ptr] \n\t" // Load the previous value.
- "stxr %w[temp], %w[new_value], %[ptr] \n\t" // Try to store the new value.
- "cbnz %w[temp], 0b \n\t" // Retry if it did not work.
- : [result]"=&r" (result),
- [temp]"=&r" (temp),
- [ptr]"+Q" (*ptr)
- : [new_value]"r" (new_value)
- : "memory"
- ); // NOLINT
-
- return result;
-}
-
-inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
- Atomic32 increment) {
- Atomic32 result;
- int32_t temp;
-
- __asm__ __volatile__ ( // NOLINT
- "0: \n\t"
- "ldxr %w[result], %[ptr] \n\t" // Load the previous value.
- "add %w[result], %w[result], %w[increment]\n\t"
- "stxr %w[temp], %w[result], %[ptr] \n\t" // Try to store the result.
- "cbnz %w[temp], 0b \n\t" // Retry on failure.
- : [result]"=&r" (result),
- [temp]"=&r" (temp),
- [ptr]"+Q" (*ptr)
- : [increment]"IJr" (increment)
- : "memory"
- ); // NOLINT
-
- return result;
-}
-
-inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
- Atomic32 increment) {
- MemoryBarrier();
- Atomic32 result = NoBarrier_AtomicIncrement(ptr, increment);
- MemoryBarrier();
-
- return result;
-}
-
-inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
- Atomic32 old_value,
- Atomic32 new_value) {
- Atomic32 prev = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
- MemoryBarrier();
-
- return prev;
-}
-
-inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
- Atomic32 old_value,
- Atomic32 new_value) {
- MemoryBarrier();
- Atomic32 prev = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
-
- return prev;
-}
-
-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) {
- __asm__ __volatile__ ( // NOLINT
- "stlr %w[value], %[ptr] \n\t"
- : [ptr]"=Q" (*ptr)
- : [value]"r" (value)
- : "memory"
- ); // NOLINT
-}
-
-inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
- return *ptr;
-}
-
-inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
- Atomic32 value;
-
- __asm__ __volatile__ ( // NOLINT
- "ldar %w[value], %[ptr] \n\t"
- : [value]"=r" (value)
- : [ptr]"Q" (*ptr)
- : "memory"
- ); // NOLINT
-
- return value;
-}
-
-inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
- MemoryBarrier();
- return *ptr;
-}
-
-// 64-bit versions of the operations.
-// See the 32-bit versions for comments.
-
-inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
- Atomic64 old_value,
- Atomic64 new_value) {
- Atomic64 prev;
- int32_t temp;
-
- __asm__ __volatile__ ( // NOLINT
- "0: \n\t"
- "ldxr %[prev], %[ptr] \n\t"
- "cmp %[prev], %[old_value] \n\t"
- "bne 1f \n\t"
- "stxr %w[temp], %[new_value], %[ptr] \n\t"
- "cbnz %w[temp], 0b \n\t"
- "1: \n\t"
- : [prev]"=&r" (prev),
- [temp]"=&r" (temp),
- [ptr]"+Q" (*ptr)
- : [old_value]"IJr" (old_value),
- [new_value]"r" (new_value)
- : "cc", "memory"
- ); // NOLINT
-
- return prev;
-}
-
-inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
- Atomic64 new_value) {
- Atomic64 result;
- int32_t temp;
-
- __asm__ __volatile__ ( // NOLINT
- "0: \n\t"
- "ldxr %[result], %[ptr] \n\t"
- "stxr %w[temp], %[new_value], %[ptr] \n\t"
- "cbnz %w[temp], 0b \n\t"
- : [result]"=&r" (result),
- [temp]"=&r" (temp),
- [ptr]"+Q" (*ptr)
- : [new_value]"r" (new_value)
- : "memory"
- ); // NOLINT
-
- return result;
-}
-
-inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
- Atomic64 increment) {
- Atomic64 result;
- int32_t temp;
-
- __asm__ __volatile__ ( // NOLINT
- "0: \n\t"
- "ldxr %[result], %[ptr] \n\t"
- "add %[result], %[result], %[increment] \n\t"
- "stxr %w[temp], %[result], %[ptr] \n\t"
- "cbnz %w[temp], 0b \n\t"
- : [result]"=&r" (result),
- [temp]"=&r" (temp),
- [ptr]"+Q" (*ptr)
- : [increment]"IJr" (increment)
- : "memory"
- ); // NOLINT
-
- return result;
-}
-
-inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
- Atomic64 increment) {
- MemoryBarrier();
- Atomic64 result = NoBarrier_AtomicIncrement(ptr, increment);
- MemoryBarrier();
-
- return result;
-}
-
-inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
- Atomic64 old_value,
- Atomic64 new_value) {
- Atomic64 prev = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
- MemoryBarrier();
-
- return prev;
-}
-
-inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
- Atomic64 old_value,
- Atomic64 new_value) {
- MemoryBarrier();
- Atomic64 prev = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
-
- return prev;
-}
-
-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) {
- __asm__ __volatile__ ( // NOLINT
- "stlr %x[value], %[ptr] \n\t"
- : [ptr]"=Q" (*ptr)
- : [value]"r" (value)
- : "memory"
- ); // NOLINT
-}
-
-inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
- return *ptr;
-}
-
-inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
- Atomic64 value;
-
- __asm__ __volatile__ ( // NOLINT
- "ldar %x[value], %[ptr] \n\t"
- : [value]"=r" (value)
- : [ptr]"Q" (*ptr)
- : "memory"
- ); // NOLINT
-
- return value;
-}
-
-inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
- MemoryBarrier();
- return *ptr;
-}
-
-} // namespace subtle
-} // namespace base
-
-#endif // BASE_ATOMICOPS_INTERNALS_ARM64_GCC_H_
diff --git a/base/atomicops_internals_arm_gcc.h b/base/atomicops_internals_arm_gcc.h
deleted file mode 100644
index 44c91c87a2..0000000000
--- a/base/atomicops_internals_arm_gcc.h
+++ /dev/null
@@ -1,294 +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_
-
-#if defined(OS_QNX)
-#include <sys/cpuinline.h>
-#endif
-
-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() {
-#if defined(OS_LINUX) || defined(OS_ANDROID)
- // Note: This is a function call, which is also an implicit compiler barrier.
- typedef void (*KernelMemoryBarrierFunc)();
- ((KernelMemoryBarrierFunc)0xffff0fa0)();
-#elif defined(OS_QNX)
- __cpu_membarrier();
-#else
-#error MemoryBarrier() is not implemented on this platform.
-#endif
-}
-
-// 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_6ZK__) || 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 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
index 342a6e4592..8b000d2571 100644
--- a/base/atomicops_internals_atomicword_compat.h
+++ b/base/atomicops_internals_atomicword_compat.h
@@ -7,7 +7,11 @@
#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,
+#include <stdint.h>
+
+#include "build/build_config.h"
+
+// AtomicWord is a synonym for intptr_t, and Atomic32 is a synonym for int32_t,
// 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.
diff --git a/base/atomicops_internals_gcc.h b/base/atomicops_internals_gcc.h
deleted file mode 100644
index 35c95fee56..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 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 98864a77da..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 <libkern/OSAtomic.h>
-
-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<Atomic32*>(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<Atomic32*>(ptr)));
- return old_value;
-}
-
-inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
- Atomic32 increment) {
- return OSAtomicAdd32(increment, const_cast<Atomic32*>(ptr));
-}
-
-inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
- Atomic32 increment) {
- return OSAtomicAdd32Barrier(increment, const_cast<Atomic32*>(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<Atomic32*>(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<volatile int64_t*>(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<volatile int64_t*>(ptr)));
- return old_value;
-}
-
-inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
- Atomic64 increment) {
- return OSAtomicAdd64(increment, reinterpret_cast<volatile int64_t*>(ptr));
-}
-
-inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
- Atomic64 increment) {
- return OSAtomicAdd64Barrier(increment,
- reinterpret_cast<volatile int64_t*>(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<volatile int64_t*>(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 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 b4551b8351..0000000000
--- a/base/atomicops_internals_mips_gcc.h
+++ /dev/null
@@ -1,280 +0,0 @@
-// Copyright (c) 2012 The Chromium 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)
- : "r" (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, %4\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, %4\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;
-}
-
-#if defined(__LP64__)
-// 64-bit versions of the atomic ops.
-
-inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
- Atomic64 old_value,
- Atomic64 new_value) {
- Atomic64 prev, tmp;
- __asm__ __volatile__(".set push\n"
- ".set noreorder\n"
- "1:\n"
- "lld %0, %5\n" // prev = *ptr
- "bne %0, %3, 2f\n" // if (prev != old_value) goto 2
- "move %2, %4\n" // tmp = new_value
- "scd %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)
- : "r" (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 Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
- Atomic64 new_value) {
- Atomic64 temp, old;
- __asm__ __volatile__(".set push\n"
- ".set noreorder\n"
- "1:\n"
- "lld %1, %4\n" // old = *ptr
- "move %0, %3\n" // temp = new_value
- "scd %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 Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
- Atomic64 increment) {
- Atomic64 temp, temp2;
-
- __asm__ __volatile__(".set push\n"
- ".set noreorder\n"
- "1:\n"
- "lld %0, %4\n" // temp = *ptr
- "daddu %1, %0, %3\n" // temp2 = temp + increment
- "scd %1, %2\n" // *ptr = temp2 (with atomic check)
- "beqz %1, 1b\n" // start again on atomic error
- "daddu %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 Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
- Atomic64 increment) {
- MemoryBarrier();
- Atomic64 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 Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
- Atomic64 old_value,
- Atomic64 new_value) {
- Atomic64 res = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
- MemoryBarrier();
- return res;
-}
-
-inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
- Atomic64 old_value,
- Atomic64 new_value) {
- MemoryBarrier();
- return NoBarrier_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
-
-} // namespace subtle
-} // namespace base
-
-#endif // BASE_ATOMICOPS_INTERNALS_MIPS_GCC_H_
diff --git a/base/atomicops_internals_portable.h b/base/atomicops_internals_portable.h
index d28561076d..ee034dee12 100644
--- a/base/atomicops_internals_portable.h
+++ b/base/atomicops_internals_portable.h
@@ -34,6 +34,8 @@
#include <atomic>
+#include "build/build_config.h"
+
namespace base {
namespace subtle {
diff --git a/base/atomicops_internals_x86_gcc.cc b/base/atomicops_internals_x86_gcc.cc
deleted file mode 100644
index c21e96d71d..0000000000
--- a/base/atomicops_internals_x86_gcc.cc
+++ /dev/null
@@ -1,103 +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 <stdint.h>
-#include <string.h>
-
-#include "base/atomicops.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.
-//
-// The include guards are the same as in atomicops.h.
-#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, // Chrome requires SSE2, but for transition assume not and initialize
- // this properly.
- false, // cmpxchg16b isn't present on early AMD64 CPUs.
-};
-
-namespace {
-
-// Initialize the AtomicOps_Internalx86CPUFeatures struct.
-void AtomicOps_Internalx86CPUFeaturesInit() {
- uint32_t eax;
- uint32_t ebx;
- uint32_t ecx;
- uint32_t 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);
-
- // ecx bit 13 indicates whether the cmpxchg16b instruction is supported
- AtomicOps_Internalx86CPUFeatures.has_cmpxchg16b = ((ecx >> 13) & 1);
-}
-
-class AtomicOpsx86Initializer {
- public:
- AtomicOpsx86Initializer() {
- AtomicOps_Internalx86CPUFeaturesInit();
- }
-};
-
-// A global to get use initialized on startup via static initialization :/
-AtomicOpsx86Initializer g_initer;
-
-} // namespace
-
-#endif // if x86
diff --git a/base/atomicops_internals_x86_gcc.h b/base/atomicops_internals_x86_gcc.h
deleted file mode 100644
index f0d224264b..0000000000
--- a/base/atomicops_internals_x86_gcc.h
+++ /dev/null
@@ -1,228 +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_
-
-#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;
-}
-
-inline void MemoryBarrier() {
- __asm__ __volatile__("mfence" : : : "memory");
-}
-
-inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
- *ptr = value;
- MemoryBarrier();
-}
-
-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 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
index 71ddca2ba3..9f05b7e78d 100644
--- a/base/atomicops_internals_x86_msvc.h
+++ b/base/atomicops_internals_x86_msvc.h
@@ -12,6 +12,7 @@
#include <intrin.h>
#include "base/macros.h"
+#include "build/build_config.h"
#if defined(ARCH_CPU_64_BITS)
// windows.h #defines this (only on x64). This causes problems because the
@@ -109,7 +110,7 @@ inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
// 64-bit low-level operations on 64-bit platform.
-COMPILE_ASSERT(sizeof(Atomic64) == sizeof(PVOID), atomic_word_is_atomic);
+static_assert(sizeof(Atomic64) == sizeof(PVOID), "atomic word is atomic");
inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
Atomic64 old_value,
diff --git a/base/atomicops_unittest.cc b/base/atomicops_unittest.cc
index 3fd5597472..7298609270 100644
--- a/base/atomicops_unittest.cc
+++ b/base/atomicops_unittest.cc
@@ -89,6 +89,13 @@ static void TestCompareAndSwap() {
EXPECT_EQ(1, value);
EXPECT_EQ(0, prev);
+ // Verify that CAS will *not* change "value" if it doesn't match the
+ // expected number. CAS will always return the actual value of the
+ // variable from before any change.
+ AtomicType fail = base::subtle::NoBarrier_CompareAndSwap(&value, 0, 2);
+ EXPECT_EQ(1, value);
+ EXPECT_EQ(1, fail);
+
// 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 = (static_cast<uint64_t>(1) <<
diff --git a/base/auto_reset.h b/base/auto_reset.h
index a5bcfaae8a..9116537bfb 100644
--- a/base/auto_reset.h
+++ b/base/auto_reset.h
@@ -5,7 +5,7 @@
#ifndef BASE_AUTO_RESET_H_
#define BASE_AUTO_RESET_H_
-#include "base/basictypes.h"
+#include "base/macros.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
diff --git a/base/base.gyp b/base/base.gyp
index ed8e29e554..dc484f4a4a 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -21,8 +21,8 @@
'optimize': 'max',
},
'dependencies': [
+ 'base_debugging_flags#target',
'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',
@@ -90,18 +90,6 @@
],
}],
['OS == "android" and _toolset == "target"', {
- 'conditions': [
- ['target_arch == "ia32" or target_arch == "x64"', {
- 'sources/': [
- ['include', '^atomicops_internals_x86_gcc\\.cc$'],
- ],
- }],
- ['target_arch == "mipsel"', {
- 'sources/': [
- ['include', '^atomicops_internals_mips_gcc\\.cc$'],
- ],
- }],
- ],
'dependencies': [
'base_java',
'base_jni_headers',
@@ -219,7 +207,7 @@
},
}],
['OS != "win" and (OS != "ios" or _toolset == "host")', {
- 'dependencies': ['../third_party/libevent/libevent.gyp:libevent'],
+ 'dependencies': ['third_party/libevent/libevent.gyp:libevent'],
},],
['component=="shared_library"', {
'conditions': [
@@ -230,11 +218,14 @@
}],
],
}],
+ ['OS=="ios"', {
+ 'sources!': [
+ 'sync_socket.h',
+ 'sync_socket_posix.cc',
+ ]
+ }],
],
'sources': [
- 'async_socket_io_handler.h',
- 'async_socket_io_handler_posix.cc',
- 'async_socket_io_handler_win.cc',
'auto_reset.h',
'linux_util.cc',
'linux_util.h',
@@ -300,6 +291,8 @@
],
'export_dependent_settings': [
'base',
+ '../third_party/icu/icu.gyp:icuuc',
+ '../third_party/icu/icu.gyp:icui18n',
],
'includes': [
'../build/android/increase_size_for_speed.gypi',
@@ -433,6 +426,7 @@
'target_name': 'base_unittests',
'type': '<(gtest_target_type)',
'sources': [
+ 'allocator/tcmalloc_unittest.cc',
'android/application_status_listener_unittest.cc',
'android/content_uri_utils_unittest.cc',
'android/jni_android_unittest.cc',
@@ -442,11 +436,11 @@
'android/path_utils_unittest.cc',
'android/scoped_java_ref_unittest.cc',
'android/sys_utils_unittest.cc',
- 'async_socket_io_handler_unittest.cc',
'at_exit_unittest.cc',
'atomicops_unittest.cc',
'barrier_closure_unittest.cc',
'base64_unittest.cc',
+ 'base64url_unittest.cc',
'big_endian_unittest.cc',
'bind_unittest.cc',
'bind_unittest.nc',
@@ -464,7 +458,6 @@
'containers/linked_list_unittest.cc',
'containers/mru_cache_unittest.cc',
'containers/scoped_ptr_hash_map_unittest.cc',
- 'containers/scoped_ptr_map_unittest.cc',
'containers/small_map_unittest.cc',
'containers/stack_container_unittest.cc',
'cpu_unittest.cc',
@@ -476,8 +469,10 @@
'debug/task_annotator_unittest.cc',
'deferred_sequenced_task_runner_unittest.cc',
'environment_unittest.cc',
+ 'feature_list_unittest.cc',
'file_version_info_unittest.cc',
'files/dir_reader_posix_unittest.cc',
+ 'files/file_locking_unittest.cc',
'files/file_path_unittest.cc',
'files/file_path_watcher_unittest.cc',
'files/file_proxy_unittest.cc',
@@ -495,6 +490,7 @@
'i18n/char_iterator_unittest.cc',
'i18n/file_util_icu_unittest.cc',
'i18n/icu_string_conversions_unittest.cc',
+ 'i18n/message_formatter_unittest.cc',
'i18n/number_formatting_unittest.cc',
'i18n/rtl_unittest.cc',
'i18n/streaming_utf8_validator_unittest.cc',
@@ -514,6 +510,7 @@
'lazy_instance_unittest.cc',
'logging_unittest.cc',
'mac/bind_objc_block_unittest.mm',
+ 'mac/call_with_eh_frame_unittest.mm',
'mac/dispatch_source_mach_unittest.cc',
'mac/foundation_util_unittest.mm',
'mac/libdispatch_task_runner_unittest.cc',
@@ -526,20 +523,22 @@
'memory/aligned_memory_unittest.cc',
'memory/discardable_shared_memory_unittest.cc',
'memory/linked_ptr_unittest.cc',
+ 'memory/memory_pressure_listener_unittest.cc',
'memory/memory_pressure_monitor_chromeos_unittest.cc',
'memory/memory_pressure_monitor_mac_unittest.cc',
'memory/memory_pressure_monitor_win_unittest.cc',
+ 'memory/ptr_util_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/shared_memory_mac_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_task_runner_unittest.cc',
'message_loop/message_loop_unittest.cc',
'message_loop/message_pump_glib_unittest.cc',
'message_loop/message_pump_io_ios_unittest.cc',
@@ -551,11 +550,12 @@
'metrics/histogram_macros_unittest.cc',
'metrics/histogram_snapshot_manager_unittest.cc',
'metrics/histogram_unittest.cc',
+ 'metrics/metrics_hashes_unittest.cc',
'metrics/sample_map_unittest.cc',
'metrics/sample_vector_unittest.cc',
'metrics/sparse_histogram_unittest.cc',
'metrics/statistics_recorder_unittest.cc',
- 'move_unittest.cc',
+ 'native_library_unittest.cc',
'numerics/safe_numerics_unittest.cc',
'observer_list_unittest.cc',
'os_compat_android_unittest.cc',
@@ -593,6 +593,7 @@
'sha1_unittest.cc',
'stl_util_unittest.cc',
'strings/nullable_string16_unittest.cc',
+ 'strings/pattern_unittest.cc',
'strings/safe_sprintf_unittest.cc',
'strings/string16_unittest.cc',
'strings/string_number_conversions_unittest.cc',
@@ -618,8 +619,6 @@
'task/cancelable_task_tracker_unittest.cc',
'task_runner_util_unittest.cc',
'template_util_unittest.cc',
- 'test/expectations/expectation_unittest.cc',
- 'test/expectations/parser_unittest.cc',
'test/histogram_tester_unittest.cc',
'test/test_pending_task_unittest.cc',
'test/test_reg_util_win_unittest.cc',
@@ -628,6 +627,7 @@
'threading/non_thread_safe_unittest.cc',
'threading/platform_thread_unittest.cc',
'threading/sequenced_worker_pool_unittest.cc',
+ 'threading/sequenced_task_runner_handle_unittest.cc',
'threading/simple_thread_unittest.cc',
'threading/thread_checker_unittest.cc',
'threading/thread_collision_warner_unittest.cc',
@@ -663,6 +663,7 @@
'win/registry_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',
@@ -700,7 +701,13 @@
}],
['OS == "ios" and _toolset != "host"', {
'sources/': [
- # Only test the iOS-meaningful portion of process_utils.
+ # This test needs multiple processes.
+ ['exclude', '^files/file_locking_unittest\\.cc$'],
+ # iOS does not support FilePathWatcher.
+ ['exclude', '^files/file_path_watcher_unittest\\.cc$'],
+ # Only test the iOS-meaningful portion of memory and process_utils.
+ ['exclude', '^memory/discardable_shared_memory_unittest\\.cc$'],
+ ['exclude', '^memory/shared_memory_unittest\\.cc$'],
['exclude', '^process/memory_unittest'],
['exclude', '^process/process_unittest\\.cc$'],
['exclude', '^process/process_util_unittest\\.cc$'],
@@ -762,6 +769,14 @@
}],
]},
],
+ [ 'OS == "win" and target_arch == "x64"', {
+ 'sources': [
+ 'profiler/win32_stack_frame_unwinder_unittest.cc',
+ ],
+ 'dependencies': [
+ 'base_profiler_test_support_library',
+ ],
+ }],
['OS == "win"', {
'sources!': [
'file_descriptor_shuffle_unittest.cc',
@@ -794,7 +809,7 @@
],
}, { # OS != "win"
'dependencies': [
- '../third_party/libevent/libevent.gyp:libevent'
+ 'third_party/libevent/libevent.gyp:libevent'
],
}],
], # conditions
@@ -820,6 +835,12 @@
['OS=="mac" or OS=="ios" or <(chromeos)==1 or <(chromecast)==1', {
'defines': ['SYSTEM_NATIVE_UTF8'],
}],
+ # SyncSocket isn't used on iOS
+ ['OS=="ios"', {
+ 'sources!': [
+ 'sync_socket_unittest.cc',
+ ],
+ }],
], # target_conditions
},
{
@@ -900,10 +921,6 @@
}],
],
'sources': [
- 'test/expectations/expectation.cc',
- 'test/expectations/expectation.h',
- 'test/expectations/parser.cc',
- 'test/expectations/parser.h',
'test/gtest_util.cc',
'test/gtest_util.h',
'test/gtest_xml_unittest_result_printer.cc',
@@ -912,6 +929,8 @@
'test/gtest_xml_util.h',
'test/histogram_tester.cc',
'test/histogram_tester.h',
+ 'test/icu_test_util.cc',
+ 'test/icu_test_util.h',
'test/ios/wait_util.h',
'test/ios/wait_util.mm',
'test/launcher/test_launcher.cc',
@@ -1062,6 +1081,21 @@
}],
],
},
+ {
+ # GN version: //base/debug:debugging_flags
+ # Since this generates a file, it most only be referenced in the target
+ # toolchain or there will be multiple rules that generate the header.
+ # When referenced from a target that might be compiled in the host
+ # toolchain, always refer to 'base_debugging_flags#target'.
+ 'target_name': 'base_debugging_flags',
+ 'includes': [ '../build/buildflag_header.gypi' ],
+ 'variables': {
+ 'buildflag_header_path': 'base/debug/debugging_flags.h',
+ 'buildflag_flags': [
+ 'ENABLE_PROFILING=<(profiling)',
+ ],
+ },
+ },
],
'conditions': [
['OS=="ios" and "<(GENERATOR)"=="ninja"', {
@@ -1117,8 +1151,8 @@
'base_target': 1,
},
'dependencies': [
+ 'base_debugging_flags#target',
'base_static_win64',
- 'allocator/allocator.gyp:allocator_extension_thunks_win64',
'../third_party/modp_b64/modp_b64.gyp:modp_b64_win64',
'third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations_win64',
'trace_event/etw_manifest/etw_manifest.gyp:etw_manifest',
@@ -1185,9 +1219,6 @@
4267,
],
'sources': [
- 'async_socket_io_handler.h',
- 'async_socket_io_handler_posix.cc',
- 'async_socket_io_handler_win.cc',
'auto_reset.h',
'linux_util.cc',
'linux_util.h',
@@ -1265,6 +1296,21 @@
},
],
}],
+ ['OS == "win" and target_arch=="x64"', {
+ 'targets': [
+ {
+ 'target_name': 'base_profiler_test_support_library',
+ # Must be a shared library so that it can be unloaded during testing.
+ 'type': 'shared_library',
+ 'include_dirs': [
+ '..',
+ ],
+ 'sources': [
+ 'profiler/test_support_library.cc',
+ ],
+ },
+ ]
+ }],
['os_posix==1 and OS!="mac" and OS!="ios"', {
'targets': [
{
@@ -1369,6 +1415,7 @@
'android/java/src/org/chromium/base/BuildInfo.java',
'android/java/src/org/chromium/base/CommandLine.java',
'android/java/src/org/chromium/base/ContentUriUtils.java',
+ 'android/java/src/org/chromium/base/ContextUtils.java',
'android/java/src/org/chromium/base/CpuFeatures.java',
'android/java/src/org/chromium/base/EventLog.java',
'android/java/src/org/chromium/base/FieldTrialList.java',
@@ -1407,7 +1454,7 @@
'includes': [ '../build/jar_file_jni_generator.gypi' ],
},
{
- # TODO(GN)
+ # GN: //base:base_unittests_jni_headers
'target_name': 'base_unittests_jni_headers',
'type': 'none',
'sources': [
@@ -1433,6 +1480,22 @@
'includes': [ '../build/android/java_cpp_template.gypi' ],
},
{
+ # GN: //base:base_multidex_gen
+ 'target_name': 'base_multidex_gen',
+ 'type': 'none',
+ 'sources': [
+ 'android/java/templates/ChromiumMultiDex.template',
+ ],
+ 'variables': {
+ 'package_name': 'org/chromium/base/multidex',
+ 'template_deps': [],
+ 'additional_gcc_preprocess_options': [
+ '--defines', 'MULTIDEX_CONFIGURATION_<(CONFIGURATION_NAME)',
+ ],
+ },
+ 'includes': ['../build/android/java_cpp_template.gypi'],
+ },
+ {
# GN: //base:base_android_java_enums_srcjar
'target_name': 'base_java_library_process_type',
'type': 'none',
@@ -1446,7 +1509,7 @@
'target_name': 'base_java',
'type': 'none',
'variables': {
- 'java_in_dir': '../base/android/java',
+ 'java_in_dir': 'android/java',
'jar_excluded_classes': [ '*/NativeLibraries.class' ],
},
'dependencies': [
@@ -1454,7 +1517,9 @@
'base_java_library_load_from_apk_status_codes',
'base_java_library_process_type',
'base_java_memory_pressure_level',
+ 'base_multidex_gen',
'base_native_libraries_gen',
+ '../third_party/android_tools/android_tools.gyp:android_support_multidex_javalib',
'../third_party/jsr-305/jsr-305.gyp:jsr_305_javalib',
],
'includes': [ '../build/java.gypi' ],
@@ -1512,18 +1577,37 @@
'includes': [ '../build/java.gypi' ],
},
{
+ # TODO(jbudorick): Remove this once we roll to robolectric 3.0 and pull
+ # in the multidex shadow library. crbug.com/522043
+ # GN: //base:base_junit_test_support
+ 'target_name': 'base_junit_test_support',
+ 'type': 'none',
+ 'dependencies': [
+ '../testing/android/junit/junit_test.gyp:junit_test_support',
+ '../third_party/android_tools/android_tools.gyp:android_support_multidex_javalib',
+ ],
+ 'variables': {
+ 'src_paths': [
+ '../base/test/android/junit/src/org/chromium/base/test/shadows/ShadowMultiDex.java',
+ ],
+ },
+ 'includes': [ '../build/host_jar.gypi' ]
+ },
+ {
# GN: //base:base_junit_tests
'target_name': 'base_junit_tests',
'type': 'none',
'dependencies': [
'base_java',
'base_java_test_support',
+ 'base_junit_test_support',
'../testing/android/junit/junit_test.gyp:junit_test_support',
],
'variables': {
'main_class': 'org.chromium.testing.local.JunitTestMain',
'src_paths': [
'../base/android/junit/',
+ '../base/test/android/junit/src/org/chromium/base/test/util/DisableIfTest.java',
],
},
'includes': [ '../build/host_jar.gypi' ],
@@ -1546,7 +1630,13 @@
'target_name': 'chromium_android_linker',
'type': 'shared_library',
'sources': [
+ 'android/linker/android_dlext.h',
+ 'android/linker/legacy_linker_jni.cc',
+ 'android/linker/legacy_linker_jni.h',
'android/linker/linker_jni.cc',
+ 'android/linker/linker_jni.h',
+ 'android/linker/modern_linker_jni.cc',
+ 'android/linker/modern_linker_jni.h',
],
# The crazy linker is never instrumented.
'cflags!': [
@@ -1560,7 +1650,7 @@
],
},
{
- # TODO(GN)
+ # GN: //base:base_perftests_apk
'target_name': 'base_perftests_apk',
'type': 'none',
'dependencies': [
@@ -1586,22 +1676,31 @@
'includes': [ '../build/apk_test.gypi' ],
},
],
+ 'conditions': [
+ ['test_isolation_mode != "noop"',
+ {
+ 'targets': [
+ {
+ 'target_name': 'base_unittests_apk_run',
+ 'type': 'none',
+ 'dependencies': [
+ 'base_unittests_apk',
+ ],
+ 'includes': [
+ '../build/isolate.gypi',
+ ],
+ 'sources': [
+ 'base_unittests_apk.isolate',
+ ],
+ },
+ ]
+ }
+ ],
+ ],
}],
['OS == "win"', {
'targets': [
{
- 'target_name': 'debug_message',
- 'type': 'executable',
- 'sources': [
- 'debug_message.cc',
- ],
- 'msvs_settings': {
- 'VCLinkerTool': {
- 'SubSystem': '2', # Set /SUBSYSTEM:WINDOWS
- },
- },
- },
- {
# Target to manually rebuild pe_image_test.dll which is checked into
# base/test/data/pe_image.
'target_name': 'pe_image_test',
diff --git a/base/base.gypi b/base/base.gypi
index 81a8c99d07..bb028bdf11 100644
--- a/base/base.gypi
+++ b/base/base.gypi
@@ -16,10 +16,10 @@
['base_target==1', {
'sources': [
'../build/build_config.h',
+ 'allocator/allocator_check.cc',
+ 'allocator/allocator_check.h',
'allocator/allocator_extension.cc',
'allocator/allocator_extension.h',
- 'allocator/type_profiler_control.cc',
- 'allocator/type_profiler_control.h',
'android/animation_frame_time_histogram.cc',
'android/animation_frame_time_histogram.h',
'android/apk_assets.cc',
@@ -36,7 +36,10 @@
'android/command_line_android.h',
'android/content_uri_utils.cc',
'android/content_uri_utils.h',
+ 'android/context_utils.cc',
+ 'android/context_utils.h',
'android/cpu_features.cc',
+ 'android/cxa_demangle_stub.cc',
'android/event_log.cc',
'android/event_log.h',
'android/field_trial_list.cc',
@@ -90,16 +93,14 @@
'atomic_ref_count.h',
'atomic_sequence_num.h',
'atomicops.h',
- 'atomicops_internals_gcc.h',
- 'atomicops_internals_mac.h',
'atomicops_internals_portable.h',
- 'atomicops_internals_x86_gcc.cc',
- 'atomicops_internals_x86_gcc.h',
'atomicops_internals_x86_msvc.h',
'barrier_closure.cc',
'barrier_closure.h',
'base64.cc',
'base64.h',
+ 'base64url.cc',
+ 'base64url.h',
'base_export.h',
'base_paths.cc',
'base_paths.h',
@@ -112,7 +113,6 @@
'base_paths_win.cc',
'base_paths_win.h',
'base_switches.h',
- 'basictypes.h',
'big_endian.cc',
'big_endian.h',
'bind.h',
@@ -120,6 +120,7 @@
'bind_helpers.h',
'bind_internal.h',
'bind_internal_win.h',
+ 'bit_cast.h',
'bits.h',
'build_time.cc',
'build_time.h',
@@ -138,7 +139,6 @@
'containers/linked_list.h',
'containers/mru_cache.h',
'containers/scoped_ptr_hash_map.h',
- 'containers/scoped_ptr_map.h',
'containers/small_map.h',
'containers/stack_container.h',
'cpu.cc',
@@ -149,6 +149,8 @@
'debug/alias.h',
'debug/asan_invalid_access.cc',
'debug/asan_invalid_access.h',
+ 'debug/close_handle_hook_win.cc',
+ 'debug/close_handle_hook_win.h',
'debug/crash_logging.cc',
'debug/crash_logging.h',
'debug/debugger.cc',
@@ -179,6 +181,8 @@
'deferred_sequenced_task_runner.h',
'environment.cc',
'environment.h',
+ 'feature_list.cc',
+ 'feature_list.h',
'file_descriptor_posix.h',
'file_version_info.h',
'file_version_info_mac.h',
@@ -248,6 +252,8 @@
'ios/device_util.mm',
'ios/ios_util.h',
'ios/ios_util.mm',
+ 'ios/ns_error_util.h',
+ 'ios/ns_error_util.mm',
'ios/scoped_critical_action.h',
'ios/scoped_critical_action.mm',
'ios/weak_nsobject.h',
@@ -279,6 +285,9 @@
'mac/bind_objc_block.h',
'mac/bundle_locations.h',
'mac/bundle_locations.mm',
+ 'mac/call_with_eh_frame.cc',
+ 'mac/call_with_eh_frame.h',
+ 'mac/call_with_eh_frame_asm.S',
'mac/close_nocancel.cc',
'mac/cocoa_protocols.h',
'mac/dispatch_source_mach.cc',
@@ -314,8 +323,6 @@
'mac/scoped_mach_vm.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_objc_class_swizzler.h',
'mac/scoped_objc_class_swizzler.mm',
@@ -347,6 +354,7 @@
'memory/memory_pressure_monitor_mac.h',
'memory/memory_pressure_monitor_win.cc',
'memory/memory_pressure_monitor_win.h',
+ 'memory/ptr_util.h',
'memory/raw_scoped_refptr_mismatch_checker.h',
'memory/ref_counted.cc',
'memory/ref_counted.h',
@@ -358,6 +366,10 @@
'memory/scoped_vector.h',
'memory/shared_memory.h',
'memory/shared_memory_android.cc',
+ 'memory/shared_memory_handle.h',
+ 'memory/shared_memory_handle_mac.cc',
+ 'memory/shared_memory_handle_win.cc',
+ 'memory/shared_memory_mac.cc',
'memory/shared_memory_nacl.cc',
'memory/shared_memory_posix.cc',
'memory/shared_memory_win.cc',
@@ -369,10 +381,8 @@
'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_loop_task_runner.cc',
+ 'message_loop/message_loop_task_runner.h',
'message_loop/message_pump.cc',
'message_loop/message_pump.h',
'message_loop/message_pump_android.cc',
@@ -396,6 +406,8 @@
'metrics/histogram_samples.h',
'metrics/histogram_snapshot_manager.cc',
'metrics/histogram_snapshot_manager.h',
+ 'metrics/metrics_hashes.cc',
+ 'metrics/metrics_hashes.h',
'metrics/sample_map.cc',
'metrics/sample_map.h',
'metrics/sample_vector.cc',
@@ -433,7 +445,6 @@
'pending_task.h',
'pickle.cc',
'pickle.h',
- 'port.h',
'posix/eintr_wrapper.h',
'posix/global_descriptors.cc',
'posix/global_descriptors.h',
@@ -473,7 +484,10 @@
'process/memory_linux.cc',
'process/memory_mac.mm',
'process/memory_win.cc',
+ 'process/port_provider_mac.cc',
+ 'process/port_provider_mac.h',
'process/process.h',
+ 'process/process_handle.cc',
'process/process_handle_freebsd.cc',
'process/process_handle_linux.cc',
'process/process_handle_mac.cc',
@@ -492,13 +506,13 @@
'process/process_iterator_openbsd.cc',
'process/process_iterator_win.cc',
'process/process_linux.cc',
- 'process/process_mac.cc',
'process/process_metrics.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_nacl.cc',
'process/process_metrics_openbsd.cc',
'process/process_metrics_posix.cc',
'process/process_metrics_win.cc',
@@ -508,14 +522,14 @@
'profiler/alternate_timer.h',
'profiler/native_stack_sampler.cc',
'profiler/native_stack_sampler.h',
+ 'profiler/native_stack_sampler_posix.cc',
+ 'profiler/native_stack_sampler_win.cc',
'profiler/scoped_profile.cc',
'profiler/scoped_profile.h',
'profiler/scoped_tracker.cc',
'profiler/scoped_tracker.h',
'profiler/stack_sampling_profiler.cc',
'profiler/stack_sampling_profiler.h',
- 'profiler/stack_sampling_profiler_posix.cc',
- 'profiler/stack_sampling_profiler_win.cc',
'profiler/tracked_time.cc',
'profiler/tracked_time.h',
'rand_util.cc',
@@ -544,6 +558,8 @@
'strings/latin1_string_conversions.h',
'strings/nullable_string16.cc',
'strings/nullable_string16.h',
+ 'strings/pattern.cc',
+ 'strings/pattern.h',
'strings/safe_sprintf.cc',
'strings/safe_sprintf.h',
'strings/string16.cc',
@@ -637,6 +653,8 @@
'threading/platform_thread_win.cc',
'threading/post_task_and_reply_impl.cc',
'threading/post_task_and_reply_impl.h',
+ 'threading/sequenced_task_runner_handle.cc',
+ 'threading/sequenced_task_runner_handle.h',
'threading/sequenced_worker_pool.cc',
'threading/sequenced_worker_pool.h',
'threading/simple_thread.cc',
@@ -717,10 +735,10 @@
'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/process_startup_helper.cc',
+ 'win/process_startup_helper.h',
'win/registry.cc',
'win/registry.h',
'win/resource_util.cc',
@@ -759,17 +777,22 @@
'include_dirs': [
'..',
],
- 'msvs_disabled_warnings': [
- 4018,
- ],
'target_conditions': [
+ ['OS == "mac" or OS == "ios"', {
+ 'sources!': [
+ 'memory/shared_memory_posix.cc',
+ ],
+ }],
+ ['OS == "ios"', {
+ 'sources!': [
+ 'memory/discardable_shared_memory.cc',
+ 'memory/discardable_shared_memory.h',
+ ],
+ }],
['(<(desktop_linux) == 0 and <(chromeos) == 0) or >(nacl_untrusted_build)==1', {
'sources/': [
['exclude', '^nix/'],
],
- 'sources!': [
- 'atomicops_internals_x86_gcc.cc',
- ],
}],
['<(use_glib)==0 or >(nacl_untrusted_build)==1', {
'sources!': [
@@ -785,8 +808,6 @@
],
['>(nacl_untrusted_build)==1', {
'sources!': [
- 'allocator/type_profiler_control.cc',
- 'allocator/type_profiler_control.h',
'base_paths.cc',
'cpu.cc',
'debug/stack_trace.cc',
@@ -849,12 +870,8 @@
],
}],
['OS == "android" and _toolset == "host" and host_os == "linux"', {
- 'defines': [
- 'OS_ANDROID_HOST=Linux',
- ],
'sources/': [
# Pull in specific files for host builds.
- ['include', '^atomicops_internals_x86_gcc\\.cc$'],
['include', '^threading/platform_thread_linux\\.cc$'],
],
}],
@@ -867,11 +884,11 @@
'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', '^files/file_util_mac\\.'],
['include', '^file_version_info_mac\\.'],
['include', '^mac/bundle_locations\\.'],
+ ['include', '^mac/call_with_eh_frame\\.'],
['include', '^mac/foundation_util\\.'],
['include', '^mac/mac_logging\\.'],
['include', '^mac/mach_logging\\.'],
@@ -881,6 +898,7 @@
['include', '^mac/scoped_nsautorelease_pool\\.'],
['include', '^mac/scoped_nsobject\\.'],
['include', '^mac/scoped_objc_class_swizzler\\.'],
+ ['include', '^memory/shared_memory_posix\\.'],
['include', '^message_loop/message_pump_mac\\.'],
['include', '^strings/sys_string_conversions_mac\\.'],
['include', '^threading/platform_thread_mac\\.'],
@@ -893,10 +911,9 @@
['include', '^process/memory_stubs\.cc$'],
['include', '^process/process_handle_posix\.cc$'],
['include', '^process/process_metrics\\.cc$'],
+ # Exclude unsupported features on iOS.
+ ['exclude', '^files/file_path_watcher.*'],
['exclude', '^threading/platform_thread_internal_posix\\.(h|cc)'],
- ['exclude', 'files/file_path_watcher_fsevents.cc'],
- ['exclude', 'files/file_path_watcher_fsevents.h'],
- ['include', 'files/file_path_watcher_mac.cc'],
],
'sources': [
'process/memory_stubs.cc',
@@ -931,6 +948,10 @@
'include_dirs': [
'<(DEPTH)/third_party/wtl/include',
],
+ 'sources': [
+ 'profiler/win32_stack_frame_unwinder.cc',
+ 'profiler/win32_stack_frame_unwinder.h',
+ ],
'sources!': [
'files/file_path_watcher_fsevents.cc',
'files/file_path_watcher_fsevents.h',
@@ -998,6 +1019,8 @@
],
'sources': [
'i18n/base_i18n_export.h',
+ 'i18n/base_i18n_switches.cc',
+ 'i18n/base_i18n_switches.h',
'i18n/bidi_line_iterator.cc',
'i18n/bidi_line_iterator.h',
'i18n/break_iterator.cc',
@@ -1016,6 +1039,8 @@
'i18n/icu_string_conversions.h',
'i18n/icu_util.cc',
'i18n/icu_util.h',
+ 'i18n/message_formatter.cc',
+ 'i18n/message_formatter.h',
'i18n/number_formatting.cc',
'i18n/number_formatting.h',
'i18n/rtl.cc',
diff --git a/base/base.isolate b/base/base.isolate
index c7ba651ac7..e2d8beaca8 100644
--- a/base/base.isolate
+++ b/base/base.isolate
@@ -9,6 +9,8 @@
'../third_party/icu/icu.isolate',
# Sanitizer-instrumented third-party libraries (if enabled).
'../third_party/instrumented_libraries/instrumented_libraries.isolate',
+ # MSVS runtime libraries.
+ '../build/config/win/msvs_dependencies.isolate',
],
'conditions': [
['use_custom_libcxx==1', {
@@ -36,7 +38,9 @@
['OS=="win" and asan==1 and component=="shared_library"', {
'variables': {
'files': [
- '../third_party/llvm-build/Release+Asserts/lib/clang/3.7.0/lib/windows/clang_rt.asan_dynamic-i386.dll',
+ # We only need x.y.z/lib/windows/clang_rt.asan_dynamic-i386.dll,
+ # but since the version (x.y.z) changes, just grab the whole dir.
+ '../third_party/llvm-build/Release+Asserts/lib/clang/',
],
},
}],
@@ -56,40 +60,6 @@
],
},
}],
- # Copy the VS runtime DLLs into the isolate so that they
- # don't have to be preinstalled on the target machine.
- ['OS=="win" and component=="shared_library" and CONFIGURATION_NAME=="Debug"', {
- 'variables': {
- 'files': [
- '<(PRODUCT_DIR)/x64/msvcp120d.dll',
- '<(PRODUCT_DIR)/x64/msvcr120d.dll',
- ],
- },
- }],
- ['OS=="win" and component=="shared_library" and CONFIGURATION_NAME=="Release"', {
- 'variables': {
- 'files': [
- '<(PRODUCT_DIR)/x64/msvcp120.dll',
- '<(PRODUCT_DIR)/x64/msvcr120.dll',
- ],
- },
- }],
- ['OS=="win" and component=="shared_library" and (CONFIGURATION_NAME=="Debug" or CONFIGURATION_NAME=="Debug_x64")', {
- 'variables': {
- 'files': [
- '<(PRODUCT_DIR)/msvcp120d.dll',
- '<(PRODUCT_DIR)/msvcr120d.dll',
- ],
- },
- }],
- ['OS=="win" and component=="shared_library" and (CONFIGURATION_NAME=="Release" or CONFIGURATION_NAME=="Release_x64")', {
- 'variables': {
- 'files': [
- '<(PRODUCT_DIR)/msvcp120.dll',
- '<(PRODUCT_DIR)/msvcr120.dll',
- ],
- },
- }],
# Workaround for https://code.google.com/p/swarming/issues/detail?id=211
['asan==0 or lsan==0 or msan==0 or tsan==0', {
'variables': {},
diff --git a/base/base64.cc b/base/base64.cc
index 9d11f8c166..61d853897b 100644
--- a/base/base64.cc
+++ b/base/base64.cc
@@ -4,6 +4,8 @@
#include "base/base64.h"
+#include <stddef.h>
+
#include <modp_b64/modp_b64.h>
namespace base {
diff --git a/base/base64url.cc b/base/base64url.cc
new file mode 100644
index 0000000000..942229e76a
--- /dev/null
+++ b/base/base64url.cc
@@ -0,0 +1,102 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/base64url.h"
+
+#include <stddef.h>
+
+#include "base/base64.h"
+#include "base/macros.h"
+#include "base/numerics/safe_math.h"
+#include "base/strings/string_util.h"
+
+#include <modp_b64/modp_b64.h>
+
+namespace base {
+
+const char kPaddingChar = '=';
+
+// Base64url maps {+, /} to {-, _} in order for the encoded content to be safe
+// to use in a URL. These characters will be translated by this implementation.
+const char kBase64Chars[] = "+/";
+const char kBase64UrlSafeChars[] = "-_";
+
+void Base64UrlEncode(const StringPiece& input,
+ Base64UrlEncodePolicy policy,
+ std::string* output) {
+ Base64Encode(input, output);
+
+ ReplaceChars(*output, "+", "-", output);
+ ReplaceChars(*output, "/", "_", output);
+
+ switch (policy) {
+ case Base64UrlEncodePolicy::INCLUDE_PADDING:
+ // The padding included in |*output| will not be amended.
+ break;
+ case Base64UrlEncodePolicy::OMIT_PADDING:
+ // The padding included in |*output| will be removed.
+ const size_t last_non_padding_pos =
+ output->find_last_not_of(kPaddingChar);
+ if (last_non_padding_pos != std::string::npos)
+ output->resize(last_non_padding_pos + 1);
+
+ break;
+ }
+}
+
+bool Base64UrlDecode(const StringPiece& input,
+ Base64UrlDecodePolicy policy,
+ std::string* output) {
+ // Characters outside of the base64url alphabet are disallowed, which includes
+ // the {+, /} characters found in the conventional base64 alphabet.
+ if (input.find_first_of(kBase64Chars) != std::string::npos)
+ return false;
+
+ const size_t required_padding_characters = input.size() % 4;
+ const bool needs_replacement =
+ input.find_first_of(kBase64UrlSafeChars) != std::string::npos;
+
+ switch (policy) {
+ case Base64UrlDecodePolicy::REQUIRE_PADDING:
+ // Fail if the required padding is not included in |input|.
+ if (required_padding_characters > 0)
+ return false;
+ break;
+ case Base64UrlDecodePolicy::IGNORE_PADDING:
+ // Missing padding will be silently appended.
+ break;
+ case Base64UrlDecodePolicy::DISALLOW_PADDING:
+ // Fail if padding characters are included in |input|.
+ if (input.find_first_of(kPaddingChar) != std::string::npos)
+ return false;
+ break;
+ }
+
+ // If the string either needs replacement of URL-safe characters to normal
+ // base64 ones, or additional padding, a copy of |input| needs to be made in
+ // order to make these adjustments without side effects.
+ if (required_padding_characters > 0 || needs_replacement) {
+ std::string base64_input;
+
+ CheckedNumeric<size_t> base64_input_size = input.size();
+ if (required_padding_characters > 0)
+ base64_input_size += 4 - required_padding_characters;
+
+ base64_input.reserve(base64_input_size.ValueOrDie());
+ input.AppendToString(&base64_input);
+
+ // Substitute the base64url URL-safe characters to their base64 equivalents.
+ ReplaceChars(base64_input, "-", "+", &base64_input);
+ ReplaceChars(base64_input, "_", "/", &base64_input);
+
+ // Append the necessary padding characters.
+ base64_input.resize(base64_input_size.ValueOrDie(), '=');
+
+ return Base64Decode(base64_input, output);
+ }
+
+ return Base64Decode(input, output);
+}
+
+} // namespace base
diff --git a/base/base64url.h b/base/base64url.h
new file mode 100644
index 0000000000..66a482461b
--- /dev/null
+++ b/base/base64url.h
@@ -0,0 +1,56 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_BASE64URL_H_
+#define BASE_BASE64URL_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+
+enum class Base64UrlEncodePolicy {
+ // Include the trailing padding in the output, when necessary.
+ INCLUDE_PADDING,
+
+ // Remove the trailing padding from the output.
+ OMIT_PADDING
+};
+
+// Encodes the |input| string in base64url, defined in RFC 4648:
+// https://tools.ietf.org/html/rfc4648#section-5
+//
+// The |policy| defines whether padding should be included or omitted from the
+// encoded |*output|. |input| and |*output| may reference the same storage.
+BASE_EXPORT void Base64UrlEncode(const StringPiece& input,
+ Base64UrlEncodePolicy policy,
+ std::string* output);
+
+enum class Base64UrlDecodePolicy {
+ // Require inputs contain trailing padding if non-aligned.
+ REQUIRE_PADDING,
+
+ // Accept inputs regardless of whether or not they have the correct padding.
+ IGNORE_PADDING,
+
+ // Reject inputs if they contain any trailing padding.
+ DISALLOW_PADDING
+};
+
+// Decodes the |input| string in base64url, defined in RFC 4648:
+// https://tools.ietf.org/html/rfc4648#section-5
+//
+// The |policy| defines whether padding will be required, ignored or disallowed
+// altogether. |input| and |*output| may reference the same storage.
+BASE_EXPORT bool Base64UrlDecode(const StringPiece& input,
+ Base64UrlDecodePolicy policy,
+ std::string* output) WARN_UNUSED_RESULT;
+
+} // namespace base
+
+#endif // BASE_BASE64URL_H_
diff --git a/base/base64url_unittest.cc b/base/base64url_unittest.cc
new file mode 100644
index 0000000000..45aa4a8c5e
--- /dev/null
+++ b/base/base64url_unittest.cc
@@ -0,0 +1,115 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/base64url.h"
+
+#include "base/macros.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+TEST(Base64UrlTest, EncodeIncludePaddingPolicy) {
+ std::string output;
+ Base64UrlEncode("hello?world", Base64UrlEncodePolicy::INCLUDE_PADDING,
+ &output);
+
+ // Base64 version: aGVsbG8/d29ybGQ=
+ EXPECT_EQ("aGVsbG8_d29ybGQ=", output);
+
+ // Test for behavior for very short and empty strings.
+ Base64UrlEncode("??", Base64UrlEncodePolicy::INCLUDE_PADDING, &output);
+ EXPECT_EQ("Pz8=", output);
+
+ Base64UrlEncode("", Base64UrlEncodePolicy::INCLUDE_PADDING, &output);
+ EXPECT_EQ("", output);
+}
+
+TEST(Base64UrlTest, EncodeOmitPaddingPolicy) {
+ std::string output;
+ Base64UrlEncode("hello?world", Base64UrlEncodePolicy::OMIT_PADDING, &output);
+
+ // base64 version: aGVsbG8/d29ybGQ=
+ EXPECT_EQ("aGVsbG8_d29ybGQ", output);
+
+ // Test for behavior for very short and empty strings.
+ Base64UrlEncode("??", Base64UrlEncodePolicy::OMIT_PADDING, &output);
+ EXPECT_EQ("Pz8", output);
+
+ Base64UrlEncode("", Base64UrlEncodePolicy::OMIT_PADDING, &output);
+ EXPECT_EQ("", output);
+}
+
+TEST(Base64UrlTest, DecodeRequirePaddingPolicy) {
+ std::string output;
+ ASSERT_TRUE(Base64UrlDecode("aGVsbG8_d29ybGQ=",
+ Base64UrlDecodePolicy::REQUIRE_PADDING, &output));
+
+ EXPECT_EQ("hello?world", output);
+
+ ASSERT_FALSE(Base64UrlDecode(
+ "aGVsbG8_d29ybGQ", Base64UrlDecodePolicy::REQUIRE_PADDING, &output));
+
+ // Test for behavior for very short and empty strings.
+ ASSERT_TRUE(
+ Base64UrlDecode("Pz8=", Base64UrlDecodePolicy::REQUIRE_PADDING, &output));
+ EXPECT_EQ("??", output);
+
+ ASSERT_TRUE(
+ Base64UrlDecode("", Base64UrlDecodePolicy::REQUIRE_PADDING, &output));
+ EXPECT_EQ("", output);
+}
+
+TEST(Base64UrlTest, DecodeIgnorePaddingPolicy) {
+ std::string output;
+ ASSERT_TRUE(Base64UrlDecode("aGVsbG8_d29ybGQ",
+ Base64UrlDecodePolicy::IGNORE_PADDING, &output));
+
+ EXPECT_EQ("hello?world", output);
+
+ // Including the padding is accepted as well.
+ ASSERT_TRUE(Base64UrlDecode("aGVsbG8_d29ybGQ=",
+ Base64UrlDecodePolicy::IGNORE_PADDING, &output));
+
+ EXPECT_EQ("hello?world", output);
+}
+
+TEST(Base64UrlTest, DecodeDisallowPaddingPolicy) {
+ std::string output;
+ ASSERT_FALSE(Base64UrlDecode(
+ "aGVsbG8_d29ybGQ=", Base64UrlDecodePolicy::DISALLOW_PADDING, &output));
+
+ // The policy will allow the input when padding has been omitted.
+ ASSERT_TRUE(Base64UrlDecode(
+ "aGVsbG8_d29ybGQ", Base64UrlDecodePolicy::DISALLOW_PADDING, &output));
+
+ EXPECT_EQ("hello?world", output);
+}
+
+TEST(Base64UrlTest, DecodeDisallowsBase64Alphabet) {
+ std::string output;
+
+ // The "/" character is part of the conventional base64 alphabet, but has been
+ // substituted with "_" in the base64url alphabet.
+ ASSERT_FALSE(Base64UrlDecode(
+ "aGVsbG8/d29ybGQ=", Base64UrlDecodePolicy::REQUIRE_PADDING, &output));
+}
+
+TEST(Base64UrlTest, DecodeDisallowsPaddingOnly) {
+ std::string output;
+
+ ASSERT_FALSE(Base64UrlDecode(
+ "=", Base64UrlDecodePolicy::IGNORE_PADDING, &output));
+ ASSERT_FALSE(Base64UrlDecode(
+ "==", Base64UrlDecodePolicy::IGNORE_PADDING, &output));
+ ASSERT_FALSE(Base64UrlDecode(
+ "===", Base64UrlDecodePolicy::IGNORE_PADDING, &output));
+ ASSERT_FALSE(Base64UrlDecode(
+ "====", Base64UrlDecodePolicy::IGNORE_PADDING, &output));
+}
+
+} // namespace
+
+} // namespace base
diff --git a/base/base_export.h b/base/base_export.h
index 723b38a60f..cf7ebd7816 100644
--- a/base/base_export.h
+++ b/base/base_export.h
@@ -10,25 +10,20 @@
#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_nacl.gyp b/base/base_nacl.gyp
index 7e7d34ff20..675cbd6ebc 100644
--- a/base/base_nacl.gyp
+++ b/base/base_nacl.gyp
@@ -35,10 +35,13 @@
'sync_socket_nacl.cc',
'time/time_posix.cc',
],
- 'gcc_compile_flags': [
+ 'compile_flags': [
'-fno-strict-aliasing',
],
},
+ 'dependencies': [
+ 'base.gyp:base_debugging_flags',
+ ],
},
{
'target_name': 'base_i18n_nacl',
@@ -96,6 +99,10 @@
# For GetKnownDeadTerminationStatus and GetTerminationStatus.
'process/kill_posix.cc',
+ # For ForkWithFlags.
+ 'process/launch.h',
+ 'process/launch_posix.cc',
+
# Unlike libbase_nacl, for Non-SFI build, we need to use
# rand_util_posix for random implementation, instead of
# rand_util_nacl.cc, which is based on IRT. rand_util_nacl.cc is
@@ -110,7 +117,8 @@
'rand_util_nacl.cc',
],
'dependencies': [
- '../third_party/libevent/libevent_nacl_nonsfi.gyp:event_nacl_nonsfi',
+ 'base.gyp:base_debugging_flags',
+ 'third_party/libevent/libevent_nacl_nonsfi.gyp:event_nacl_nonsfi',
],
},
{
diff --git a/base/base_switches.cc b/base/base_switches.cc
index 30765405de..02b2229885 100644
--- a/base/base_switches.cc
+++ b/base/base_switches.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "base/base_switches.h"
+#include "build/build_config.h"
namespace switches {
@@ -14,6 +15,11 @@ const char kDisableBreakpad[] = "disable-breakpad";
// generated internally.
const char kEnableCrashReporter[] = "enable-crash-reporter";
+// Makes memory allocators keep track of their allocations and context, so a
+// detailed breakdown of memory usage can be presented in chrome://tracing when
+// the memory-infra category is enabled.
+const char kEnableHeapProfiling[] = "enable-heap-profiling";
+
// Generates full memory crash dump.
const char kFullMemoryCrashReport[] = "full-memory-crash-report";
@@ -23,6 +29,16 @@ const char kEnableLowEndDeviceMode[] = "enable-low-end-device-mode";
// Force disabling of low-end device mode when set.
const char kDisableLowEndDeviceMode[] = "disable-low-end-device-mode";
+// This option can be used to force field trials when testing changes locally.
+// The argument is a list of name and value pairs, separated by slashes. If a
+// trial name is prefixed with an asterisk, that trial will start activated.
+// For example, the following argument defines two trials, with the second one
+// activated: "GoogleNow/Enable/*MaterialDesignNTP/Default/" This option can
+// also be used by the browser process to send the list of trials to a
+// non-browser process, using the same format. See
+// FieldTrialList::CreateTrialsFromString() in field_trial.h for details.
+const char kForceFieldTrials[] = "force-fieldtrials";
+
// Suppresses all error dialogs when present.
const char kNoErrorDialogs[] = "noerrdialogs";
@@ -48,9 +64,6 @@ 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";
-
// Sends trace events from these categories to a file.
// --trace-to-file on its own sends to default categories.
const char kTraceToFile[] = "trace-to-file";
@@ -67,6 +80,11 @@ const char kProfilerTiming[] = "profiler-timing";
// chrome://profiler.
const char kProfilerTimingDisabledValue[] = "0";
+#if defined(OS_WIN)
+// Disables the USB keyboard detection for blocking the OSK on Win8+.
+const char kDisableUsbKeyboardDetect[] = "disable-usb-keyboard-detect";
+#endif
+
#if defined(OS_POSIX)
// Used for turning on Breakpad crash reporting in a debug environment where
// crash reporting is typically compiled but disabled.
diff --git a/base/base_switches.h b/base/base_switches.h
index c579f6a240..c97a629d9f 100644
--- a/base/base_switches.h
+++ b/base/base_switches.h
@@ -12,21 +12,26 @@
namespace switches {
extern const char kDisableBreakpad[];
+extern const char kDisableLowEndDeviceMode[];
extern const char kEnableCrashReporter[];
-extern const char kFullMemoryCrashReport[];
+extern const char kEnableHeapProfiling[];
extern const char kEnableLowEndDeviceMode[];
-extern const char kDisableLowEndDeviceMode[];
+extern const char kForceFieldTrials[];
+extern const char kFullMemoryCrashReport[];
extern const char kNoErrorDialogs[];
extern const char kProfilerTiming[];
extern const char kProfilerTimingDisabledValue[];
extern const char kTestChildProcess[];
-extern const char kTraceToConsole[];
extern const char kTraceToFile[];
extern const char kTraceToFileName[];
extern const char kV[];
extern const char kVModule[];
extern const char kWaitForDebugger[];
+#if defined(OS_WIN)
+extern const char kDisableUsbKeyboardDetect[];
+#endif
+
#if defined(OS_POSIX)
extern const char kEnableCrashReporterForTesting[];
#endif
diff --git a/base/base_unittests.isolate b/base/base_unittests.isolate
index 57fc4d2e53..208501fce8 100644
--- a/base/base_unittests.isolate
+++ b/base/base_unittests.isolate
@@ -25,9 +25,7 @@
'variables': {
'files': [
'../testing/test_env.py',
- '<(PRODUCT_DIR)/base_unittests<(EXECUTABLE_SUFFIX)',
],
- 'read_only': 1,
},
}],
['OS=="linux"', {
diff --git a/base/basictypes.h b/base/basictypes.h
deleted file mode 100644
index d71abd9bac..0000000000
--- a/base/basictypes.h
+++ /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 contains definitions of our old basic integral types
-// ((u)int{8,16,32,64}) and further includes. I recommend that you use the C99
-// standard types instead, and include <stdint.h>/<stddef.h>/etc. as needed.
-// Note that the macros and macro-like constructs that were formerly defined in
-// this file are now available separately in base/macros.h.
-
-#ifndef BASE_BASICTYPES_H_
-#define BASE_BASICTYPES_H_
-
-#include <limits.h> // So we can set the bounds of our types.
-#include <stddef.h> // For size_t.
-#include <stdint.h> // For intptr_t.
-
-#include "base/macros.h"
-#include "build/build_config.h"
-
-// DEPRECATED: Please use (u)int{8,16,32,64}_t instead (and include <stdint.h>).
-typedef int8_t int8;
-typedef uint8_t uint8;
-typedef int16_t int16;
-typedef uint16_t uint16;
-typedef int32_t int32;
-typedef uint32_t uint32;
-typedef int64_t int64;
-typedef uint64_t uint64;
-
-// DEPRECATED: Please use std::numeric_limits (from <limits>) instead.
-const uint8 kuint8max = 0xFF;
-const uint16 kuint16max = 0xFFFF;
-const uint32 kuint32max = 0xFFFFFFFF;
-const uint64 kuint64max = 0xFFFFFFFFFFFFFFFFULL;
-const int8 kint8min = -0x7F - 1;
-const int8 kint8max = 0x7F;
-const int16 kint16min = -0x7FFF - 1;
-const int16 kint16max = 0x7FFF;
-const int32 kint32min = -0x7FFFFFFF - 1;
-const int32 kint32max = 0x7FFFFFFF;
-const int64 kint64min = -0x7FFFFFFFFFFFFFFFLL - 1;
-const int64 kint64max = 0x7FFFFFFFFFFFFFFFLL;
-
-#endif // BASE_BASICTYPES_H_
diff --git a/base/bind.h b/base/bind.h
index 51be10dd7e..770e45706b 100644
--- a/base/bind.h
+++ b/base/bind.h
@@ -47,49 +47,34 @@
namespace base {
-template <typename Functor>
-base::Callback<
- typename internal::BindState<
- typename internal::FunctorTraits<Functor>::RunnableType,
- typename internal::FunctorTraits<Functor>::RunType,
- internal::TypeList<>>::UnboundRunType>
-Bind(Functor functor) {
- // Typedefs for how to store and run the functor.
- typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
- typedef typename internal::FunctorTraits<Functor>::RunType RunType;
-
- typedef internal::BindState<RunnableType, RunType,
- internal::TypeList<>> BindState;
-
- return Callback<typename BindState::UnboundRunType>(
- new BindState(internal::MakeRunnable(functor)));
-}
-
template <typename Functor, typename... Args>
base::Callback<
typename internal::BindState<
typename internal::FunctorTraits<Functor>::RunnableType,
typename internal::FunctorTraits<Functor>::RunType,
- internal::TypeList<
- typename internal::CallbackParamTraits<Args>::StorageType...>>
+ typename internal::CallbackParamTraits<Args>::StorageType...>
::UnboundRunType>
Bind(Functor functor, const Args&... args) {
- // Typedefs for how to store and run the functor.
- typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
- typedef typename internal::FunctorTraits<Functor>::RunType RunType;
+ // Type aliases for how to store and run the functor.
+ using RunnableType = typename internal::FunctorTraits<Functor>::RunnableType;
+ using RunType = typename internal::FunctorTraits<Functor>::RunType;
// Use RunnableType::RunType instead of RunType above because our
- // checks should below for bound references need to know what the actual
+ // checks below for bound references need to know what the actual
// functor is going to interpret the argument as.
- typedef typename RunnableType::RunType BoundRunType;
+ using BoundRunType = typename RunnableType::RunType;
+
+ using BoundArgs =
+ internal::TakeTypeListItem<sizeof...(Args),
+ internal::ExtractArgs<BoundRunType>>;
// 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.
- static_assert(!internal::HasNonConstReferenceParam<BoundRunType>::value,
- "do_not_bind_functions_with_nonconst_ref");
+ static_assert(!internal::HasNonConstReferenceItem<BoundArgs>::value,
+ "do not bind functions with nonconst ref");
const bool is_method = internal::HasIsMethodTag<RunnableType>::value;
@@ -98,16 +83,14 @@ Bind(Functor functor, const Args&... args) {
// methods. We also disallow binding of an array as the method's target
// object.
static_assert(!internal::BindsArrayToFirstArg<is_method, Args...>::value,
- "first_bound_argument_to_method_cannot_be_array");
+ "first bound argument to method cannot be array");
static_assert(
!internal::HasRefCountedParamAsRawPtr<is_method, Args...>::value,
- "a_parameter_is_refcounted_type_and_needs_scoped_refptr");
+ "a parameter is a refcounted type and needs scoped_refptr");
- typedef internal::BindState<
+ using BindState = internal::BindState<
RunnableType, RunType,
- internal::TypeList<
- typename internal::CallbackParamTraits<Args>::StorageType...>>
- BindState;
+ typename internal::CallbackParamTraits<Args>::StorageType...>;
return Callback<typename BindState::UnboundRunType>(
new BindState(internal::MakeRunnable(functor), args...));
diff --git a/base/bind_helpers.h b/base/bind_helpers.h
index 4068d37108..b97558c4b6 100644
--- a/base/bind_helpers.h
+++ b/base/bind_helpers.h
@@ -111,7 +111,7 @@
// scoped_ptr<Foo> 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.
+// // You can use std::move(f) 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
@@ -143,14 +143,18 @@
#ifndef BASE_BIND_HELPERS_H_
#define BASE_BIND_HELPERS_H_
+#include <stddef.h>
+
#include <map>
#include <memory>
+#include <type_traits>
+#include <utility>
#include <vector>
-#include "base/basictypes.h"
#include "base/callback.h"
#include "base/memory/weak_ptr.h"
#include "base/template_util.h"
+#include "build/build_config.h"
namespace base {
namespace internal {
@@ -189,7 +193,7 @@ namespace internal {
// 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).
+// we are probing for; thus it's easiest to just use void().
//
// Now, if TargetFunc exists somewhere in T, then &Base::TargetFunc has an
// ambiguous resolution between BaseMixin and T. This lets us write the
@@ -226,8 +230,8 @@ namespace internal {
// See http://crbug.com/82038.
template <typename T>
class SupportsAddRefAndRelease {
- typedef char Yes[1];
- typedef char No[2];
+ using Yes = char[1];
+ using No = char[2];
struct BaseMixin {
void AddRef();
@@ -246,7 +250,7 @@ class SupportsAddRefAndRelease {
#pragma warning(pop)
#endif
- template <void(BaseMixin::*)(void)> struct Helper {};
+ template <void(BaseMixin::*)()> struct Helper {};
template <typename C>
static No& Check(Helper<&C::AddRef>*);
@@ -280,8 +284,8 @@ struct UnsafeBindtoRefCountedArg<T*>
template <typename T>
class HasIsMethodTag {
- typedef char Yes[1];
- typedef char No[2];
+ using Yes = char[1];
+ using No = char[2];
template <typename U>
static Yes& Check(typename U::IsMethod*);
@@ -363,22 +367,24 @@ class OwnedWrapper {
// 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<>.
+// 1) PassedWrapper supports any type that has a move constructor, however
+// the type will need to be specifically whitelisted in order for it to be
+// bound to a Callback. We guard this explicitly at the call of Passed()
+// to make for clear errors. Things not given to Passed() will be forwarded
+// and stored by value which will not work for general move-only types.
// 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 <typename T>
class PassedWrapper {
public:
- explicit PassedWrapper(T scoper) : is_valid_(true), scoper_(scoper.Pass()) {}
+ explicit PassedWrapper(T&& scoper)
+ : is_valid_(true), scoper_(std::move(scoper)) {}
PassedWrapper(const PassedWrapper& other)
- : is_valid_(other.is_valid_), scoper_(other.scoper_.Pass()) {
- }
+ : is_valid_(other.is_valid_), scoper_(std::move(other.scoper_)) {}
T Pass() const {
CHECK(is_valid_);
is_valid_ = false;
- return scoper_.Pass();
+ return std::move(scoper_);
}
private:
@@ -450,13 +456,13 @@ class PassedWrapper<std::map<K, std::unique_ptr<T, D>, C, A>> {
// Unwrap the stored parameters for the wrappers above.
template <typename T>
struct UnwrapTraits {
- typedef const T& ForwardType;
+ using ForwardType = const T&;
static ForwardType Unwrap(const T& o) { return o; }
};
template <typename T>
struct UnwrapTraits<UnretainedWrapper<T> > {
- typedef T* ForwardType;
+ using ForwardType = T*;
static ForwardType Unwrap(UnretainedWrapper<T> unretained) {
return unretained.get();
}
@@ -464,7 +470,7 @@ struct UnwrapTraits<UnretainedWrapper<T> > {
template <typename T>
struct UnwrapTraits<ConstRefWrapper<T> > {
- typedef const T& ForwardType;
+ using ForwardType = const T&;
static ForwardType Unwrap(ConstRefWrapper<T> const_ref) {
return const_ref.get();
}
@@ -472,19 +478,19 @@ struct UnwrapTraits<ConstRefWrapper<T> > {
template <typename T>
struct UnwrapTraits<scoped_refptr<T> > {
- typedef T* ForwardType;
+ using ForwardType = T*;
static ForwardType Unwrap(const scoped_refptr<T>& o) { return o.get(); }
};
template <typename T>
struct UnwrapTraits<WeakPtr<T> > {
- typedef const WeakPtr<T>& ForwardType;
+ using ForwardType = const WeakPtr<T>&;
static ForwardType Unwrap(const WeakPtr<T>& o) { return o; }
};
template <typename T>
struct UnwrapTraits<OwnedWrapper<T> > {
- typedef T* ForwardType;
+ using ForwardType = T*;
static ForwardType Unwrap(const OwnedWrapper<T>& o) {
return o.get();
}
@@ -492,7 +498,7 @@ struct UnwrapTraits<OwnedWrapper<T> > {
template <typename T>
struct UnwrapTraits<PassedWrapper<T> > {
- typedef T ForwardType;
+ using ForwardType = T;
static T Unwrap(PassedWrapper<T>& o) {
return o.Pass();
}
@@ -575,25 +581,50 @@ struct DropTypeListItemImpl<n, TypeList<T, List...>>
template <typename T, typename... List>
struct DropTypeListItemImpl<0, TypeList<T, List...>> {
- typedef TypeList<T, List...> Type;
+ using Type = TypeList<T, List...>;
};
template <>
struct DropTypeListItemImpl<0, TypeList<>> {
- typedef TypeList<> Type;
+ using Type = TypeList<>;
};
// A type-level function that drops |n| list item from given TypeList.
template <size_t n, typename List>
using DropTypeListItem = typename DropTypeListItemImpl<n, List>::Type;
+// Used for TakeTypeListItem implementation.
+template <size_t n, typename List, typename... Accum>
+struct TakeTypeListItemImpl;
+
+// Do not use enable_if and SFINAE here to avoid MSVC2013 compile failure.
+template <size_t n, typename T, typename... List, typename... Accum>
+struct TakeTypeListItemImpl<n, TypeList<T, List...>, Accum...>
+ : TakeTypeListItemImpl<n - 1, TypeList<List...>, Accum..., T> {};
+
+template <typename T, typename... List, typename... Accum>
+struct TakeTypeListItemImpl<0, TypeList<T, List...>, Accum...> {
+ using Type = TypeList<Accum...>;
+};
+
+template <typename... Accum>
+struct TakeTypeListItemImpl<0, TypeList<>, Accum...> {
+ using Type = TypeList<Accum...>;
+};
+
+// A type-level function that takes first |n| list item from given TypeList.
+// E.g. TakeTypeListItem<3, TypeList<A, B, C, D>> is evaluated to
+// TypeList<A, B, C>.
+template <size_t n, typename List>
+using TakeTypeListItem = typename TakeTypeListItemImpl<n, List>::Type;
+
// Used for ConcatTypeLists implementation.
template <typename List1, typename List2>
struct ConcatTypeListsImpl;
template <typename... Types1, typename... Types2>
struct ConcatTypeListsImpl<TypeList<Types1...>, TypeList<Types2...>> {
- typedef TypeList<Types1..., Types2...> Type;
+ using Type = TypeList<Types1..., Types2...>;
};
// A type-level function that concats two TypeLists.
@@ -606,7 +637,9 @@ struct MakeFunctionTypeImpl;
template <typename R, typename... Args>
struct MakeFunctionTypeImpl<R, TypeList<Args...>> {
- typedef R(Type)(Args...);
+ // MSVC 2013 doesn't support Type Alias of function types.
+ // Revisit this after we update it to newer version.
+ typedef R Type(Args...);
};
// A type-level function that constructs a function type that has |R| as its
@@ -614,6 +647,20 @@ struct MakeFunctionTypeImpl<R, TypeList<Args...>> {
template <typename R, typename ArgList>
using MakeFunctionType = typename MakeFunctionTypeImpl<R, ArgList>::Type;
+// Used for ExtractArgs.
+template <typename Signature>
+struct ExtractArgsImpl;
+
+template <typename R, typename... Args>
+struct ExtractArgsImpl<R(Args...)> {
+ using Type = TypeList<Args...>;
+};
+
+// A type-level function that extracts function arguments into a TypeList.
+// E.g. ExtractArgs<R(A, B, C)> is evaluated to TypeList<A, B, C>.
+template <typename Signature>
+using ExtractArgs = typename ExtractArgsImpl<Signature>::Type;
+
} // namespace internal
template <typename T>
@@ -631,60 +678,25 @@ static inline internal::OwnedWrapper<T> Owned(T* o) {
return internal::OwnedWrapper<T>(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 <typename T>
-static inline internal::PassedWrapper<T> Passed(T scoper) {
- return internal::PassedWrapper<T>(scoper.Pass());
+// We offer 2 syntaxes for calling Passed(). The first takes an rvalue and
+// is best suited for use with the return value of a function or other temporary
+// rvalues. The second takes a pointer to the scoper and is just syntactic sugar
+// to avoid having to write Passed(std::move(scoper)).
+//
+// Both versions of Passed() prevent T from being an lvalue reference. The first
+// via use of enable_if, and the second takes a T* which will not bind to T&.
+template <typename T,
+ typename std::enable_if<internal::IsMoveOnlyType<T>::value &&
+ !std::is_lvalue_reference<T>::value>::type* =
+ nullptr>
+static inline internal::PassedWrapper<T> Passed(T&& scoper) {
+ return internal::PassedWrapper<T>(std::move(scoper));
}
-template <typename T>
+template <typename T,
+ typename std::enable_if<internal::IsMoveOnlyType<T>::value>::type* =
+ nullptr>
static inline internal::PassedWrapper<T> Passed(T* scoper) {
- return internal::PassedWrapper<T>(scoper->Pass());
-}
-
-// Overload base::Passed() for std::unique_ptr<T>.
-template <typename T>
-static inline internal::PassedWrapper<std::unique_ptr<T>>
-Passed(std::unique_ptr<T>* scoper) {
- return internal::PassedWrapper<std::unique_ptr<T>>(std::move(*scoper));
-}
-
-template <typename T>
-static inline internal::PassedWrapper<std::unique_ptr<T>>
-Passed(std::unique_ptr<T> scoper) {
- return internal::PassedWrapper<std::unique_ptr<T>>(std::move(scoper));
-}
-
-// Overload base::Passed() for std::vector<std::unique_ptr<T>>.
-template <typename T, typename D, typename A>
-static inline internal::PassedWrapper<std::vector<std::unique_ptr<T, D>, A>>
-Passed(std::vector<std::unique_ptr<T, D>, A>* scoper) {
- return internal::PassedWrapper<std::vector<std::unique_ptr<T, D>, A>>(
- std::move(*scoper));
-}
-
-template <typename T, typename D, typename A>
-static inline internal::PassedWrapper<std::vector<std::unique_ptr<T, D>, A>>
-Passed(std::vector<std::unique_ptr<T, D>, A> scoper) {
- return internal::PassedWrapper<std::vector<std::unique_ptr<T, D>, A>>(
- std::move(scoper));
-}
-
-// Overload base::Passed() for std::map<K, std::unique_ptr<T>>.
-template <typename K, typename T, typename D, typename C, typename A>
-static inline internal::PassedWrapper<std::map<K, std::unique_ptr<T, D>, C, A>>
-Passed(std::map<K, std::unique_ptr<T, D>, C, A>* scoper) {
- return internal::PassedWrapper<std::map<K, std::unique_ptr<T, D>, C, A>>(
- std::move(*scoper));
-}
-
-template <typename K, typename T, typename D, typename C, typename A>
-static inline internal::PassedWrapper<std::map<K, std::unique_ptr<T, D>, C, A>>
-Passed(std::map<K, std::unique_ptr<T, D>, C, A> scoper) {
- return internal::PassedWrapper<std::map<K, std::unique_ptr<T, D>, C, A>>(
- std::move(scoper));
+ return internal::PassedWrapper<T>(std::move(*scoper));
}
template <typename T>
diff --git a/base/bind_internal.h b/base/bind_internal.h
index e053218862..ac7cd00987 100644
--- a/base/bind_internal.h
+++ b/base/bind_internal.h
@@ -5,6 +5,10 @@
#ifndef BASE_BIND_INTERNAL_H_
#define BASE_BIND_INTERNAL_H_
+#include <stddef.h>
+
+#include <type_traits>
+
#include "base/bind_helpers.h"
#include "base/callback_internal.h"
#include "base/memory/raw_scoped_refptr_mismatch_checker.h"
@@ -37,12 +41,7 @@ namespace internal {
// 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.
+// (Bound)Args -- A set of types that stores the arguments.
//
// Types:
// RunnableAdapter<> -- Wraps the various "function" pointer types into an
@@ -54,7 +53,6 @@ namespace internal {
// signature adapters are applied.
// 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
@@ -69,17 +67,17 @@ namespace internal {
// |Sig| is a non-const reference.
// Implementation note: This non-specialized case handles zero-arity case only.
// Non-zero-arity cases should be handled by the specialization below.
-template <typename Sig>
-struct HasNonConstReferenceParam : false_type {};
+template <typename List>
+struct HasNonConstReferenceItem : false_type {};
// Implementation note: Select true_type if the first parameter is a non-const
// reference. Otherwise, skip the first parameter and check rest of parameters
// recursively.
-template <typename R, typename T, typename... Args>
-struct HasNonConstReferenceParam<R(T, Args...)>
- : SelectType<is_non_const_reference<T>::value,
- true_type,
- HasNonConstReferenceParam<R(Args...)>>::Type {};
+template <typename T, typename... Args>
+struct HasNonConstReferenceItem<TypeList<T, Args...>>
+ : std::conditional<is_non_const_reference<T>::value,
+ true_type,
+ HasNonConstReferenceItem<TypeList<Args...>>>::type {};
// HasRefCountedTypeAsRawPtr selects true_type when any of the |Args| is a raw
// pointer to a RefCounted type.
@@ -93,9 +91,9 @@ struct HasRefCountedTypeAsRawPtr : false_type {};
// parameters recursively.
template <typename T, typename... Args>
struct HasRefCountedTypeAsRawPtr<T, Args...>
- : SelectType<NeedsScopedRefptrButGetsRawPtr<T>::value,
- true_type,
- HasRefCountedTypeAsRawPtr<Args...>>::Type {};
+ : std::conditional<NeedsScopedRefptrButGetsRawPtr<T>::value,
+ true_type,
+ HasRefCountedTypeAsRawPtr<Args...>>::type {};
// BindsArrayToFirstArg selects true_type when |is_method| is true and the first
// item of |Args| is an array type.
@@ -147,7 +145,9 @@ class RunnableAdapter;
template <typename R, typename... Args>
class RunnableAdapter<R(*)(Args...)> {
public:
- typedef R (RunType)(Args...);
+ // MSVC 2013 doesn't support Type Alias of function types.
+ // Revisit this after we update it to newer version.
+ typedef R RunType(Args...);
explicit RunnableAdapter(R(*function)(Args...))
: function_(function) {
@@ -165,8 +165,10 @@ class RunnableAdapter<R(*)(Args...)> {
template <typename R, typename T, typename... Args>
class RunnableAdapter<R(T::*)(Args...)> {
public:
- typedef R (RunType)(T*, Args...);
- typedef true_type IsMethod;
+ // MSVC 2013 doesn't support Type Alias of function types.
+ // Revisit this after we update it to newer version.
+ typedef R RunType(T*, Args...);
+ using IsMethod = true_type;
explicit RunnableAdapter(R(T::*method)(Args...))
: method_(method) {
@@ -184,8 +186,8 @@ class RunnableAdapter<R(T::*)(Args...)> {
template <typename R, typename T, typename... Args>
class RunnableAdapter<R(T::*)(Args...) const> {
public:
- typedef R (RunType)(const T*, Args...);
- typedef true_type IsMethod;
+ using RunType = R(const T*, Args...);
+ using IsMethod = true_type;
explicit RunnableAdapter(R(T::*method)(Args...) const)
: method_(method) {
@@ -209,7 +211,9 @@ struct ForceVoidReturn;
template <typename R, typename... Args>
struct ForceVoidReturn<R(Args...)> {
- typedef void(RunType)(Args...);
+ // MSVC 2013 doesn't support Type Alias of function types.
+ // Revisit this after we update it to newer version.
+ typedef void RunType(Args...);
};
@@ -218,21 +222,21 @@ struct ForceVoidReturn<R(Args...)> {
// See description at top of file.
template <typename T>
struct FunctorTraits {
- typedef RunnableAdapter<T> RunnableType;
- typedef typename RunnableType::RunType RunType;
+ using RunnableType = RunnableAdapter<T>;
+ using RunType = typename RunnableType::RunType;
};
template <typename T>
struct FunctorTraits<IgnoreResultHelper<T>> {
- typedef typename FunctorTraits<T>::RunnableType RunnableType;
- typedef typename ForceVoidReturn<
- typename RunnableType::RunType>::RunType RunType;
+ using RunnableType = typename FunctorTraits<T>::RunnableType;
+ using RunType =
+ typename ForceVoidReturn<typename RunnableType::RunType>::RunType;
};
template <typename T>
struct FunctorTraits<Callback<T>> {
- typedef Callback<T> RunnableType;
- typedef typename Callback<T>::RunType RunType;
+ using RunnableType = Callback<T> ;
+ using RunType = typename Callback<T>::RunType;
};
@@ -311,8 +315,8 @@ struct InvokeHelper<true, ReturnType, Runnable, ArgsType> {
// 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<ReturnType>::value,
- weak_ptrs_can_only_bind_to_methods_without_return_values);
+ static_assert(is_void<ReturnType>::value,
+ "weak_ptrs can only bind to methods without return values");
};
#endif
@@ -358,19 +362,18 @@ struct Invoker<IndexSequence<bound_indices...>,
// 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 <typename Runnable, typename RunType, typename BoundArgList>
+// BoundArgs contains the storage type for all the bound arguments.
+template <typename Runnable, typename RunType, typename... BoundArgs>
struct BindState;
template <typename Runnable,
typename R,
typename... Args,
typename... BoundArgs>
-struct BindState<Runnable, R(Args...), TypeList<BoundArgs...>> final
+struct BindState<Runnable, R(Args...), BoundArgs...> final
: public BindStateBase {
private:
- using StorageType = BindState<Runnable, R(Args...), TypeList<BoundArgs...>>;
+ using StorageType = BindState<Runnable, R(Args...), BoundArgs...>;
using RunnableType = Runnable;
// true_type if Runnable is a method invocation and the first bound argument
diff --git a/base/bind_internal_win.h b/base/bind_internal_win.h
index c3f7477668..2ee12ef214 100644
--- a/base/bind_internal_win.h
+++ b/base/bind_internal_win.h
@@ -8,6 +8,8 @@
#ifndef BASE_BIND_INTERNAL_WIN_H_
#define BASE_BIND_INTERNAL_WIN_H_
+#include "build/build_config.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.
@@ -23,7 +25,9 @@ class RunnableAdapter;
template <typename R, typename... Args>
class RunnableAdapter<R(__stdcall *)(Args...)> {
public:
- typedef R (RunType)(Args...);
+ // MSVC 2013 doesn't support Type Alias of function types.
+ // Revisit this after we update it to newer version.
+ typedef R RunType(Args...);
explicit RunnableAdapter(R(__stdcall *function)(Args...))
: function_(function) {
@@ -41,7 +45,9 @@ class RunnableAdapter<R(__stdcall *)(Args...)> {
template <typename R, typename... Args>
class RunnableAdapter<R(__fastcall *)(Args...)> {
public:
- typedef R (RunType)(Args...);
+ // MSVC 2013 doesn't support Type Alias of function types.
+ // Revisit this after we update it to newer version.
+ typedef R RunType(Args...);
explicit RunnableAdapter(R(__fastcall *function)(Args...))
: function_(function) {
diff --git a/base/bind_unittest.cc b/base/bind_unittest.cc
index 140b2c31e3..25b4a1048f 100644
--- a/base/bind_unittest.cc
+++ b/base/bind_unittest.cc
@@ -4,10 +4,15 @@
#include "base/bind.h"
+#include <memory>
+#include <utility>
+
#include "base/callback.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
+#include "build/build_config.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -24,11 +29,11 @@ class NoRef {
public:
NoRef() {}
- MOCK_METHOD0(VoidMethod0, void(void));
- MOCK_CONST_METHOD0(VoidConstMethod0, void(void));
+ MOCK_METHOD0(VoidMethod0, void());
+ MOCK_CONST_METHOD0(VoidConstMethod0, void());
- MOCK_METHOD0(IntMethod0, int(void));
- MOCK_CONST_METHOD0(IntConstMethod0, int(void));
+ MOCK_METHOD0(IntMethod0, int());
+ MOCK_CONST_METHOD0(IntConstMethod0, int());
private:
// Particularly important in this test to ensure no copies are made.
@@ -39,8 +44,8 @@ class HasRef : public NoRef {
public:
HasRef() {}
- MOCK_CONST_METHOD0(AddRef, void(void));
- MOCK_CONST_METHOD0(Release, bool(void));
+ MOCK_CONST_METHOD0(AddRef, void());
+ MOCK_CONST_METHOD0(Release, bool());
private:
// Particularly important in this test to ensure no copies are made.
@@ -58,8 +63,8 @@ static const int kChildValue = 2;
class Parent {
public:
virtual ~Parent() = default;
- void AddRef(void) const {}
- void Release(void) const {}
+ void AddRef() const {}
+ void Release() const {}
virtual void VirtualSet() { value = kParentValue; }
void NonVirtualSet() { value = kParentValue; }
int value;
@@ -155,7 +160,7 @@ class DeleteCounter {
template <typename T>
T PassThru(T scoper) {
- return scoper.Pass();
+ return scoper;
}
// Some test functions that we can Bind to.
@@ -164,9 +169,10 @@ T PolymorphicIdentity(T t) {
return t;
}
-template <typename T>
-void VoidPolymorphic1(T t) {
-}
+template <typename... Ts>
+struct VoidPolymorphic {
+ static void Run(Ts... t) {}
+};
int Identity(int n) {
return n;
@@ -231,11 +237,11 @@ class BindTest : public ::testing::Test {
virtual ~BindTest() {
}
- static void VoidFunc0(void) {
+ static void VoidFunc0() {
static_func_mock_ptr->VoidMethod0();
}
- static int IntFunc0(void) { return static_func_mock_ptr->IntMethod0(); }
+ static int IntFunc0() { return static_func_mock_ptr->IntMethod0(); }
protected:
StrictMock<NoRef> no_ref_;
@@ -255,7 +261,7 @@ StrictMock<NoRef>* BindTest::static_func_mock_ptr;
// Sanity check that we can instantiate a callback for each arity.
TEST_F(BindTest, ArityTest) {
- Callback<int(void)> c0 = Bind(&Sum, 32, 16, 8, 4, 2, 1);
+ Callback<int()> c0 = Bind(&Sum, 32, 16, 8, 4, 2, 1);
EXPECT_EQ(63, c0.Run());
Callback<int(int)> c1 = Bind(&Sum, 32, 16, 8, 4, 2);
@@ -297,7 +303,7 @@ TEST_F(BindTest, CurryingTest) {
Callback<int(int)> c1 = Bind(c2, 2);
EXPECT_EQ(75, c1.Run(13));
- Callback<int(void)> c0 = Bind(c1, 1);
+ Callback<int()> c0 = Bind(c1, 1);
EXPECT_EQ(63, c0.Run());
}
@@ -338,7 +344,7 @@ TEST_F(BindTest, FunctionTypeSupport) {
EXPECT_CALL(has_ref_, VoidConstMethod0()).Times(2);
Closure normal_cb = Bind(&VoidFunc0);
- Callback<NoRef*(void)> normal_non_refcounted_cb =
+ Callback<NoRef*()> normal_non_refcounted_cb =
Bind(&PolymorphicIdentity<NoRef*>, &no_ref_);
normal_cb.Run();
EXPECT_EQ(&no_ref_, normal_non_refcounted_cb.Run());
@@ -380,11 +386,11 @@ TEST_F(BindTest, ReturnValues) {
.WillOnce(Return(41337))
.WillOnce(Return(51337));
- Callback<int(void)> normal_cb = Bind(&IntFunc0);
- Callback<int(void)> method_cb = Bind(&HasRef::IntMethod0, &has_ref_);
- Callback<int(void)> const_method_nonconst_obj_cb =
+ Callback<int()> normal_cb = Bind(&IntFunc0);
+ Callback<int()> method_cb = Bind(&HasRef::IntMethod0, &has_ref_);
+ Callback<int()> const_method_nonconst_obj_cb =
Bind(&HasRef::IntConstMethod0, &has_ref_);
- Callback<int(void)> const_method_const_obj_cb =
+ Callback<int()> const_method_const_obj_cb =
Bind(&HasRef::IntConstMethod0, const_has_ref_ptr_);
EXPECT_EQ(1337, normal_cb.Run());
EXPECT_EQ(31337, method_cb.Run());
@@ -448,46 +454,46 @@ TEST_F(BindTest, IgnoreResult) {
TEST_F(BindTest, ArgumentBinding) {
int n = 2;
- Callback<int(void)> bind_primitive_cb = Bind(&Identity, n);
+ Callback<int()> bind_primitive_cb = Bind(&Identity, n);
EXPECT_EQ(n, bind_primitive_cb.Run());
- Callback<int*(void)> bind_primitive_pointer_cb =
+ Callback<int*()> bind_primitive_pointer_cb =
Bind(&PolymorphicIdentity<int*>, &n);
EXPECT_EQ(&n, bind_primitive_pointer_cb.Run());
- Callback<int(void)> bind_int_literal_cb = Bind(&Identity, 3);
+ Callback<int()> bind_int_literal_cb = Bind(&Identity, 3);
EXPECT_EQ(3, bind_int_literal_cb.Run());
- Callback<const char*(void)> bind_string_literal_cb =
+ Callback<const char*()> bind_string_literal_cb =
Bind(&CStringIdentity, "hi");
EXPECT_STREQ("hi", bind_string_literal_cb.Run());
- Callback<int(void)> bind_template_function_cb =
+ Callback<int()> bind_template_function_cb =
Bind(&PolymorphicIdentity<int>, 4);
EXPECT_EQ(4, bind_template_function_cb.Run());
NoRefParent p;
p.value = 5;
- Callback<int(void)> bind_object_cb = Bind(&UnwrapNoRefParent, p);
+ Callback<int()> bind_object_cb = Bind(&UnwrapNoRefParent, p);
EXPECT_EQ(5, bind_object_cb.Run());
IncompleteType* incomplete_ptr = reinterpret_cast<IncompleteType*>(123);
- Callback<IncompleteType*(void)> bind_incomplete_ptr_cb =
+ Callback<IncompleteType*()> bind_incomplete_ptr_cb =
Bind(&PolymorphicIdentity<IncompleteType*>, incomplete_ptr);
EXPECT_EQ(incomplete_ptr, bind_incomplete_ptr_cb.Run());
NoRefChild c;
c.value = 6;
- Callback<int(void)> bind_promotes_cb = Bind(&UnwrapNoRefParent, c);
+ Callback<int()> bind_promotes_cb = Bind(&UnwrapNoRefParent, c);
EXPECT_EQ(6, bind_promotes_cb.Run());
c.value = 7;
- Callback<int(void)> bind_pointer_promotes_cb =
+ Callback<int()> bind_pointer_promotes_cb =
Bind(&UnwrapNoRefParentPtr, &c);
EXPECT_EQ(7, bind_pointer_promotes_cb.Run());
c.value = 8;
- Callback<int(void)> bind_const_reference_promotes_cb =
+ Callback<int()> bind_const_reference_promotes_cb =
Bind(&UnwrapNoRefParentConstRef, c);
EXPECT_EQ(8, bind_const_reference_promotes_cb.Run());
}
@@ -501,17 +507,20 @@ TEST_F(BindTest, ArgumentBinding) {
// - Unbound sized array.
// - Unbound array-of-arrays.
TEST_F(BindTest, UnboundArgumentTypeSupport) {
- Callback<void(int)> unbound_value_cb = Bind(&VoidPolymorphic1<int>);
- Callback<void(int*)> unbound_pointer_cb = Bind(&VoidPolymorphic1<int*>);
- Callback<void(int&)> unbound_ref_cb = Bind(&VoidPolymorphic1<int&>);
+ Callback<void(int)> unbound_value_cb = Bind(&VoidPolymorphic<int>::Run);
+ Callback<void(int*)> unbound_pointer_cb = Bind(&VoidPolymorphic<int*>::Run);
+ Callback<void(int&)> unbound_ref_cb = Bind(&VoidPolymorphic<int&>::Run);
Callback<void(const int&)> unbound_const_ref_cb =
- Bind(&VoidPolymorphic1<const int&>);
+ Bind(&VoidPolymorphic<const int&>::Run);
Callback<void(int[])> unbound_unsized_array_cb =
- Bind(&VoidPolymorphic1<int[]>);
+ Bind(&VoidPolymorphic<int[]>::Run);
Callback<void(int[2])> unbound_sized_array_cb =
- Bind(&VoidPolymorphic1<int[2]>);
+ Bind(&VoidPolymorphic<int[2]>::Run);
Callback<void(int[][2])> unbound_array_of_arrays_cb =
- Bind(&VoidPolymorphic1<int[][2]>);
+ Bind(&VoidPolymorphic<int[][2]>::Run);
+
+ Callback<void(int&)> unbound_ref_with_bound_arg =
+ Bind(&VoidPolymorphic<int, int&>::Run, 1);
}
// Function with unbound reference parameter.
@@ -531,12 +540,12 @@ TEST_F(BindTest, ReferenceArgumentBinding) {
int& ref_n = n;
const int& const_ref_n = n;
- Callback<int(void)> ref_copies_cb = Bind(&Identity, ref_n);
+ Callback<int()> ref_copies_cb = Bind(&Identity, ref_n);
EXPECT_EQ(n, ref_copies_cb.Run());
n++;
EXPECT_EQ(n - 1, ref_copies_cb.Run());
- Callback<int(void)> const_ref_copies_cb = Bind(&Identity, const_ref_n);
+ Callback<int()> 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());
@@ -549,10 +558,10 @@ TEST_F(BindTest, ArrayArgumentBinding) {
int array[4] = {1, 1, 1, 1};
const int (*const_array_ptr)[4] = &array;
- Callback<int(void)> array_cb = Bind(&ArrayGet, array, 1);
+ Callback<int()> array_cb = Bind(&ArrayGet, array, 1);
EXPECT_EQ(1, array_cb.Run());
- Callback<int(void)> const_array_cb = Bind(&ArrayGet, *const_array_ptr, 1);
+ Callback<int()> const_array_cb = Bind(&ArrayGet, *const_array_ptr, 1);
EXPECT_EQ(1, const_array_cb.Run());
array[1] = 3;
@@ -590,15 +599,15 @@ TEST_F(BindTest, Unretained) {
EXPECT_CALL(no_ref_, VoidMethod0());
EXPECT_CALL(no_ref_, VoidConstMethod0()).Times(2);
- Callback<void(void)> method_cb =
+ Callback<void()> method_cb =
Bind(&NoRef::VoidMethod0, Unretained(&no_ref_));
method_cb.Run();
- Callback<void(void)> const_method_cb =
+ Callback<void()> const_method_cb =
Bind(&NoRef::VoidConstMethod0, Unretained(&no_ref_));
const_method_cb.Run();
- Callback<void(void)> const_method_const_ptr_cb =
+ Callback<void()> const_method_const_ptr_cb =
Bind(&NoRef::VoidConstMethod0, Unretained(const_no_ref_ptr_));
const_method_const_ptr_cb.Run();
}
@@ -650,8 +659,8 @@ TEST_F(BindTest, WeakPtr) {
TEST_F(BindTest, ConstRef) {
int n = 1;
- Callback<int(void)> copy_cb = Bind(&Identity, n);
- Callback<int(void)> const_ref_cb = Bind(&Identity, ConstRef(n));
+ Callback<int()> copy_cb = Bind(&Identity, n);
+ Callback<int()> const_ref_cb = Bind(&Identity, ConstRef(n));
EXPECT_EQ(n, copy_cb.Run());
EXPECT_EQ(n, const_ref_cb.Run());
n++;
@@ -661,7 +670,7 @@ TEST_F(BindTest, ConstRef) {
int copies = 0;
int assigns = 0;
CopyCounter counter(&copies, &assigns);
- Callback<int(void)> all_const_ref_cb =
+ Callback<int()> all_const_ref_cb =
Bind(&GetCopies, ConstRef(counter));
EXPECT_EQ(0, all_const_ref_cb.Run());
EXPECT_EQ(0, copies);
@@ -678,7 +687,7 @@ TEST_F(BindTest, ScopedRefptr) {
const scoped_refptr<StrictMock<HasRef> > refptr(&has_ref_);
- Callback<int(void)> scoped_refptr_const_ref_cb =
+ Callback<int()> scoped_refptr_const_ref_cb =
Bind(&FunctionWithScopedRefptrFirstParam, base::ConstRef(refptr), 1);
EXPECT_EQ(1, scoped_refptr_const_ref_cb.Run());
}
@@ -690,7 +699,7 @@ TEST_F(BindTest, Owned) {
// If we don't capture, delete happens on Callback destruction/reset.
// return the same value.
- Callback<DeleteCounter*(void)> no_capture_cb =
+ Callback<DeleteCounter*()> no_capture_cb =
Bind(&PolymorphicIdentity<DeleteCounter*>, Owned(counter));
ASSERT_EQ(counter, no_capture_cb.Run());
ASSERT_EQ(counter, no_capture_cb.Run());
@@ -719,7 +728,7 @@ TEST_F(BindTest, ScopedPtr) {
// Tests the Passed() function's support for pointers.
scoped_ptr<DeleteCounter> ptr(new DeleteCounter(&deletes));
- Callback<scoped_ptr<DeleteCounter>(void)> unused_callback =
+ Callback<scoped_ptr<DeleteCounter>()> unused_callback =
Bind(&PassThru<scoped_ptr<DeleteCounter> >, Passed(&ptr));
EXPECT_FALSE(ptr.get());
EXPECT_EQ(0, deletes);
@@ -731,7 +740,7 @@ TEST_F(BindTest, ScopedPtr) {
// Tests the Passed() function's support for rvalues.
deletes = 0;
DeleteCounter* counter = new DeleteCounter(&deletes);
- Callback<scoped_ptr<DeleteCounter>(void)> callback =
+ Callback<scoped_ptr<DeleteCounter>()> callback =
Bind(&PassThru<scoped_ptr<DeleteCounter> >,
Passed(scoped_ptr<DeleteCounter>(counter)));
EXPECT_FALSE(ptr.get());
@@ -754,7 +763,50 @@ TEST_F(BindTest, ScopedPtr) {
Callback<scoped_ptr<DeleteCounter>(scoped_ptr<DeleteCounter>)> cb_unbound =
Bind(&PassThru<scoped_ptr<DeleteCounter> >);
ptr.reset(new DeleteCounter(&deletes));
- cb_unbound.Run(ptr.Pass());
+ cb_unbound.Run(std::move(ptr));
+}
+
+TEST_F(BindTest, UniquePtr) {
+ int deletes = 0;
+
+ // Tests the Passed() function's support for pointers.
+ std::unique_ptr<DeleteCounter> ptr(new DeleteCounter(&deletes));
+ Callback<std::unique_ptr<DeleteCounter>()> unused_callback =
+ Bind(&PassThru<std::unique_ptr<DeleteCounter>>, 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<std::unique_ptr<DeleteCounter>()> callback =
+ Bind(&PassThru<std::unique_ptr<DeleteCounter>>,
+ Passed(std::unique_ptr<DeleteCounter>(counter)));
+ EXPECT_FALSE(ptr.get());
+ EXPECT_EQ(0, deletes);
+
+ // Check that ownership can be transferred back out.
+ std::unique_ptr<DeleteCounter> 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<std::unique_ptr<DeleteCounter>(std::unique_ptr<DeleteCounter>)>
+ cb_unbound = Bind(&PassThru<std::unique_ptr<DeleteCounter>>);
+ ptr.reset(new DeleteCounter(&deletes));
+ cb_unbound.Run(std::move(ptr));
}
// Argument Copy-constructor usage for non-reference parameters.
@@ -768,15 +820,15 @@ TEST_F(BindTest, ArgumentCopies) {
CopyCounter counter(&copies, &assigns);
- Callback<void(void)> copy_cb =
- Bind(&VoidPolymorphic1<CopyCounter>, counter);
+ Callback<void()> copy_cb =
+ Bind(&VoidPolymorphic<CopyCounter>::Run, counter);
EXPECT_GE(1, copies);
EXPECT_EQ(0, assigns);
copies = 0;
assigns = 0;
Callback<void(CopyCounter)> forward_cb =
- Bind(&VoidPolymorphic1<CopyCounter>);
+ Bind(&VoidPolymorphic<CopyCounter>::Run);
forward_cb.Run(counter);
EXPECT_GE(1, copies);
EXPECT_EQ(0, assigns);
@@ -785,7 +837,7 @@ TEST_F(BindTest, ArgumentCopies) {
assigns = 0;
DerivedCopyCounter derived(&copies, &assigns);
Callback<void(CopyCounter)> coerce_cb =
- Bind(&VoidPolymorphic1<CopyCounter>);
+ Bind(&VoidPolymorphic<CopyCounter>::Run);
coerce_cb.Run(CopyCounter(derived));
EXPECT_GE(2, copies);
EXPECT_EQ(0, assigns);
@@ -810,10 +862,10 @@ int __stdcall StdCallFunc(int n) {
// - Can bind a __fastcall function.
// - Can bind a __stdcall function.
TEST_F(BindTest, WindowsCallingConventions) {
- Callback<int(void)> fastcall_cb = Bind(&FastCallFunc, 1);
+ Callback<int()> fastcall_cb = Bind(&FastCallFunc, 1);
EXPECT_EQ(1, fastcall_cb.Run());
- Callback<int(void)> stdcall_cb = Bind(&StdCallFunc, 2);
+ Callback<int()> stdcall_cb = Bind(&StdCallFunc, 2);
EXPECT_EQ(2, stdcall_cb.Run());
}
#endif
diff --git a/base/bits.h b/base/bits.h
index b2209e8ed7..a3a59d1dfa 100644
--- a/base/bits.h
+++ b/base/bits.h
@@ -7,21 +7,23 @@
#ifndef BASE_BITS_H_
#define BASE_BITS_H_
-#include "base/basictypes.h"
+#include <stddef.h>
+#include <stdint.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) {
+inline int Log2Floor(uint32_t n) {
if (n == 0)
return -1;
int log = 0;
- uint32 value = n;
+ uint32_t value = n;
for (int i = 4; i >= 0; --i) {
int shift = (1 << i);
- uint32 x = value >> shift;
+ uint32_t x = value >> shift;
if (x != 0) {
value = x;
log += shift;
@@ -32,7 +34,7 @@ inline int Log2Floor(uint32 n) {
}
// Returns the integer i such as 2^(i-1) < n <= 2^i
-inline int Log2Ceiling(uint32 n) {
+inline int Log2Ceiling(uint32_t n) {
if (n == 0) {
return -1;
} else {
@@ -41,6 +43,12 @@ inline int Log2Ceiling(uint32 n) {
}
}
+// Round up |size| to a multiple of alignment, which must be a power of two.
+inline size_t Align(size_t size, size_t alignment) {
+ DCHECK_EQ(alignment & (alignment - 1), 0u);
+ return (size + alignment - 1) & ~(alignment - 1);
+}
+
} // namespace bits
} // namespace base
diff --git a/base/bits_unittest.cc b/base/bits_unittest.cc
index e913d6ae59..4f5b6ea49e 100644
--- a/base/bits_unittest.cc
+++ b/base/bits_unittest.cc
@@ -5,6 +5,11 @@
// This file contains the unit tests for the bit utilities.
#include "base/bits.h"
+
+#include <stddef.h>
+
+#include <limits>
+
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
@@ -44,5 +49,17 @@ TEST(BitsTest, Log2Ceiling) {
EXPECT_EQ(32, Log2Ceiling(0xffffffffU));
}
+TEST(BitsTest, Align) {
+ const size_t kSizeTMax = std::numeric_limits<size_t>::max();
+ EXPECT_EQ(0ul, Align(0, 4));
+ EXPECT_EQ(4ul, Align(1, 4));
+ EXPECT_EQ(4096ul, Align(1, 4096));
+ EXPECT_EQ(4096ul, Align(4096, 4096));
+ EXPECT_EQ(4096ul, Align(4095, 4096));
+ EXPECT_EQ(8192ul, Align(4097, 4096));
+ EXPECT_EQ(kSizeTMax - 31, Align(kSizeTMax - 62, 32));
+ EXPECT_EQ(kSizeTMax / 2 + 1, Align(1, kSizeTMax / 2 + 1));
+}
+
} // namespace bits
} // namespace base
diff --git a/base/callback.h b/base/callback.h
index 00669dd83d..3bf0008b6d 100644
--- a/base/callback.h
+++ b/base/callback.h
@@ -26,7 +26,7 @@
// 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<void(void)>)
+// A callback with no unbound input parameters (base::Callback<void()>)
// 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.
@@ -48,7 +48,7 @@
// BINDING A BARE FUNCTION
//
// int Return5() { return 5; }
-// base::Callback<int(void)> func_cb = base::Bind(&Return5);
+// base::Callback<int()> func_cb = base::Bind(&Return5);
// LOG(INFO) << func_cb.Run(); // Prints 5.
//
// BINDING A CLASS METHOD
@@ -62,7 +62,7 @@
// void PrintBye() { LOG(INFO) << "bye."; }
// };
// scoped_refptr<Ref> ref = new Ref();
-// base::Callback<void(void)> ref_cb = base::Bind(&Ref::Foo, ref);
+// base::Callback<void()> 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
@@ -104,10 +104,10 @@
// calling.
//
// void MyFunc(int i, const std::string& str) {}
-// base::Callback<void(void)> cb = base::Bind(&MyFunc, 23, "hello world");
+// base::Callback<void()> cb = base::Bind(&MyFunc, 23, "hello world");
// cb.Run();
//
-// A callback with no unbound input parameters (base::Callback<void(void)>)
+// A callback with no unbound input parameters (base::Callback<void()>)
// is called a base::Closure. So we could have also written:
//
// base::Closure cb = base::Bind(&MyFunc, 23, "hello world");
@@ -165,7 +165,7 @@
// that doesn't expect a return value.
//
// int DoSomething(int arg) { cout << arg << endl; }
-// base::Callback<void<int>) cb =
+// base::Callback<void(int)> cb =
// base::Bind(base::IgnoreResult(&DoSomething));
//
//
@@ -175,7 +175,7 @@
//
// 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<void(void)> and base::Closure are the same thing).
+// Closure (base::Callback<void()> and base::Closure are the same thing).
//
// PASSING PARAMETERS OWNED BY THE CALLBACK
//
@@ -354,32 +354,30 @@ namespace base {
//
// If you are thinking of forward declaring Callback in your own header file,
// please include "base/callback_forward.h" instead.
-template <typename Sig>
-class Callback;
namespace internal {
-template <typename Runnable, typename RunType, typename BoundArgsType>
+template <typename Runnable, typename RunType, typename... BoundArgsType>
struct BindState;
} // namespace internal
template <typename R, typename... Args>
class Callback<R(Args...)> : public internal::CallbackBase {
public:
- typedef R(RunType)(Args...);
+ // MSVC 2013 doesn't support Type Alias of function types.
+ // Revisit this after we update it to newer version.
+ typedef R RunType(Args...);
- Callback() : CallbackBase(NULL) { }
+ Callback() : CallbackBase(nullptr) { }
- // Note that this constructor CANNOT be explicit, and that Bind() CANNOT
- // return the exact Callback<> type. See base/bind.h for details.
- template <typename Runnable, typename BindRunType, typename BoundArgsType>
- Callback(internal::BindState<Runnable, BindRunType,
- BoundArgsType>* bind_state)
+ template <typename Runnable, typename BindRunType, typename... BoundArgsType>
+ explicit Callback(
+ internal::BindState<Runnable, BindRunType, BoundArgsType...>* 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<Runnable, BindRunType, BoundArgsType>
+ &internal::BindState<Runnable, BindRunType, BoundArgsType...>
::InvokerType::Run;
polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
}
@@ -397,15 +395,11 @@ class Callback<R(Args...)> : public internal::CallbackBase {
}
private:
- typedef R(*PolymorphicInvoke)(
- internal::BindStateBase*,
- typename internal::CallbackParamTraits<Args>::ForwardType...);
+ using PolymorphicInvoke =
+ R(*)(internal::BindStateBase*,
+ typename internal::CallbackParamTraits<Args>::ForwardType...);
};
-// Syntactic sugar to make Callback<void(void)> easier to declare since it
-// will be used in a lot of APIs with delayed execution.
-typedef Callback<void(void)> Closure;
-
} // namespace base
#endif // BASE_CALLBACK_H_
diff --git a/base/callback_forward.h b/base/callback_forward.h
index 262c306530..a9a263a50e 100644
--- a/base/callback_forward.h
+++ b/base/callback_forward.h
@@ -10,7 +10,9 @@ namespace base {
template <typename Sig>
class Callback;
-typedef Callback<void(void)> Closure;
+// Syntactic sugar to make Callback<void()> easier to declare since it
+// will be used in a lot of APIs with delayed execution.
+using Closure = Callback<void()>;
} // namespace base
diff --git a/base/callback_helpers.h b/base/callback_helpers.h
index 8481e3e71c..860803989f 100644
--- a/base/callback_helpers.h
+++ b/base/callback_helpers.h
@@ -14,9 +14,9 @@
#ifndef BASE_CALLBACK_HELPERS_H_
#define BASE_CALLBACK_HELPERS_H_
-#include "base/basictypes.h"
#include "base/callback.h"
#include "base/compiler_specific.h"
+#include "base/macros.h"
namespace base {
diff --git a/base/callback_internal.h b/base/callback_internal.h
index 3e5ed9de9a..630a5c494b 100644
--- a/base/callback_internal.h
+++ b/base/callback_internal.h
@@ -11,6 +11,7 @@
#include <stddef.h>
#include <map>
#include <memory>
+#include <type_traits>
#include <vector>
#include "base/atomic_ref_count.h"
@@ -20,9 +21,6 @@
#include "base/memory/scoped_ptr.h"
#include "base/template_util.h"
-template <typename T>
-class ScopedVector;
-
namespace base {
namespace internal {
class CallbackBase;
@@ -77,7 +75,7 @@ class BASE_EXPORT CallbackBase {
// 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);
+ using InvokeFuncStorage = void(*)();
// Returns true if this callback equals |other|. |other| may be null.
bool Equals(const CallbackBase& other) const;
@@ -98,8 +96,14 @@ class BASE_EXPORT CallbackBase {
};
// A helper template to determine if given type is non-const move-only-type,
-// i.e. if a value of the given type should be passed via .Pass() in a
-// destructive way.
+// i.e. if a value of the given type should be passed via std::move() in a
+// destructive way. Types are considered to be move-only if they have a
+// sentinel MoveOnlyTypeForCPP03 member: a class typically gets this from using
+// the DISALLOW_COPY_AND_ASSIGN_WITH_MOVE_FOR_BIND macro.
+// It would be easy to generalize this trait to all move-only types... but this
+// confuses template deduction in VS2013 with certain types such as
+// std::unique_ptr.
+// TODO(dcheng): Revisit this when Windows switches to VS2015 by default.
template <typename T> struct IsMoveOnlyType {
template <typename U>
static YesType Test(const typename U::MoveOnlyTypeForCPP03*);
@@ -111,31 +115,10 @@ template <typename T> struct IsMoveOnlyType {
!is_const<T>::value;
};
-// Mark std::unique_ptr<T> and common containers using unique_ptr as MoveOnly
-// type for base::Callback, so it is stored by value and not a const reference
-// inside Callback.
-template<typename T, typename D>
-struct IsMoveOnlyType<std::unique_ptr<T, D>> : public std::true_type {};
-
-template<typename T, typename D, typename A>
-struct IsMoveOnlyType<std::vector<std::unique_ptr<T, D>, A>>
- : public std::true_type {};
-
-template<typename K, typename T, typename D, typename C, typename A>
-struct IsMoveOnlyType<std::map<K, std::unique_ptr<T, D>, C, A>>
- : public std::true_type {};
-
-// Returns |Then| as SelectType::Type if |condition| is true. Otherwise returns
-// |Else|.
-template <bool condition, typename Then, typename Else>
-struct SelectType {
- typedef Then Type;
-};
-
-template <typename Then, typename Else>
-struct SelectType<false, Then, Else> {
- typedef Else Type;
-};
+// Specialization of IsMoveOnlyType so that std::unique_ptr is still considered
+// move-only, even without the sentinel member.
+template <typename T>
+struct IsMoveOnlyType<std::unique_ptr<T>> : std::true_type {};
template <typename>
struct CallbackParamTraitsForMoveOnlyType;
@@ -160,15 +143,15 @@ struct CallbackParamTraitsForNonMoveOnlyType;
// break passing of C-string literals.
template <typename T>
struct CallbackParamTraits
- : SelectType<IsMoveOnlyType<T>::value,
+ : std::conditional<IsMoveOnlyType<T>::value,
CallbackParamTraitsForMoveOnlyType<T>,
- CallbackParamTraitsForNonMoveOnlyType<T> >::Type {
+ CallbackParamTraitsForNonMoveOnlyType<T>>::type {
};
template <typename T>
struct CallbackParamTraitsForNonMoveOnlyType {
- typedef const T& ForwardType;
- typedef T StorageType;
+ using ForwardType = const T&;
+ using StorageType = T;
};
// The Storage should almost be impossible to trigger unless someone manually
@@ -178,8 +161,8 @@ struct CallbackParamTraitsForNonMoveOnlyType {
// The ForwardType should only be used for unbound arguments.
template <typename T>
struct CallbackParamTraitsForNonMoveOnlyType<T&> {
- typedef T& ForwardType;
- typedef T StorageType;
+ using ForwardType = T&;
+ using StorageType = T;
};
// Note that for array types, we implicitly add a const in the conversion. This
@@ -189,15 +172,15 @@ struct CallbackParamTraitsForNonMoveOnlyType<T&> {
// restriction.
template <typename T, size_t n>
struct CallbackParamTraitsForNonMoveOnlyType<T[n]> {
- typedef const T* ForwardType;
- typedef const T* StorageType;
+ using ForwardType = const T*;
+ using StorageType = const T*;
};
// See comment for CallbackParamTraits<T[n]>.
template <typename T>
struct CallbackParamTraitsForNonMoveOnlyType<T[]> {
- typedef const T* ForwardType;
- typedef const T* StorageType;
+ using ForwardType = const T*;
+ using StorageType = const T*;
};
// Parameter traits for movable-but-not-copyable scopers.
@@ -215,8 +198,8 @@ struct CallbackParamTraitsForNonMoveOnlyType<T[]> {
// function or a cast would not be usable with Callback<> or Bind().
template <typename T>
struct CallbackParamTraitsForMoveOnlyType {
- typedef T ForwardType;
- typedef T StorageType;
+ using ForwardType = T;
+ using StorageType = T;
};
// CallbackForward() is a very limited simulation of C++11's std::forward()
@@ -228,7 +211,7 @@ struct CallbackParamTraitsForMoveOnlyType {
// 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
+// is impossible to implement a general std::forward without C++11 due to a lack
// of rvalue references.
//
// In addition to Callback/Bind, this is used by PostTaskAndReplyWithResult to
@@ -236,32 +219,14 @@ struct CallbackParamTraitsForMoveOnlyType {
// parameter to another callback. This is to support Callbacks that return
// the movable-but-not-copyable types whitelisted above.
template <typename T>
-typename enable_if<!IsMoveOnlyType<T>::value, T>::type& CallbackForward(T& t) {
+typename std::enable_if<!IsMoveOnlyType<T>::value, T>::type& CallbackForward(
+ T& t) {
return t;
}
template <typename T>
-typename enable_if<IsMoveOnlyType<T>::value, T>::type CallbackForward(T& t) {
- return t.Pass();
-}
-
-// Overload base::internal::CallbackForward() to forward unique_ptr and common
-// containers with unique_ptr by using std::move instead of default T::Pass()
-// used with scoped_ptr<U>.
-template <typename T, typename D>
-std::unique_ptr<T, D> CallbackForward(std::unique_ptr<T, D>& t) {
- return std::move(t);
-}
-
-template <typename T, typename D, typename A>
-std::vector<std::unique_ptr<T, D>, A>
-CallbackForward(std::vector<std::unique_ptr<T, D>, A>& t) {
- return std::move(t);
-}
-
-template <typename K, typename T, typename D, typename C, typename A>
-std::map<K, std::unique_ptr<T, D>, C, A>
-CallbackForward(std::map<K, std::unique_ptr<T, D>, C, A>& t) {
+typename std::enable_if<IsMoveOnlyType<T>::value, T>::type CallbackForward(
+ T& t) {
return std::move(t);
}
diff --git a/base/callback_list.h b/base/callback_list.h
index aeed5f1e22..7d6a478e8c 100644
--- a/base/callback_list.h
+++ b/base/callback_list.h
@@ -7,11 +7,11 @@
#include <list>
-#include "base/basictypes.h"
#include "base/callback.h"
#include "base/callback_internal.h"
#include "base/compiler_specific.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
// OVERVIEW:
@@ -185,10 +185,10 @@ class CallbackListBase {
} else {
++it;
}
-
- if (updated && !removal_callback_.is_null())
- removal_callback_.Run();
}
+
+ if (updated && !removal_callback_.is_null())
+ removal_callback_.Run();
}
private:
diff --git a/base/callback_list_unittest.cc b/base/callback_list_unittest.cc
index 9adbabb093..010efc54f7 100644
--- a/base/callback_list_unittest.cc
+++ b/base/callback_list_unittest.cc
@@ -4,9 +4,11 @@
#include "base/callback_list.h"
-#include "base/basictypes.h"
+#include <utility>
+
#include "base/bind.h"
#include "base/bind_helpers.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -37,7 +39,7 @@ class Remover {
}
void SetSubscriptionToRemove(
scoped_ptr<CallbackList<void(void)>::Subscription> sub) {
- removal_subscription_ = sub.Pass();
+ removal_subscription_ = std::move(sub);
}
int total() const { return total_; }
@@ -98,6 +100,19 @@ class Summer {
DISALLOW_COPY_AND_ASSIGN(Summer);
};
+class Counter {
+ public:
+ Counter() : value_(0) {}
+
+ void Increment() { value_++; }
+
+ int value() const { return value_; }
+
+ private:
+ int value_;
+ DISALLOW_COPY_AND_ASSIGN(Counter);
+};
+
// Sanity check that we can instantiate a CallbackList for each arity.
TEST(CallbackListTest, ArityTest) {
Summer s;
@@ -234,9 +249,9 @@ TEST(CallbackListTest, RemoveCallbacksDuringIteration) {
cb_reg.Add(Bind(&Listener::IncrementTotal, Unretained(&b)));
// |remover_1| will remove itself.
- remover_1.SetSubscriptionToRemove(remover_1_sub.Pass());
+ remover_1.SetSubscriptionToRemove(std::move(remover_1_sub));
// |remover_2| will remove a.
- remover_2.SetSubscriptionToRemove(a_subscription.Pass());
+ remover_2.SetSubscriptionToRemove(std::move(a_subscription));
cb_reg.Notify();
@@ -287,5 +302,37 @@ TEST(CallbackListTest, EmptyList) {
cb_reg.Notify();
}
+TEST(CallbackList, RemovalCallback) {
+ Counter remove_count;
+ CallbackList<void(void)> cb_reg;
+ cb_reg.set_removal_callback(
+ Bind(&Counter::Increment, Unretained(&remove_count)));
+
+ scoped_ptr<CallbackList<void(void)>::Subscription> subscription =
+ cb_reg.Add(Bind(&DoNothing));
+
+ // Removing a subscription outside of iteration signals the callback.
+ EXPECT_EQ(0, remove_count.value());
+ subscription.reset();
+ EXPECT_EQ(1, remove_count.value());
+
+ // Configure two subscriptions to remove themselves.
+ Remover remover_1, remover_2;
+ scoped_ptr<CallbackList<void(void)>::Subscription> remover_1_sub =
+ cb_reg.Add(Bind(&Remover::IncrementTotalAndRemove,
+ Unretained(&remover_1)));
+ scoped_ptr<CallbackList<void(void)>::Subscription> remover_2_sub =
+ cb_reg.Add(Bind(&Remover::IncrementTotalAndRemove,
+ Unretained(&remover_2)));
+ remover_1.SetSubscriptionToRemove(std::move(remover_1_sub));
+ remover_2.SetSubscriptionToRemove(std::move(remover_2_sub));
+
+ // The callback should be signaled exactly once.
+ EXPECT_EQ(1, remove_count.value());
+ cb_reg.Notify();
+ EXPECT_EQ(2, remove_count.value());
+ EXPECT_TRUE(cb_reg.empty());
+}
+
} // namespace
} // namespace base
diff --git a/base/callback_unittest.cc b/base/callback_unittest.cc
index 2844aa98a2..1f492d4209 100644
--- a/base/callback_unittest.cc
+++ b/base/callback_unittest.cc
@@ -15,7 +15,9 @@ namespace base {
namespace {
struct FakeInvoker {
- typedef void(RunType)(internal::BindStateBase*);
+ // MSVC 2013 doesn't support Type Alias of function types.
+ // Revisit this after we update it to newer version.
+ typedef void RunType(internal::BindStateBase*);
static void Run(internal::BindStateBase*) {
}
};
@@ -23,8 +25,6 @@ struct FakeInvoker {
} // namespace
namespace internal {
-template <typename Runnable, typename RunType, typename BoundArgsType>
-struct BindState;
// White-box testpoints to inject into a Callback<> object for checking
// comparators and emptiness APIs. Use a BindState that is specialized
@@ -32,11 +32,11 @@ struct BindState;
// chance of colliding with another instantiation and breaking the
// one-definition-rule.
template <>
-struct BindState<void(void), void(void), void(FakeInvoker)>
+struct BindState<void(), void(), FakeInvoker>
: public BindStateBase {
public:
BindState() : BindStateBase(&Destroy) {}
- typedef FakeInvoker InvokerType;
+ using InvokerType = FakeInvoker;
private:
~BindState() {}
static void Destroy(BindStateBase* self) {
@@ -45,12 +45,11 @@ struct BindState<void(void), void(void), void(FakeInvoker)>
};
template <>
-struct BindState<void(void), void(void),
- void(FakeInvoker, FakeInvoker)>
+struct BindState<void(), void(), FakeInvoker, FakeInvoker>
: public BindStateBase {
public:
BindState() : BindStateBase(&Destroy) {}
- typedef FakeInvoker InvokerType;
+ using InvokerType = FakeInvoker;
private:
~BindState() {}
static void Destroy(BindStateBase* self) {
@@ -61,11 +60,9 @@ struct BindState<void(void), void(void),
namespace {
-typedef internal::BindState<void(void), void(void), void(FakeInvoker)>
- FakeBindState1;
-typedef internal::BindState<void(void), void(void),
- void(FakeInvoker, FakeInvoker)>
- FakeBindState2;
+using FakeBindState1 = internal::BindState<void(), void(), FakeInvoker>;
+using FakeBindState2 =
+ internal::BindState<void(), void(), FakeInvoker, FakeInvoker>;
class CallbackTest : public ::testing::Test {
public:
@@ -77,15 +74,15 @@ class CallbackTest : public ::testing::Test {
~CallbackTest() override {}
protected:
- Callback<void(void)> callback_a_;
- const Callback<void(void)> callback_b_; // Ensure APIs work with const.
- Callback<void(void)> null_callback_;
+ Callback<void()> callback_a_;
+ const Callback<void()> callback_b_; // Ensure APIs work with const.
+ Callback<void()> 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<void(void)> c0;
+ Callback<void()> c0;
Callback<void(int)> c1;
Callback<void(int,int)> c2;
Callback<void(int,int,int)> c3;
@@ -114,13 +111,13 @@ TEST_F(CallbackTest, Equals) {
EXPECT_FALSE(callback_b_.Equals(callback_a_));
// We should compare based on instance, not type.
- Callback<void(void)> callback_c(new FakeBindState1());
- Callback<void(void)> callback_a2 = callback_a_;
+ Callback<void()> callback_c(new FakeBindState1());
+ Callback<void()> 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<void(void)> empty2;
+ Callback<void()> empty2;
EXPECT_TRUE(null_callback_.Equals(empty2));
}
diff --git a/base/cancelable_callback.h b/base/cancelable_callback.h
index 2b9d260946..47dfb2d5c7 100644
--- a/base/cancelable_callback.h
+++ b/base/cancelable_callback.h
@@ -48,6 +48,7 @@
#include "base/callback_internal.h"
#include "base/compiler_specific.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/weak_ptr.h"
namespace base {
diff --git a/base/command_line.cc b/base/command_line.cc
index c6f3197091..40b65b9e85 100644
--- a/base/command_line.cc
+++ b/base/command_line.cc
@@ -7,9 +7,9 @@
#include <algorithm>
#include <ostream>
-#include "base/basictypes.h"
#include "base/files/file_path.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -75,7 +75,11 @@ void AppendSwitchesAndArguments(CommandLine* command_line,
bool parse_switches = true;
for (size_t i = 1; i < argv.size(); ++i) {
CommandLine::StringType arg = argv[i];
+#if defined(OS_WIN)
TrimWhitespace(arg, TRIM_ALL, &arg);
+#else
+ TrimWhitespaceASCII(arg, TRIM_ALL, &arg);
+#endif
CommandLine::StringType switch_string;
CommandLine::StringType switch_value;
@@ -263,11 +267,15 @@ FilePath CommandLine::GetProgram() const {
}
void CommandLine::SetProgram(const FilePath& program) {
+#if defined(OS_WIN)
TrimWhitespace(program.value(), TRIM_ALL, &argv_[0]);
+#else
+ TrimWhitespaceASCII(program.value(), TRIM_ALL, &argv_[0]);
+#endif
}
bool CommandLine::HasSwitch(const base::StringPiece& switch_string) const {
- DCHECK_EQ(StringToLowerASCII(switch_string.as_string()), switch_string);
+ DCHECK_EQ(ToLowerASCII(switch_string), switch_string);
return switches_by_stringpiece_.find(switch_string) !=
switches_by_stringpiece_.end();
}
@@ -297,7 +305,7 @@ FilePath CommandLine::GetSwitchValuePath(
CommandLine::StringType CommandLine::GetSwitchValueNative(
const base::StringPiece& switch_string) const {
- DCHECK_EQ(StringToLowerASCII(switch_string.as_string()), switch_string);
+ DCHECK_EQ(ToLowerASCII(switch_string), switch_string);
auto result = switches_by_stringpiece_.find(switch_string);
return result == switches_by_stringpiece_.end() ? StringType()
: *(result->second);
@@ -315,7 +323,7 @@ void CommandLine::AppendSwitchPath(const std::string& switch_string,
void CommandLine::AppendSwitchNative(const std::string& switch_string,
const CommandLine::StringType& value) {
#if defined(OS_WIN)
- const std::string switch_key = StringToLowerASCII(switch_string);
+ const std::string switch_key = ToLowerASCII(switch_string);
StringType combined_switch_string(ASCIIToUTF16(switch_key));
#elif defined(OS_POSIX)
const std::string& switch_key = switch_string;
@@ -394,8 +402,9 @@ void CommandLine::PrependWrapper(const CommandLine::StringType& wrapper) {
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;
- SplitString(wrapper, FILE_PATH_LITERAL(' '), &wrapper_argv);
+ StringVector wrapper_argv = SplitString(
+ wrapper, FilePath::StringType(1, ' '), base::TRIM_WHITESPACE,
+ base::SPLIT_WANT_ALL);
// 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();
diff --git a/base/command_line_unittest.cc b/base/command_line_unittest.cc
index ac8a39567c..967ce1c5d5 100644
--- a/base/command_line_unittest.cc
+++ b/base/command_line_unittest.cc
@@ -5,11 +5,12 @@
#include <string>
#include <vector>
-#include "base/basictypes.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
diff --git a/base/compiler_specific.h b/base/compiler_specific.h
index 63297dcaf0..339e9b74e9 100644
--- a/base/compiler_specific.h
+++ b/base/compiler_specific.h
@@ -9,6 +9,9 @@
#if defined(COMPILER_MSVC)
+// For _Printf_format_string_.
+#include <sal.h>
+
// Macros for suppressing and disabling warnings on MSVC.
//
// Warning numbers are enumerated at:
@@ -57,6 +60,7 @@
#else // Not MSVC
+#define _Printf_format_string_
#define MSVC_SUPPRESS_WARNING(n)
#define MSVC_PUSH_DISABLE_WARNING(n)
#define MSVC_PUSH_WARNING_LEVEL(n)
@@ -68,28 +72,6 @@
#endif // COMPILER_MSVC
-// The C++ standard requires that static const members have an out-of-class
-// definition (in a single compilation unit), but MSVC chokes on this (when
-// language extensions, which are required, are enabled). (You're only likely to
-// notice the need for a definition if you take the address of the member or,
-// more commonly, pass it to a function that takes it as a reference argument --
-// probably an STL function.) This macro makes MSVC do the right thing. See
-// http://msdn.microsoft.com/en-us/library/34h23df8(v=vs.100).aspx for more
-// information. Use like:
-//
-// In .h file:
-// struct Foo {
-// static const int kBar = 5;
-// };
-//
-// In .cc file:
-// STATIC_CONST_MEMBER_DEFINITION const int Foo::kBar;
-#if defined(COMPILER_MSVC)
-#define STATIC_CONST_MEMBER_DEFINITION __declspec(selectany)
-#else
-#define STATIC_CONST_MEMBER_DEFINITION
-#endif
-
// 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.)
@@ -101,7 +83,7 @@
// Annotate a typedef or function indicating it's ok if it's not used.
// Use like:
// typedef Foo Bar ALLOW_UNUSED_TYPE;
-#if defined(COMPILER_GCC)
+#if defined(COMPILER_GCC) || defined(__clang__)
#define ALLOW_UNUSED_TYPE __attribute__((unused))
#else
#define ALLOW_UNUSED_TYPE
@@ -130,7 +112,7 @@
// Return the byte alignment of the given type (available at compile time).
// Use like:
-// ALIGNOF(int32) // this would be 4
+// ALIGNOF(int32_t) // this would be 4
#if defined(COMPILER_MSVC)
#define ALIGNOF(type) __alignof(type)
#elif defined(COMPILER_GCC)
@@ -140,8 +122,9 @@
// 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 <base/basictypes.h>.
-#if defined(COMPILER_GCC)
+// To explicitly ignore a result, see |ignore_result()| in base/macros.h.
+#undef WARN_UNUSED_RESULT
+#if defined(COMPILER_GCC) || defined(__clang__)
#define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
#else
#define WARN_UNUSED_RESULT
diff --git a/base/containers/adapters.h b/base/containers/adapters.h
index cc151fc246..fa671b46d9 100644
--- a/base/containers/adapters.h
+++ b/base/containers/adapters.h
@@ -5,6 +5,10 @@
#ifndef BASE_CONTAINERS_ADAPTERS_H_
#define BASE_CONTAINERS_ADAPTERS_H_
+#include <stddef.h>
+
+#include <iterator>
+
#include "base/macros.h"
namespace base {
@@ -15,11 +19,13 @@ namespace internal {
template <typename T>
class ReversedAdapter {
public:
- typedef decltype(static_cast<T*>(nullptr)->rbegin()) Iterator;
+ using Iterator = decltype(static_cast<T*>(nullptr)->rbegin());
explicit ReversedAdapter(T& t) : t_(t) {}
ReversedAdapter(const ReversedAdapter& ra) : t_(ra.t_) {}
+ // TODO(mdempsky): Once we can use C++14 library features, use std::rbegin
+ // and std::rend instead, so we can remove the specialization below.
Iterator begin() const { return t_.rbegin(); }
Iterator end() const { return t_.rend(); }
@@ -29,6 +35,23 @@ class ReversedAdapter {
DISALLOW_ASSIGN(ReversedAdapter);
};
+template <typename T, size_t N>
+class ReversedAdapter<T[N]> {
+ public:
+ using Iterator = std::reverse_iterator<T*>;
+
+ explicit ReversedAdapter(T (&t)[N]) : t_(t) {}
+ ReversedAdapter(const ReversedAdapter& ra) : t_(ra.t_) {}
+
+ Iterator begin() const { return Iterator(&t_[N]); }
+ Iterator end() const { return Iterator(&t_[0]); }
+
+ private:
+ T (&t_)[N];
+
+ DISALLOW_ASSIGN(ReversedAdapter);
+};
+
} // namespace internal
// Reversed returns a container adapter usable in a range-based "for" statement
diff --git a/base/containers/hash_tables.h b/base/containers/hash_tables.h
index 5ce9161917..c421dddf3e 100644
--- a/base/containers/hash_tables.h
+++ b/base/containers/hash_tables.h
@@ -21,9 +21,11 @@
#ifndef BASE_CONTAINERS_HASH_TABLES_H_
#define BASE_CONTAINERS_HASH_TABLES_H_
+#include <stddef.h>
+#include <stdint.h>
+
#include <utility>
-#include "base/basictypes.h"
#include "base/strings/string16.h"
#include "build/build_config.h"
@@ -196,19 +198,19 @@ using hash_set = BASE_HASH_IMPL_NAMESPACE::hash_set<Key, Hash, Pred, Alloc>;
// 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;
+inline std::size_t HashInts32(uint32_t value1, uint32_t value2) {
+ uint64_t value1_64 = value1;
+ uint64_t hash64 = (value1_64 << 32) | value2;
- if (sizeof(std::size_t) >= sizeof(uint64))
+ if (sizeof(std::size_t) >= sizeof(uint64_t))
return static_cast<std::size_t>(hash64);
- uint64 odd_random = 481046412LL << 32 | 1025306955LL;
- uint32 shift_random = 10121U << 16;
+ uint64_t odd_random = 481046412LL << 32 | 1025306955LL;
+ uint32_t shift_random = 10121U << 16;
hash64 = hash64 * odd_random + shift_random;
std::size_t high_bits = static_cast<std::size_t>(
- hash64 >> (8 * (sizeof(uint64) - sizeof(std::size_t))));
+ hash64 >> (8 * (sizeof(uint64_t) - sizeof(std::size_t))));
return high_bits;
}
@@ -217,87 +219,46 @@ inline std::size_t HashInts32(uint32 value1, uint32 value2) {
// 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;
+inline std::size_t HashInts64(uint64_t value1, uint64_t value2) {
+ uint32_t short_random1 = 842304669U;
+ uint32_t short_random2 = 619063811U;
+ uint32_t short_random3 = 937041849U;
+ uint32_t short_random4 = 3309708029U;
- uint32 value1a = static_cast<uint32>(value1 & 0xffffffff);
- uint32 value1b = static_cast<uint32>((value1 >> 32) & 0xffffffff);
- uint32 value2a = static_cast<uint32>(value2 & 0xffffffff);
- uint32 value2b = static_cast<uint32>((value2 >> 32) & 0xffffffff);
+ uint32_t value1a = static_cast<uint32_t>(value1 & 0xffffffff);
+ uint32_t value1b = static_cast<uint32_t>((value1 >> 32) & 0xffffffff);
+ uint32_t value2a = static_cast<uint32_t>(value2 & 0xffffffff);
+ uint32_t value2b = static_cast<uint32_t>((value2 >> 32) & 0xffffffff);
- uint64 product1 = static_cast<uint64>(value1a) * short_random1;
- uint64 product2 = static_cast<uint64>(value1b) * short_random2;
- uint64 product3 = static_cast<uint64>(value2a) * short_random3;
- uint64 product4 = static_cast<uint64>(value2b) * short_random4;
+ uint64_t product1 = static_cast<uint64_t>(value1a) * short_random1;
+ uint64_t product2 = static_cast<uint64_t>(value1b) * short_random2;
+ uint64_t product3 = static_cast<uint64_t>(value2a) * short_random3;
+ uint64_t product4 = static_cast<uint64_t>(value2b) * short_random4;
- uint64 hash64 = product1 + product2 + product3 + product4;
+ uint64_t hash64 = product1 + product2 + product3 + product4;
- if (sizeof(std::size_t) >= sizeof(uint64))
+ if (sizeof(std::size_t) >= sizeof(uint64_t))
return static_cast<std::size_t>(hash64);
- uint64 odd_random = 1578233944LL << 32 | 194370989LL;
- uint32 shift_random = 20591U << 16;
+ uint64_t odd_random = 1578233944LL << 32 | 194370989LL;
+ uint32_t shift_random = 20591U << 16;
hash64 = hash64 * odd_random + shift_random;
std::size_t high_bits = static_cast<std::size_t>(
- hash64 >> (8 * (sizeof(uint64) - sizeof(std::size_t))));
+ hash64 >> (8 * (sizeof(uint64_t) - 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); \
-}
+template<typename T1, typename T2>
+inline std::size_t HashPair(T1 value1, T2 value2) {
+ // This condition is expected to be compile-time evaluated and optimised away
+ // in release builds.
+ if (sizeof(T1) > sizeof(uint32_t) || (sizeof(T2) > sizeof(uint32_t)))
+ return HashInts64(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); \
+ return HashInts32(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 {
diff --git a/base/containers/mru_cache.h b/base/containers/mru_cache.h
index ed1ad251a2..272a773c88 100644
--- a/base/containers/mru_cache.h
+++ b/base/containers/mru_cache.h
@@ -16,13 +16,16 @@
#ifndef BASE_CONTAINERS_MRU_CACHE_H_
#define BASE_CONTAINERS_MRU_CACHE_H_
+#include <stddef.h>
+
+#include <algorithm>
#include <list>
#include <map>
#include <utility>
-#include "base/basictypes.h"
#include "base/containers/hash_tables.h"
#include "base/logging.h"
+#include "base/macros.h"
namespace base {
@@ -137,6 +140,14 @@ class MRUCacheBase {
return index_iter->second;
}
+ // Exchanges the contents of |this| by the contents of the |other|.
+ void Swap(MRUCacheBase& other) {
+ ordering_.swap(other.ordering_);
+ index_.swap(other.index_);
+ std::swap(deletor_, other.deletor_);
+ std::swap(max_size_, other.max_size_);
+ }
+
// 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) {
diff --git a/base/containers/scoped_ptr_hash_map.h b/base/containers/scoped_ptr_hash_map.h
index 8fe550e731..189c3149f3 100644
--- a/base/containers/scoped_ptr_hash_map.h
+++ b/base/containers/scoped_ptr_hash_map.h
@@ -5,12 +5,14 @@
#ifndef BASE_CONTAINERS_SCOPED_PTR_HASH_MAP_H_
#define BASE_CONTAINERS_SCOPED_PTR_HASH_MAP_H_
+#include <stddef.h>
+
#include <algorithm>
#include <utility>
-#include "base/basictypes.h"
#include "base/containers/hash_tables.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/stl_util.h"
@@ -57,7 +59,7 @@ class ScopedPtrHashMap {
std::pair<iterator, bool> result =
data_.insert(std::make_pair(key, data.get()));
if (result.second)
- ignore_result(data.release());
+ ::ignore_result(data.release());
return result;
}
@@ -82,7 +84,7 @@ class ScopedPtrHashMap {
ScopedPtr ret(it->second);
it->second = NULL;
- return ret.Pass();
+ return ret;
}
ScopedPtr take(const Key& k) {
@@ -100,7 +102,7 @@ class ScopedPtrHashMap {
ScopedPtr ret(it->second);
data_.erase(it);
- return ret.Pass();
+ return ret;
}
ScopedPtr take_and_erase(const Key& k) {
diff --git a/base/containers/scoped_ptr_map.h b/base/containers/scoped_ptr_map.h
deleted file mode 100644
index 19a115316e..0000000000
--- a/base/containers/scoped_ptr_map.h
+++ /dev/null
@@ -1,137 +0,0 @@
-// Copyright 2015 The Chromium Authors. All 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_SCOPED_PTR_MAP_H_
-#define BASE_CONTAINERS_SCOPED_PTR_MAP_H_
-
-#include <map>
-#include <utility>
-
-#include "base/basictypes.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/move.h"
-#include "base/stl_util.h"
-
-// ScopedPtrMap provides a std::map that supports scoped_ptr values. It ensures
-// that the map's values are properly deleted when removed from the map, or when
-// the map is destroyed.
-//
-// |ScopedPtr| must be a type scoped_ptr<T>. This is for compatibility with
-// std::map in C++11.
-template <class Key, class ScopedPtr>
-class ScopedPtrMap {
- MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(ScopedPtrMap)
-
- using Container = std::map<Key, typename ScopedPtr::element_type*>;
-
- public:
- using allocator_type = typename Container::allocator_type;
- using size_type = typename Container::size_type;
- using difference_type = typename Container::difference_type;
- using reference = typename Container::reference;
- using const_reference = typename Container::const_reference;
- using key_type = typename Container::key_type;
- using const_iterator = typename Container::const_iterator;
- using const_reverse_iterator = typename Container::const_reverse_iterator;
-
- ScopedPtrMap() {}
- ~ScopedPtrMap() { clear(); }
- ScopedPtrMap(ScopedPtrMap<Key, ScopedPtr>&& other) { swap(other); }
-
- ScopedPtrMap& operator=(ScopedPtrMap<Key, ScopedPtr>&& rhs) {
- swap(rhs);
- return *this;
- }
-
- const_iterator find(const Key& k) const { return data_.find(k); }
- size_type count(const Key& k) const { return data_.count(k); }
-
- bool empty() const { return data_.empty(); }
- size_t size() const { return data_.size(); }
-
- const_reverse_iterator rbegin() const { return data_.rbegin(); }
- const_reverse_iterator rend() const { return data_.rend(); }
-
- const_iterator begin() const { return data_.begin(); }
- const_iterator end() const { return data_.end(); }
-
- void swap(ScopedPtrMap<Key, ScopedPtr>& other) { data_.swap(other.data_); }
-
- void clear() { STLDeleteValues(&data_); }
-
- // Inserts |val| into the map, associated with |key|.
- std::pair<const_iterator, bool> insert(const Key& key, ScopedPtr val) {
- auto result = data_.insert(std::make_pair(key, val.get()));
- if (result.second)
- ignore_result(val.release());
- return result;
- }
-
- // Inserts |val| into the map, associated with |key|. Overwrites any existing
- // element at |key|.
- void set(const Key& key, ScopedPtr val) {
- typename ScopedPtr::element_type*& val_ref = data_[key];
- delete val_ref;
- val_ref = val.release();
- }
-
- void erase(const_iterator position) {
- DCHECK(position != end());
- delete position->second;
- // Key-based lookup (cannot use const_iterator overload in C++03 library).
- data_.erase(position->first);
- }
-
- size_type erase(const Key& k) {
- typename Container::iterator it = data_.find(k);
- if (it == end())
- return 0;
-
- delete it->second;
- data_.erase(it);
- return 1;
- }
-
- void erase(const_iterator first, const_iterator last) {
- STLDeleteContainerPairSecondPointers(first, last);
- // Need non-const iterators as required by the C++03 library.
- data_.erase(ConstIteratorToIterator(first), ConstIteratorToIterator(last));
- }
-
- // Like |erase()|, but returns the element instead of deleting it.
- ScopedPtr take_and_erase(const_iterator position) {
- DCHECK(position != end());
- if (position == end())
- return ScopedPtr();
-
- ScopedPtr ret(position->second);
- // Key-based lookup (cannot use const_iterator overload in C++03 library).
- data_.erase(position->first);
- return ret.Pass();
- }
-
- // Like |erase()|, but returns the element instead of deleting it.
- ScopedPtr take_and_erase(const Key& k) {
- typename Container::iterator it = data_.find(k);
- if (it == end())
- return ScopedPtr();
-
- ScopedPtr ret(it->second);
- data_.erase(it);
- return ret.Pass();
- }
-
- private:
- Container data_;
-
- typename Container::iterator ConstIteratorToIterator(const_iterator it) {
- // This is the only way to convert a const iterator to a non-const iterator
- // in C++03 (get the key and do the lookup again).
- if (it == data_.end())
- return data_.end();
- return data_.find(it->first);
- };
-};
-
-#endif // BASE_CONTAINERS_SCOPED_PTR_MAP_H_
diff --git a/base/containers/small_map.h b/base/containers/small_map.h
index df3d22ae9a..427736ca8c 100644
--- a/base/containers/small_map.h
+++ b/base/containers/small_map.h
@@ -5,11 +5,12 @@
#ifndef BASE_CONTAINERS_SMALL_MAP_H_
#define BASE_CONTAINERS_SMALL_MAP_H_
+#include <stddef.h>
+
#include <map>
#include <string>
#include <utility>
-#include "base/basictypes.h"
#include "base/containers/hash_tables.h"
#include "base/logging.h"
#include "base/memory/manual_constructor.h"
@@ -187,7 +188,7 @@ class SmallMap {
// 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);
+ static_assert(kArraySize > 0, "default initial size should be positive");
public:
typedef typename NormalMap::key_type key_type;
diff --git a/base/containers/stack_container.h b/base/containers/stack_container.h
index 54090d3cd9..9e0efc13b4 100644
--- a/base/containers/stack_container.h
+++ b/base/containers/stack_container.h
@@ -5,10 +5,12 @@
#ifndef BASE_CONTAINERS_STACK_CONTAINER_H_
#define BASE_CONTAINERS_STACK_CONTAINER_H_
+#include <stddef.h>
+
#include <string>
#include <vector>
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/memory/aligned_memory.h"
#include "base/strings/string16.h"
#include "build/build_config.h"
@@ -57,7 +59,7 @@ class StackAllocator : public std::allocator<T> {
// buffer of the right size instead.
base::AlignedMemory<sizeof(T[stack_capacity]), ALIGNOF(T)> stack_buffer_;
#if defined(__GNUC__) && !defined(ARCH_CPU_X86_FAMILY)
- COMPILE_ASSERT(ALIGNOF(T) <= 16, crbug_115612);
+ static_assert(ALIGNOF(T) <= 16, "http://crbug.com/115612");
#endif
// Set when the stack buffer is used for an allocation. We do not track
diff --git a/base/cpu.cc b/base/cpu.cc
index ef3309dad1..7135445664 100644
--- a/base/cpu.cc
+++ b/base/cpu.cc
@@ -4,12 +4,15 @@
#include "base/cpu.h"
+#include <limits.h>
+#include <stddef.h>
+#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/strings/string_piece.h"
#include "build/build_config.h"
@@ -43,7 +46,7 @@ CPU::CPU()
has_sse41_(false),
has_sse42_(false),
has_avx_(false),
- has_avx_hardware_(false),
+ has_avx2_(false),
has_aesni_(false),
has_non_stop_time_stamp_counter_(false),
has_broken_neon_(false),
@@ -72,7 +75,7 @@ void __cpuid(int cpu_info[4], int info_type) {
void __cpuid(int cpu_info[4], int info_type) {
__asm__ volatile (
- "cpuid \n\t"
+ "cpuid\n"
: "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
: "a"(info_type)
);
@@ -82,11 +85,12 @@ void __cpuid(int cpu_info[4], int info_type) {
// _xgetbv returns the value of an Intel Extended Control Register (XCR).
// Currently only XCR0 is defined by Intel so |xcr| should always be zero.
-uint64 _xgetbv(uint32 xcr) {
- uint32 eax, edx;
+uint64_t _xgetbv(uint32_t xcr) {
+ uint32_t eax, edx;
- __asm__ volatile ("xgetbv" : "=a" (eax), "=d" (edx) : "c" (xcr));
- return (static_cast<uint64>(edx) << 32) | eax;
+ __asm__ volatile (
+ "xgetbv" : "=a"(eax), "=d"(edx) : "c"(xcr));
+ return (static_cast<uint64_t>(edx) << 32) | eax;
}
#endif // !_MSC_VER
@@ -110,7 +114,7 @@ class LazyCpuInfoValue {
revision = 0;
const struct {
const char key[17];
- unsigned *result;
+ unsigned int* result;
} kUnsignedValues[] = {
{"CPU implementer", &implementer},
{"CPU architecture", &architecture},
@@ -156,7 +160,7 @@ class LazyCpuInfoValue {
// The string may have leading "0x" or not, so we use strtoul to
// handle that.
- char *endptr;
+ char* endptr;
std::string value(value_sp.as_string());
unsigned long int result = strtoul(value.c_str(), &endptr, 0);
if (*endptr == 0 && result <= UINT_MAX) {
@@ -211,7 +215,11 @@ void CPU::Initialize() {
// Interpret CPU feature information.
if (num_ids > 0) {
+ int cpu_info7[4] = {0};
__cpuid(cpu_info, 1);
+ if (num_ids >= 7) {
+ __cpuid(cpu_info7, 7);
+ }
signature_ = cpu_info[0];
stepping_ = cpu_info[0] & 0xf;
model_ = ((cpu_info[0] >> 4) & 0xf) + ((cpu_info[0] >> 12) & 0xf0);
@@ -226,8 +234,6 @@ void CPU::Initialize() {
has_ssse3_ = (cpu_info[2] & 0x00000200) != 0;
has_sse41_ = (cpu_info[2] & 0x00080000) != 0;
has_sse42_ = (cpu_info[2] & 0x00100000) != 0;
- has_avx_hardware_ =
- (cpu_info[2] & 0x10000000) != 0;
// AVX instructions will generate an illegal instruction exception unless
// a) they are supported by the CPU,
// b) XSAVE is supported by the CPU and
@@ -239,11 +245,12 @@ void CPU::Initialize() {
// Because of that, we also test the XSAVE bit because its description in
// the CPUID documentation suggests that it signals xgetbv support.
has_avx_ =
- has_avx_hardware_ &&
+ (cpu_info[2] & 0x10000000) != 0 &&
(cpu_info[2] & 0x04000000) != 0 /* XSAVE */ &&
(cpu_info[2] & 0x08000000) != 0 /* OSXSAVE */ &&
(_xgetbv(0) & 6) == 6 /* XSAVE enabled by kernel */;
has_aesni_ = (cpu_info[2] & 0x02000000) != 0;
+ has_avx2_ = has_avx_ && (cpu_info7[1] & 0x00000020) != 0;
}
// Get the brand string of the cpu.
@@ -275,6 +282,7 @@ void CPU::Initialize() {
}
CPU::IntelMicroArchitecture CPU::GetIntelMicroArchitecture() const {
+ if (has_avx2()) return AVX2;
if (has_avx()) return AVX;
if (has_sse42()) return SSE42;
if (has_sse41()) return SSE41;
diff --git a/base/cpu.h b/base/cpu.h
index 0c809f00c8..8c3c06c044 100644
--- a/base/cpu.h
+++ b/base/cpu.h
@@ -26,6 +26,7 @@ class BASE_EXPORT CPU {
SSE41,
SSE42,
AVX,
+ AVX2,
MAX_INTEL_MICRO_ARCHITECTURE
};
@@ -46,12 +47,7 @@ class BASE_EXPORT CPU {
bool has_sse41() const { return has_sse41_; }
bool has_sse42() const { return has_sse42_; }
bool has_avx() const { return has_avx_; }
- // has_avx_hardware returns true when AVX is present in the CPU. This might
- // differ from the value of |has_avx()| because |has_avx()| also tests for
- // operating system support needed to actually call AVX instuctions.
- // Note: you should never need to call this function. It was added in order
- // to workaround a bug in NSS but |has_avx()| is what you want.
- bool has_avx_hardware() const { return has_avx_hardware_; }
+ bool has_avx2() const { return has_avx2_; }
bool has_aesni() const { return has_aesni_; }
bool has_non_stop_time_stamp_counter() const {
return has_non_stop_time_stamp_counter_;
@@ -83,7 +79,7 @@ class BASE_EXPORT CPU {
bool has_sse41_;
bool has_sse42_;
bool has_avx_;
- bool has_avx_hardware_;
+ bool has_avx2_;
bool has_aesni_;
bool has_non_stop_time_stamp_counter_;
bool has_broken_neon_;
diff --git a/base/cpu_unittest.cc b/base/cpu_unittest.cc
index 18bf959a55..ec14620f98 100644
--- a/base/cpu_unittest.cc
+++ b/base/cpu_unittest.cc
@@ -7,6 +7,11 @@
#include "testing/gtest/include/gtest/gtest.h"
+#if _MSC_VER >= 1700
+// C4752: found Intel(R) Advanced Vector Extensions; consider using /arch:AVX.
+#pragma warning(disable: 4752)
+#endif
+
// 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
@@ -17,77 +22,96 @@ TEST(CPU, RunExtendedInstructions) {
// 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());
+ ASSERT_TRUE(cpu.has_sse());
+ ASSERT_TRUE(cpu.has_sse2());
+// GCC and clang instruction test.
+#if defined(COMPILER_GCC)
// Execute an MMX instruction.
- __asm emms;
+ __asm__ __volatile__("emms\n" : : : "mm0");
- if (cpu.has_sse()) {
- // Execute an SSE instruction.
- __asm xorps xmm0, xmm0;
- }
+ // Execute an SSE instruction.
+ __asm__ __volatile__("xorps %%xmm0, %%xmm0\n" : : : "xmm0");
- if (cpu.has_sse2()) {
- // Execute an SSE 2 instruction.
- __asm psrldq xmm0, 0;
- }
+ // Execute an SSE 2 instruction.
+ __asm__ __volatile__("psrldq $0, %%xmm0\n" : : : "xmm0");
if (cpu.has_sse3()) {
// Execute an SSE 3 instruction.
- __asm addsubpd xmm0, xmm0;
+ __asm__ __volatile__("addsubpd %%xmm0, %%xmm0\n" : : : "xmm0");
}
if (cpu.has_ssse3()) {
// Execute a Supplimental SSE 3 instruction.
- __asm psignb xmm0, xmm0;
+ __asm__ __volatile__("psignb %%xmm0, %%xmm0\n" : : : "xmm0");
}
if (cpu.has_sse41()) {
// Execute an SSE 4.1 instruction.
- __asm pmuldq xmm0, xmm0;
+ __asm__ __volatile__("pmuldq %%xmm0, %%xmm0\n" : : : "xmm0");
}
if (cpu.has_sse42()) {
// Execute an SSE 4.2 instruction.
- __asm crc32 eax, eax;
+ __asm__ __volatile__("crc32 %%eax, %%eax\n" : : : "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_avx()) {
+ // Execute an AVX instruction.
+ __asm__ __volatile__("vzeroupper\n" : : : "xmm0");
}
- if (cpu.has_sse2()) {
- // Execute an SSE 2 instruction.
- __asm__ __volatile__("psrldq $0, %%xmm0\n" : : : "xmm0");
+ if (cpu.has_avx2()) {
+ // Execute an AVX 2 instruction.
+ __asm__ __volatile__("vpunpcklbw %%ymm0, %%ymm0, %%ymm0\n" : : : "xmm0");
}
+// Visual C 32 bit and ClangCL 32/64 bit test.
+#elif defined(COMPILER_MSVC) && (defined(ARCH_CPU_32_BITS) || \
+ (defined(ARCH_CPU_64_BITS) && defined(__clang__)))
+
+ // Execute an MMX instruction.
+ __asm emms;
+
+ // Execute an SSE instruction.
+ __asm xorps xmm0, xmm0;
+
+ // Execute an SSE 2 instruction.
+ __asm psrldq xmm0, 0;
+
if (cpu.has_sse3()) {
// Execute an SSE 3 instruction.
- __asm__ __volatile__("addsubpd %%xmm0, %%xmm0\n" : : : "xmm0");
+ __asm addsubpd xmm0, xmm0;
}
if (cpu.has_ssse3()) {
// Execute a Supplimental SSE 3 instruction.
- __asm__ __volatile__("psignb %%xmm0, %%xmm0\n" : : : "xmm0");
+ __asm psignb xmm0, xmm0;
}
if (cpu.has_sse41()) {
// Execute an SSE 4.1 instruction.
- __asm__ __volatile__("pmuldq %%xmm0, %%xmm0\n" : : : "xmm0");
+ __asm pmuldq xmm0, xmm0;
}
if (cpu.has_sse42()) {
// Execute an SSE 4.2 instruction.
- __asm__ __volatile__("crc32 %%eax, %%eax\n" : : : "eax");
+ __asm crc32 eax, eax;
}
-#endif
-#endif
+
+// Visual C 2012 required for AVX.
+#if _MSC_VER >= 1700
+ if (cpu.has_avx()) {
+ // Execute an AVX instruction.
+ __asm vzeroupper;
+ }
+
+ if (cpu.has_avx2()) {
+ // Execute an AVX 2 instruction.
+ __asm vpunpcklbw ymm0, ymm0, ymm0
+ }
+#endif // _MSC_VER >= 1700
+#endif // defined(COMPILER_GCC)
+#endif // defined(ARCH_CPU_X86_FAMILY)
}
diff --git a/base/critical_closure.h b/base/critical_closure.h
index 75e37045a7..6ebd7afa50 100644
--- a/base/critical_closure.h
+++ b/base/critical_closure.h
@@ -6,6 +6,8 @@
#define BASE_CRITICAL_CLOSURE_H_
#include "base/callback.h"
+#include "base/macros.h"
+#include "build/build_config.h"
#if defined(OS_IOS)
#include "base/bind.h"
diff --git a/base/debug/BUILD.gn b/base/debug/BUILD.gn
deleted file mode 100644
index 8ed623b03f..0000000000
--- a/base/debug/BUILD.gn
+++ /dev/null
@@ -1,76 +0,0 @@
-# Copyright (c) 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-source_set("debug") {
- sources = [
- "alias.cc",
- "alias.h",
- "asan_invalid_access.cc",
- "asan_invalid_access.h",
- "crash_logging.cc",
- "crash_logging.h",
- "debugger.cc",
- "debugger.h",
- "debugger_posix.cc",
- "debugger_win.cc",
- "dump_without_crashing.cc",
- "dump_without_crashing.h",
- "gdi_debug_util_win.cc",
- "gdi_debug_util_win.h",
-
- # This file depends on files from the "allocator" target,
- # but this target does not depend on "allocator" (see
- # allocator.gyp for details).
- "leak_annotations.h",
- "leak_tracker.h",
- "proc_maps_linux.cc",
- "proc_maps_linux.h",
- "profiler.cc",
- "profiler.h",
- "stack_trace.cc",
- "stack_trace.h",
- "stack_trace_android.cc",
- "stack_trace_posix.cc",
- "stack_trace_win.cc",
- "task_annotator.cc",
- "task_annotator.h",
- ]
-
- if (is_android) {
- # Android uses some Linux sources, put those back.
- set_sources_assignment_filter([])
- sources += [ "proc_maps_linux.cc" ]
- set_sources_assignment_filter(sources_assignment_filter)
-
- sources -= [ "stack_trace_posix.cc" ]
- }
-
- if (is_nacl) {
- sources -= [
- "crash_logging.cc",
- "crash_logging.h",
- "stack_trace.cc",
- "stack_trace_posix.cc",
- ]
- }
-
- configs += [ "//base:base_implementation" ]
-
- deps = [
- "//base/memory",
- "//base/process",
- ]
-
- if (is_linux) {
- defines = [ "USE_SYMBOLIZE" ]
- deps += [ "//base/third_party/symbolize" ]
- }
-
- allow_circular_includes_from = [
- "//base/memory",
- "//base/process",
- ]
-
- visibility = [ "//base/*" ]
-}
diff --git a/base/debug/debugger.cc b/base/debug/debugger.cc
index 79233c58c5..1ccee1c2c2 100644
--- a/base/debug/debugger.cc
+++ b/base/debug/debugger.cc
@@ -5,6 +5,7 @@
#include "base/debug/debugger.h"
#include "base/logging.h"
#include "base/threading/platform_thread.h"
+#include "build/build_config.h"
namespace base {
namespace debug {
diff --git a/base/debug/debugger_posix.cc b/base/debug/debugger_posix.cc
index f719cc61c5..d7e492bed9 100644
--- a/base/debug/debugger_posix.cc
+++ b/base/debug/debugger_posix.cc
@@ -3,10 +3,12 @@
// found in the LICENSE file.
#include "base/debug/debugger.h"
+#include "base/macros.h"
#include "build/build_config.h"
#include <errno.h>
#include <fcntl.h>
+#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/param.h>
@@ -34,7 +36,7 @@
#include <ostream>
-#include "base/basictypes.h"
+#include "base/debug/alias.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/posix/eintr_wrapper.h"
@@ -237,6 +239,12 @@ 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.
+ // Linker's ICF feature may merge this function with other functions with the
+ // same definition (e.g. any function whose sole job is to call abort()) and
+ // it may confuse the crash report processing system. http://crbug.com/508489
+ static int static_variable_to_make_this_function_unique = 0;
+ base::debug::Alias(&static_variable_to_make_this_function_unique);
+
DEBUG_BREAK();
#if defined(OS_ANDROID) && !defined(OFFICIAL_BUILD)
// For Android development we always build release (debug builds are
diff --git a/base/debug/leak_tracker.h b/base/debug/leak_tracker.h
index 8c5aaf31c2..9dd1622939 100644
--- a/base/debug/leak_tracker.h
+++ b/base/debug/leak_tracker.h
@@ -5,6 +5,8 @@
#ifndef BASE_DEBUG_LEAK_TRACKER_H_
#define BASE_DEBUG_LEAK_TRACKER_H_
+#include <stddef.h>
+
#include "build/build_config.h"
// Only enable leak tracking in non-uClibc debug builds.
diff --git a/base/debug/proc_maps_linux.h b/base/debug/proc_maps_linux.h
index 9fbd47898d..38e92314c8 100644
--- a/base/debug/proc_maps_linux.h
+++ b/base/debug/proc_maps_linux.h
@@ -5,11 +5,12 @@
#ifndef BASE_DEBUG_PROC_MAPS_LINUX_H_
#define BASE_DEBUG_PROC_MAPS_LINUX_H_
+#include <stdint.h>
+
#include <string>
#include <vector>
#include "base/base_export.h"
-#include "base/basictypes.h"
namespace base {
namespace debug {
@@ -31,7 +32,7 @@ struct MappedMemoryRegion {
unsigned long long offset;
// Bitmask of read/write/execute/private/shared permissions.
- uint8 permissions;
+ uint8_t permissions;
// Name of the file mapped into memory.
//
diff --git a/base/debug/stack_trace.cc b/base/debug/stack_trace.cc
index ce9e9ad550..2250c8fb14 100644
--- a/base/debug/stack_trace.cc
+++ b/base/debug/stack_trace.cc
@@ -4,13 +4,13 @@
#include "base/debug/stack_trace.h"
-#include "base/basictypes.h"
-
#include <string.h>
#include <algorithm>
#include <sstream>
+#include "base/macros.h"
+
namespace base {
namespace debug {
diff --git a/base/debug/stack_trace.h b/base/debug/stack_trace.h
index fb271b6da4..07e119a16b 100644
--- a/base/debug/stack_trace.h
+++ b/base/debug/stack_trace.h
@@ -5,6 +5,8 @@
#ifndef BASE_DEBUG_STACK_TRACE_H_
#define BASE_DEBUG_STACK_TRACE_H_
+#include <stddef.h>
+
#include <iosfwd>
#include <string>
@@ -26,16 +28,13 @@ 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 different version of EnableInProcessStackDumping that also works for
-// sandboxed processes. For more details take a look at the description
-// of EnableInProcessStackDumping.
+// In sandboxed processes, this has to be called before the sandbox is turned
+// on.
// Calling this function on Linux opens /proc/self/maps and caches its
-// contents. In DEBUG builds, this function also opens the object files that
-// are loaded in memory and caches their file descriptors (this cannot be
+// contents. In non-official builds, this function also opens the object files
+// that are loaded in memory and caches their file descriptors (this cannot be
// done in official builds because it has security implications).
-BASE_EXPORT bool EnableInProcessStackDumpingForSandbox();
+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
@@ -54,7 +53,7 @@ class BASE_EXPORT StackTrace {
// Creates a stacktrace for an exception.
// Note: this function will throw an import not found (StackWalk64) exception
// on system without dbghelp 5.1.
- StackTrace(const _EXCEPTION_POINTERS* exception_pointers);
+ StackTrace(_EXCEPTION_POINTERS* exception_pointers);
StackTrace(const _CONTEXT* context);
#endif
@@ -79,7 +78,7 @@ class BASE_EXPORT StackTrace {
private:
#if defined(OS_WIN)
- void InitTrace(_CONTEXT* context_record);
+ void InitTrace(const _CONTEXT* context_record);
#endif
// From http://msdn.microsoft.com/en-us/library/bb204633.aspx,
diff --git a/base/debug/stack_trace_posix.cc b/base/debug/stack_trace_posix.cc
index 4506cbef6f..98e6c2ed2b 100644
--- a/base/debug/stack_trace_posix.cc
+++ b/base/debug/stack_trace_posix.cc
@@ -7,6 +7,8 @@
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
+#include <stddef.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/param.h>
@@ -30,10 +32,10 @@
#include <AvailabilityMacros.h>
#endif
-#include "base/basictypes.h"
#include "base/debug/debugger.h"
#include "base/debug/proc_maps_linux.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/singleton.h"
#include "base/numerics/safe_conversions.h"
@@ -291,6 +293,16 @@ void StackDumpSignalHandler(int signal,
}
PrintToStderr("\n");
+#if defined(CFI_ENFORCEMENT)
+ if (signal == SIGILL && info->si_code == ILL_ILLOPN) {
+ PrintToStderr(
+ "CFI: Most likely a control flow integrity violation; for more "
+ "information see:\n");
+ PrintToStderr(
+ "https://www.chromium.org/developers/testing/control-flow-integrity\n");
+ }
+#endif
+
debug::StackTrace().Print();
#if defined(OS_LINUX)
@@ -344,7 +356,7 @@ void StackDumpSignalHandler(int signal,
{ " trp: ", context->uc_mcontext.gregs[REG_TRAPNO] },
{ " msk: ", context->uc_mcontext.gregs[REG_OLDMASK] },
{ " cr2: ", context->uc_mcontext.gregs[REG_CR2] },
-#endif
+#endif // ARCH_CPU_32_BITS
};
#if ARCH_CPU_32_BITS
@@ -363,49 +375,20 @@ void StackDumpSignalHandler(int signal,
PrintToStderr("\n");
}
PrintToStderr("\n");
-#endif
-#elif defined(OS_MACOSX)
- // TODO(shess): Port to 64-bit, and ARM architecture (32 and 64-bit).
-#if ARCH_CPU_X86_FAMILY && ARCH_CPU_32_BITS
- ucontext_t* context = reinterpret_cast<ucontext_t*>(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<size_t>(
- 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<size_t>(
- 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<size_t>(
- 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)
+#endif // ARCH_CPU_X86_FAMILY
+#endif // defined(OS_LINUX)
+
+ PrintToStderr("[end of stack trace]\n");
+
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+ if (::signal(signal, SIG_DFL) == SIG_ERR)
+ _exit(1);
+#else
+ // Non-Mac OSes should probably reraise the signal as well, but the Linux
+ // sandbox tests break on CrOS devices.
+ // https://code.google.com/p/chromium/issues/detail?id=551681
_exit(1);
+#endif // defined(OS_MACOSX) && !defined(OS_IOS)
}
class PrintBacktraceOutputHandler : public BacktraceOutputHandler {
@@ -502,14 +485,14 @@ class SandboxSymbolizeHelper {
}
// Returns a O_RDONLY file descriptor for |file_path| if it was opened
- // sucessfully during the initialization. The file is repositioned at
+ // successfully during the initialization. The file is repositioned at
// offset 0.
// IMPORTANT: This function must be async-signal-safe because it can be
// called from a signal handler (symbolizing stack frames for a crash).
int GetFileDescriptor(const char* file_path) {
int fd = -1;
-#if !defined(NDEBUG)
+#if !defined(OFFICIAL_BUILD)
if (file_path) {
// The assumption here is that iterating over std::map<std::string, int>
// using a const_iterator does not allocate dynamic memory, hense it is
@@ -530,7 +513,7 @@ class SandboxSymbolizeHelper {
fd = -1;
}
}
-#endif // !defined(NDEBUG)
+#endif // !defined(OFFICIAL_BUILD)
return fd;
}
@@ -616,11 +599,9 @@ class SandboxSymbolizeHelper {
// Opens all object files and caches their file descriptors.
void OpenSymbolFiles() {
// Pre-opening and caching the file descriptors of all loaded modules is
- // not considered safe for retail builds. Hence it is only done in debug
- // builds. For more details, take a look at: http://crbug.com/341966
- // Enabling this to release mode would require approval from the security
- // team.
-#if !defined(NDEBUG)
+ // not safe for production builds. Hence it is only done in non-official
+ // builds. For more details, take a look at: http://crbug.com/341966.
+#if !defined(OFFICIAL_BUILD)
// Open the object files for all read-only executable regions and cache
// their file descriptors.
std::vector<MappedMemoryRegion>::const_iterator it;
@@ -652,7 +633,7 @@ class SandboxSymbolizeHelper {
}
}
}
-#endif // !defined(NDEBUG)
+#endif // !defined(OFFICIAL_BUILD)
}
// Initializes and installs the symbolization callback.
@@ -674,7 +655,7 @@ class SandboxSymbolizeHelper {
// Closes all file descriptors owned by this instance.
void CloseObjectFiles() {
-#if !defined(NDEBUG)
+#if !defined(OFFICIAL_BUILD)
std::map<std::string, int>::iterator it;
for (it = modules_.begin(); it != modules_.end(); ++it) {
int ret = IGNORE_EINTR(close(it->second));
@@ -682,19 +663,18 @@ class SandboxSymbolizeHelper {
it->second = -1;
}
modules_.clear();
-#endif // !defined(NDEBUG)
+#endif // !defined(OFFICIAL_BUILD)
}
// Set to true upon successful initialization.
bool is_initialized_;
-#if !defined(NDEBUG)
+#if !defined(OFFICIAL_BUILD)
// Mapping from file name to file descriptor. Includes file descriptors
// for all successfully opened object files and the file descriptor for
- // /proc/self/maps. This code is not safe for release builds so
- // this is only done for DEBUG builds.
+ // /proc/self/maps. This code is not safe for production builds.
std::map<std::string, int> modules_;
-#endif // !defined(NDEBUG)
+#endif // !defined(OFFICIAL_BUILD)
// Cache for the process memory regions. Produced by parsing the contents
// of /proc/self/maps cache.
@@ -704,15 +684,11 @@ class SandboxSymbolizeHelper {
};
#endif // USE_SYMBOLIZE
-bool EnableInProcessStackDumpingForSandbox() {
+bool EnableInProcessStackDumping() {
#if defined(USE_SYMBOLIZE)
SandboxSymbolizeHelper::GetInstance();
#endif // USE_SYMBOLIZE
- return EnableInProcessStackDumping();
-}
-
-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.
@@ -777,7 +753,7 @@ void StackTrace::OutputToStream(std::ostream* os) const {
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) {
+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)
@@ -788,13 +764,14 @@ char *itoa_r(intptr_t i, char *buf, size_t sz, int base, size_t padding) {
return NULL;
}
- char *start = buf;
+ char* start = buf;
uintptr_t j = i;
// Handle negative numbers (only for base 10).
if (i < 0 && base == 10) {
- j = -i;
+ // This does "j = -i" while avoiding integer overflow.
+ j = static_cast<uintptr_t>(-(i + 1)) + 1;
// Make sure we can write the '-' character.
if (++n > sz) {
@@ -806,7 +783,7 @@ char *itoa_r(intptr_t i, char *buf, size_t sz, int base, size_t padding) {
// Loop until we have converted the entire number. Output at least one
// character (i.e. '0').
- char *ptr = start;
+ char* ptr = start;
do {
// Make sure there is still enough space left in our output buffer.
if (++n > sz) {
diff --git a/base/debug/task_annotator.cc b/base/debug/task_annotator.cc
index 19df8cb39e..4ba4d91b88 100644
--- a/base/debug/task_annotator.cc
+++ b/base/debug/task_annotator.cc
@@ -20,36 +20,25 @@ TaskAnnotator::~TaskAnnotator() {
void TaskAnnotator::DidQueueTask(const char* queue_function,
const PendingTask& pending_task) {
- TRACE_EVENT_FLOW_BEGIN0(TRACE_DISABLED_BY_DEFAULT("toplevel.flow"),
+ TRACE_EVENT_WITH_FLOW0(TRACE_DISABLED_BY_DEFAULT("toplevel.flow"),
queue_function,
- TRACE_ID_MANGLE(GetTaskTraceID(pending_task)));
+ TRACE_ID_MANGLE(GetTaskTraceID(pending_task)),
+ TRACE_EVENT_FLAG_FLOW_OUT);
}
void TaskAnnotator::RunTask(const char* queue_function,
- const char* run_function,
const PendingTask& pending_task) {
tracked_objects::TaskStopwatch stopwatch;
stopwatch.Start();
tracked_objects::Duration queue_duration =
stopwatch.StartTime() - pending_task.EffectiveTimePosted();
- TRACE_EVENT_FLOW_END1(TRACE_DISABLED_BY_DEFAULT("toplevel.flow"),
- queue_function,
- TRACE_ID_MANGLE(GetTaskTraceID(pending_task)),
- "queue_duration",
- queue_duration.InMilliseconds());
-
- // When tracing memory for posted tasks it's more valuable to attribute the
- // memory allocations to the source function than generically to the task
- // runner.
- TRACE_EVENT_WITH_MEMORY_TAG2(
- "toplevel",
- run_function,
- pending_task.posted_from.function_name(), // Name for memory tracking.
- "src_file",
- pending_task.posted_from.file_name(),
- "src_func",
- pending_task.posted_from.function_name());
+ TRACE_EVENT_WITH_FLOW1(TRACE_DISABLED_BY_DEFAULT("toplevel.flow"),
+ queue_function,
+ TRACE_ID_MANGLE(GetTaskTraceID(pending_task)),
+ TRACE_EVENT_FLAG_FLOW_IN,
+ "queue_duration",
+ queue_duration.InMilliseconds());
// 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
@@ -66,9 +55,10 @@ void TaskAnnotator::RunTask(const char* queue_function,
pending_task, stopwatch);
}
-uint64 TaskAnnotator::GetTaskTraceID(const PendingTask& task) const {
- return (static_cast<uint64>(task.sequence_num) << 32) |
- ((static_cast<uint64>(reinterpret_cast<intptr_t>(this)) << 32) >> 32);
+uint64_t TaskAnnotator::GetTaskTraceID(const PendingTask& task) const {
+ return (static_cast<uint64_t>(task.sequence_num) << 32) |
+ ((static_cast<uint64_t>(reinterpret_cast<intptr_t>(this)) << 32) >>
+ 32);
}
} // namespace debug
diff --git a/base/debug/task_annotator.h b/base/debug/task_annotator.h
index aa5f17b11f..443c71bf30 100644
--- a/base/debug/task_annotator.h
+++ b/base/debug/task_annotator.h
@@ -5,8 +5,10 @@
#ifndef BASE_DEBUG_TASK_ANNOTATOR_H_
#define BASE_DEBUG_TASK_ANNOTATOR_H_
+#include <stdint.h>
+
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
namespace base {
struct PendingTask;
@@ -25,21 +27,23 @@ class BASE_EXPORT TaskAnnotator {
const PendingTask& pending_task);
// Run a previously queued task. |queue_function| should match what was
- // passed into |DidQueueTask| for this task. |run_function| is used as the
- // name for the trace event that surrounds the task's execution.
- void RunTask(const char* queue_function,
- const char* run_function,
- const PendingTask& pending_task);
+ // passed into |DidQueueTask| for this task.
+ void RunTask(const char* queue_function, const PendingTask& pending_task);
private:
// 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 TaskAnnotator pointers on other processes.
- uint64 GetTaskTraceID(const PendingTask& task) const;
+ uint64_t GetTaskTraceID(const PendingTask& task) const;
DISALLOW_COPY_AND_ASSIGN(TaskAnnotator);
};
+#define TRACE_TASK_EXECUTION(run_function, task) \
+ TRACE_EVENT2("toplevel", (run_function), "src_file", \
+ (task).posted_from.file_name(), "src_func", \
+ (task).posted_from.function_name());
+
} // namespace debug
} // namespace base
diff --git a/base/debug/task_annotator_unittest.cc b/base/debug/task_annotator_unittest.cc
index ddffc21ab0..9f5c442327 100644
--- a/base/debug/task_annotator_unittest.cc
+++ b/base/debug/task_annotator_unittest.cc
@@ -24,8 +24,7 @@ TEST(TaskAnnotatorTest, QueueAndRunTask) {
TaskAnnotator annotator;
annotator.DidQueueTask("TaskAnnotatorTest::Queue", pending_task);
EXPECT_EQ(0, result);
- annotator.RunTask(
- "TaskAnnotatorTest::Queue", "TaskAnnotatorTest::Run", pending_task);
+ annotator.RunTask("TaskAnnotatorTest::Queue", pending_task);
EXPECT_EQ(123, result);
}
diff --git a/base/environment.cc b/base/environment.cc
index 245051d0c1..adb73871d0 100644
--- a/base/environment.cc
+++ b/base/environment.cc
@@ -4,11 +4,14 @@
#include "base/environment.h"
+#include <stddef.h>
+
#include <vector>
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
#if defined(OS_POSIX)
#include <stdlib.h>
@@ -33,9 +36,9 @@ class EnvironmentImpl : public Environment {
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));
+ alternate_case_var = ToUpperASCII(variable_name);
else if (first_char >= 'A' && first_char <= 'Z')
- alternate_case_var = StringToLowerASCII(std::string(variable_name));
+ alternate_case_var = ToLowerASCII(variable_name);
else
return false;
return GetVarImpl(alternate_case_var.c_str(), result);
@@ -228,7 +231,7 @@ scoped_ptr<char*[]> AlterEnvironment(const char* const* const env,
result[i] = &storage_data[result_indices[i]];
result[result_indices.size()] = 0; // Null terminator.
- return result.Pass();
+ return result;
}
#endif // OS_POSIX
diff --git a/base/environment_unittest.cc b/base/environment_unittest.cc
index f0577a8a82..77e971787d 100644
--- a/base/environment_unittest.cc
+++ b/base/environment_unittest.cc
@@ -4,6 +4,7 @@
#include "base/environment.h"
#include "base/memory/scoped_ptr.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
@@ -129,7 +130,7 @@ TEST_F(EnvironmentTest, AlterEnvironment) {
EnvironmentMap changes;
scoped_ptr<char*[]> e;
- e = AlterEnvironment(empty, changes).Pass();
+ e = AlterEnvironment(empty, changes);
EXPECT_TRUE(e[0] == NULL);
changes["A"] = "1";
diff --git a/base/file_descriptor_posix.h b/base/file_descriptor_posix.h
index 376ad39e30..2a366116a3 100644
--- a/base/file_descriptor_posix.h
+++ b/base/file_descriptor_posix.h
@@ -14,9 +14,16 @@ 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.
+// IMPORTANT: This is primarily intended for use when sending file descriptors
+// over IPC. Even if |auto_close| is true, base::FileDescriptor does NOT close()
+// |fd| when going out of scope. Instead, a consumer of a base::FileDescriptor
+// must invoke close() on |fd| if |auto_close| is true.
+//
+// In the case of IPC, the the IPC subsystem knows to close() |fd| after sending
+// a message that contains a base::FileDescriptor if auto_close == true. On the
+// other end, the receiver must make sure to close() |fd| after it has finished
+// processing the IPC message. See the IPC::ParamTraits<> specialization in
+// ipc/ipc_message_utils.h for all the details.
// -----------------------------------------------------------------------------
struct FileDescriptor {
FileDescriptor() : fd(-1), auto_close(false) {}
diff --git a/base/file_version_info.h b/base/file_version_info.h
index 57b837c24b..8c1bf92438 100644
--- a/base/file_version_info.h
+++ b/base/file_version_info.h
@@ -32,6 +32,17 @@ class FilePath;
// version returns values from the Info.plist as appropriate. TODO(avi): make
// this a less-obvious Windows-ism.
+#if defined(OS_WIN)
+// 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
+// is done as a macro to force inlining of __ImageBase. It used to be inside of
+// a method labeled with __forceinline, but inlining through __forceinline
+// stopped working for Debug builds in VS2013 (http://crbug.com/516359).
+#define CREATE_FILE_VERSION_INFO_FOR_CURRENT_MODULE() \
+ FileVersionInfo::CreateFileVersionInfoForModule( \
+ reinterpret_cast<HMODULE>(&__ImageBase))
+#endif
+
class BASE_EXPORT FileVersionInfo {
public:
virtual ~FileVersionInfo() {}
@@ -46,17 +57,9 @@ class BASE_EXPORT FileVersionInfo {
#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.
+ // See CREATE_FILE_VERSION_INFO_FOR_CURRENT_MODULE() helper above for a
+ // CreateFileVersionInfoForCurrentModule() alternative for Windows.
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<HMODULE>(&__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.
diff --git a/base/file_version_info_unittest.cc b/base/file_version_info_unittest.cc
index f89bb8e27c..66e298df97 100644
--- a/base/file_version_info_unittest.cc
+++ b/base/file_version_info_unittest.cc
@@ -2,9 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stddef.h>
+
#include "base/file_version_info.h"
#include "base/files/file_path.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#if defined(OS_WIN)
@@ -32,53 +36,49 @@ FilePath GetTestDataPath() {
#if defined(OS_WIN)
TEST(FileVersionInfoTest, HardCodedProperties) {
- const wchar_t* kDLLNames[] = {
- L"FileVersionInfoTest1.dll"
- };
+ const wchar_t kDLLName[] = {L"FileVersionInfoTest1.dll"};
- const wchar_t* kExpectedValues[1][15] = {
+ const wchar_t* const kExpectedValues[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"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
+ 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]);
+ FilePath dll_path = GetTestDataPath();
+ dll_path = dll_path.Append(kDLLName);
- scoped_ptr<FileVersionInfo> version_info(
- FileVersionInfo::CreateFileVersionInfo(dll_path));
+ scoped_ptr<FileVersionInfo> 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());
- }
+ int j = 0;
+ EXPECT_EQ(kExpectedValues[j++], version_info->company_name());
+ EXPECT_EQ(kExpectedValues[j++], version_info->company_short_name());
+ EXPECT_EQ(kExpectedValues[j++], version_info->product_name());
+ EXPECT_EQ(kExpectedValues[j++], version_info->product_short_name());
+ EXPECT_EQ(kExpectedValues[j++], version_info->internal_name());
+ EXPECT_EQ(kExpectedValues[j++], version_info->product_version());
+ EXPECT_EQ(kExpectedValues[j++], version_info->private_build());
+ EXPECT_EQ(kExpectedValues[j++], version_info->special_build());
+ EXPECT_EQ(kExpectedValues[j++], version_info->comments());
+ EXPECT_EQ(kExpectedValues[j++], version_info->original_filename());
+ EXPECT_EQ(kExpectedValues[j++], version_info->file_description());
+ EXPECT_EQ(kExpectedValues[j++], version_info->file_version());
+ EXPECT_EQ(kExpectedValues[j++], version_info->legal_copyright());
+ EXPECT_EQ(kExpectedValues[j++], version_info->legal_trademarks());
+ EXPECT_EQ(kExpectedValues[j++], version_info->last_change());
}
#endif
@@ -97,7 +97,7 @@ TEST(FileVersionInfoTest, IsOfficialBuild) {
// Test consistency check.
ASSERT_EQ(arraysize(kDLLNames), arraysize(kExpected));
- for (int i = 0; i < arraysize(kDLLNames); ++i) {
+ for (size_t i = 0; i < arraysize(kDLLNames); ++i) {
FilePath dll_path = GetTestDataPath();
dll_path = dll_path.Append(kDLLNames[i]);
diff --git a/base/files/OWNERS b/base/files/OWNERS
deleted file mode 100644
index b99e8a2fc7..0000000000
--- a/base/files/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-rvargas@chromium.org
-
-per-file file_path_watcher*=mnissler@chromium.org
diff --git a/base/files/dir_reader_fallback.h b/base/files/dir_reader_fallback.h
index d2bf252a6e..4bc199a922 100644
--- a/base/files/dir_reader_fallback.h
+++ b/base/files/dir_reader_fallback.h
@@ -21,7 +21,7 @@ class DirReaderFallback {
bool Next() { return false; }
// Return the name of the current directory entry.
- const char* name() { return 0;}
+ const char* name() { return nullptr;}
// Return the file descriptor which is being used.
int fd() const { return -1; }
diff --git a/base/files/dir_reader_linux.h b/base/files/dir_reader_linux.h
index abf259530b..4ce0c34245 100644
--- a/base/files/dir_reader_linux.h
+++ b/base/files/dir_reader_linux.h
@@ -7,11 +7,13 @@
#include <errno.h>
#include <fcntl.h>
+#include <stddef.h>
#include <stdint.h>
#include <sys/syscall.h>
#include <unistd.h>
#include "base/logging.h"
+#include "base/macros.h"
#include "base/posix/eintr_wrapper.h"
// See the comments in dir_reader_posix.h about this.
@@ -70,7 +72,7 @@ class DirReaderLinux {
const char* name() const {
if (!size_)
- return NULL;
+ return nullptr;
const linux_dirent* dirent =
reinterpret_cast<const linux_dirent*>(&buf_[offset_]);
@@ -88,7 +90,8 @@ class DirReaderLinux {
private:
const int fd_;
unsigned char buf_[512];
- size_t offset_, size_;
+ size_t offset_;
+ size_t size_;
DISALLOW_COPY_AND_ASSIGN(DirReaderLinux);
};
diff --git a/base/files/dir_reader_posix_unittest.cc b/base/files/dir_reader_posix_unittest.cc
index 2e181b3d85..a75858feeb 100644
--- a/base/files/dir_reader_posix_unittest.cc
+++ b/base/files/dir_reader_posix_unittest.cc
@@ -12,6 +12,7 @@
#include "base/files/scoped_temp_dir.h"
#include "base/logging.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#if defined(OS_ANDROID)
diff --git a/base/files/file.cc b/base/files/file.cc
index 58f80c5232..ab05630062 100644
--- a/base/files/file.cc
+++ b/base/files/file.cc
@@ -7,6 +7,7 @@
#include "base/files/file_tracing.h"
#include "base/metrics/histogram.h"
#include "base/timer/elapsed_timer.h"
+#include "build/build_config.h"
namespace base {
@@ -26,10 +27,8 @@ File::File()
}
#if !defined(OS_NACL)
-File::File(const FilePath& path, uint32 flags)
- : error_details_(FILE_OK),
- created_(false),
- async_(false) {
+File::File(const FilePath& path, uint32_t flags)
+ : error_details_(FILE_OK), created_(false), async_(false) {
Initialize(path, flags);
}
#endif
@@ -50,40 +49,48 @@ File::File(Error error_details)
async_(false) {
}
-File::File(RValue other)
- : file_(other.object->TakePlatformFile()),
- path_(other.object->path_),
- error_details_(other.object->error_details()),
- created_(other.object->created()),
- async_(other.object->async_) {
-}
+File::File(File&& other)
+ : file_(other.TakePlatformFile()),
+ tracing_path_(other.tracing_path_),
+ error_details_(other.error_details()),
+ created_(other.created()),
+ async_(other.async_) {}
File::~File() {
// Go through the AssertIOAllowed logic.
Close();
}
-File& File::operator=(RValue other) {
- if (this != other.object) {
- Close();
- SetPlatformFile(other.object->TakePlatformFile());
- path_ = other.object->path_;
- error_details_ = other.object->error_details();
- created_ = other.object->created();
- async_ = other.object->async_;
- }
+// static
+File File::CreateForAsyncHandle(PlatformFile platform_file) {
+ File file(platform_file);
+ // It would be nice if we could validate that |platform_file| was opened with
+ // FILE_FLAG_OVERLAPPED on Windows but this doesn't appear to be possible.
+ file.async_ = true;
+ return file;
+}
+
+File& File::operator=(File&& other) {
+ DCHECK_NE(this, &other);
+ Close();
+ SetPlatformFile(other.TakePlatformFile());
+ tracing_path_ = other.tracing_path_;
+ error_details_ = other.error_details();
+ created_ = other.created();
+ async_ = other.async_;
return *this;
}
#if !defined(OS_NACL)
-void File::Initialize(const FilePath& path, uint32 flags) {
+void File::Initialize(const FilePath& path, uint32_t flags) {
if (path.ReferencesParent()) {
error_details_ = FILE_ERROR_ACCESS_DENIED;
return;
}
- path_ = path;
+ if (FileTracing::IsCategoryEnabled())
+ tracing_path_ = path;
SCOPED_FILE_TRACE("Initialize");
- DoInitialize(flags);
+ DoInitialize(path, flags);
}
#endif
diff --git a/base/files/file.h b/base/files/file.h
index b21b15972b..7ab5ca5859 100644
--- a/base/files/file.h
+++ b/base/files/file.h
@@ -5,31 +5,26 @@
#ifndef BASE_FILES_FILE_H_
#define BASE_FILES_FILE_H_
-#include "build/build_config.h"
-#if defined(OS_WIN)
-#include <windows.h>
-#endif
-
-#if defined(OS_POSIX)
-#include <sys/stat.h>
-#endif
+#include <stdint.h>
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/files/file_path.h"
#include "base/files/file_tracing.h"
#include "base/files/scoped_file.h"
-#include "base/gtest_prod_util.h"
#include "base/move.h"
#include "base/time/time.h"
+#include "build/build_config.h"
#if defined(OS_WIN)
+#include <windows.h>
#include "base/win/scoped_handle.h"
#endif
-FORWARD_DECLARE_TEST(FileTest, MemoryCorruption);
+#if defined(OS_POSIX)
+#include <sys/stat.h>
+#endif
namespace base {
@@ -56,7 +51,7 @@ typedef struct stat64 stat_wrapper_t;
// to the OS is not considered const, even if there is no apparent change to
// member variables.
class BASE_EXPORT File {
- MOVE_ONLY_TYPE_FOR_CPP_03(File, RValue)
+ MOVE_ONLY_TYPE_FOR_CPP_03(File)
public:
// FLAG_(OPEN|CREATE).* are mutually exclusive. You should specify exactly one
@@ -88,6 +83,7 @@ class BASE_EXPORT File {
FLAG_TERMINAL_DEVICE = 1 << 16, // Serial port flags.
FLAG_BACKUP_SEMANTICS = 1 << 17, // Used on Windows only.
FLAG_EXECUTE = 1 << 18, // Used on Windows only.
+ FLAG_SEQUENTIAL_SCAN = 1 << 19, // Used on Windows only.
};
// This enum has been recorded in multiple histograms. If the order of the
@@ -140,7 +136,7 @@ class BASE_EXPORT File {
#endif
// The size of the file in bytes. Undefined when is_directory is true.
- int64 size;
+ int64_t size;
// True if the file corresponds to a directory.
bool is_directory;
@@ -163,7 +159,7 @@ class BASE_EXPORT File {
// Creates or opens the given file. This will fail with 'access denied' if the
// |path| contains path traversal ('..') components.
- File(const FilePath& path, uint32 flags);
+ File(const FilePath& path, uint32_t flags);
// Takes ownership of |platform_file|.
explicit File(PlatformFile platform_file);
@@ -171,17 +167,21 @@ class BASE_EXPORT File {
// Creates an object with a specific error_details code.
explicit File(Error error_details);
- // Move constructor for C++03 move emulation of this type.
- File(RValue other);
+ File(File&& other);
~File();
- // Move operator= for C++03 move emulation of this type.
- File& operator=(RValue other);
+ // Takes ownership of |platform_file|.
+ static File CreateForAsyncHandle(PlatformFile platform_file);
+
+ File& operator=(File&& other);
// Creates or opens the given file.
- void Initialize(const FilePath& path, uint32 flags);
+ void Initialize(const FilePath& path, uint32_t flags);
+ // Returns |true| if the handle / fd wrapped by this object is valid. This
+ // method doesn't interact with the file system (and is safe to be called from
+ // ThreadRestrictions::SetIOAllowed(false) threads).
bool IsValid() const;
// Returns true if a new file was created (or an old one truncated to zero
@@ -205,7 +205,7 @@ class BASE_EXPORT 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.
- int64 Seek(Whence whence, int64 offset);
+ int64_t Seek(Whence whence, int64_t 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
@@ -213,7 +213,7 @@ class BASE_EXPORT File {
// 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.
- int Read(int64 offset, char* data, int size);
+ int Read(int64_t offset, char* data, int size);
// Same as above but without seek.
int ReadAtCurrentPos(char* data, int size);
@@ -221,7 +221,7 @@ class BASE_EXPORT File {
// 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.
- int ReadNoBestEffort(int64 offset, char* data, int size);
+ int ReadNoBestEffort(int64_t offset, char* data, int size);
// Same as above but without seek.
int ReadAtCurrentPosNoBestEffort(char* data, int size);
@@ -232,7 +232,7 @@ class BASE_EXPORT File {
// all platforms.
// Ignores the offset and writes to the end of the file if the file was opened
// with FLAG_APPEND.
- int Write(int64 offset, const char* data, int size);
+ int Write(int64_t offset, const char* data, int size);
// Save as above but without seek.
int WriteAtCurrentPos(const char* data, int size);
@@ -242,12 +242,12 @@ class BASE_EXPORT File {
int WriteAtCurrentPosNoBestEffort(const char* data, int size);
// Returns the current size of this file, or a negative number on failure.
- int64 GetLength();
+ int64_t GetLength();
// Truncates the 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.
- bool SetLength(int64 length);
+ bool SetLength(int64_t length);
// Instructs the filesystem to flush the file to disk. (POSIX: fsync, Windows:
// FlushFileBuffers).
@@ -303,58 +303,11 @@ class BASE_EXPORT File {
static std::string ErrorToString(Error error);
private:
- FRIEND_TEST_ALL_PREFIXES(::FileTest, MemoryCorruption);
-
friend class FileTracing::ScopedTrace;
-#if defined(OS_POSIX)
- // Encloses a single ScopedFD, saving a cheap tamper resistent memory checksum
- // alongside it. This checksum is validated at every access, allowing early
- // detection of memory corruption.
-
- // TODO(gavinp): This is in place temporarily to help us debug
- // https://crbug.com/424562 , which can't be reproduced in valgrind. Remove
- // this code after we have fixed this issue.
- class MemoryCheckingScopedFD {
- public:
- MemoryCheckingScopedFD();
- MemoryCheckingScopedFD(int fd);
- ~MemoryCheckingScopedFD();
-
- bool is_valid() const { Check(); return file_.is_valid(); }
- int get() const { Check(); return file_.get(); }
-
- void reset() { Check(); file_.reset(); UpdateChecksum(); }
- void reset(int fd) { Check(); file_.reset(fd); UpdateChecksum(); }
- int release() {
- Check();
- int fd = file_.release();
- UpdateChecksum();
- return fd;
- }
-
- private:
- FRIEND_TEST_ALL_PREFIXES(::FileTest, MemoryCorruption);
-
- // Computes the checksum for the current value of |file_|. Returns via an
- // out parameter to guard against implicit conversions of unsigned integral
- // types.
- void ComputeMemoryChecksum(unsigned int* out_checksum) const;
-
- // Confirms that the current |file_| and |file_memory_checksum_| agree,
- // failing a CHECK if they do not.
- void Check() const;
-
- void UpdateChecksum();
-
- ScopedFD file_;
- unsigned int file_memory_checksum_;
- };
-#endif
-
- // Creates or opens the given file. Only called if |path_| has no
+ // Creates or opens the given file. Only called if |path| has no
// traversal ('..') components.
- void DoInitialize(uint32 flags);
+ void DoInitialize(const FilePath& path, uint32_t flags);
// TODO(tnagel): Reintegrate into Flush() once histogram isn't needed anymore,
// cf. issue 473337.
@@ -365,11 +318,12 @@ class BASE_EXPORT File {
#if defined(OS_WIN)
win::ScopedHandle file_;
#elif defined(OS_POSIX)
- MemoryCheckingScopedFD file_;
+ ScopedFD file_;
#endif
- // Path that |Initialize()| was called with. Only set if safe (i.e. no '..').
- FilePath path_;
+ // A path to use for tracing purposes. Set if file tracing is enabled during
+ // |Initialize()|.
+ FilePath tracing_path_;
// Object tied to the lifetime of |this| that enables/disables tracing.
FileTracing::ScopedEnabler trace_enabler_;
@@ -382,3 +336,4 @@ class BASE_EXPORT File {
} // namespace base
#endif // BASE_FILES_FILE_H_
+
diff --git a/base/files/file_enumerator.h b/base/files/file_enumerator.h
index 38bb8337c7..7cac8dd9d4 100644
--- a/base/files/file_enumerator.h
+++ b/base/files/file_enumerator.h
@@ -5,12 +5,15 @@
#ifndef BASE_FILES_FILE_ENUMERATOR_H_
#define BASE_FILES_FILE_ENUMERATOR_H_
+#include <stddef.h>
+#include <stdint.h>
+
#include <stack>
#include <vector>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/files/file_path.h"
+#include "base/macros.h"
#include "base/time/time.h"
#include "build/build_config.h"
@@ -49,7 +52,7 @@ class BASE_EXPORT FileEnumerator {
// includes the |root_path| passed into the FileEnumerator constructor.
FilePath GetName() const;
- int64 GetSize() const;
+ int64_t GetSize() const;
Time GetLastModifiedTime() const;
#if defined(OS_WIN)
diff --git a/base/files/file_enumerator_posix.cc b/base/files/file_enumerator_posix.cc
index 7533a24c35..fb4010aadc 100644
--- a/base/files/file_enumerator_posix.cc
+++ b/base/files/file_enumerator_posix.cc
@@ -7,9 +7,11 @@
#include <dirent.h>
#include <errno.h>
#include <fnmatch.h>
+#include <stdint.h>
#include "base/logging.h"
#include "base/threading/thread_restrictions.h"
+#include "build/build_config.h"
namespace base {
@@ -27,7 +29,7 @@ FilePath FileEnumerator::FileInfo::GetName() const {
return filename_;
}
-int64 FileEnumerator::FileInfo::GetSize() const {
+int64_t FileEnumerator::FileInfo::GetSize() const {
return stat_.st_size;
}
diff --git a/base/files/file_path.cc b/base/files/file_path.cc
index b04a01df26..2677258128 100644
--- a/base/files/file_path.cc
+++ b/base/files/file_path.cc
@@ -7,16 +7,14 @@
#include <string.h>
#include <algorithm>
-#include "base/basictypes.h"
#include "base/logging.h"
+#include "base/macros.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"
+#include "build/build_config.h"
#if defined(OS_MACOSX)
#include "base/mac/scoped_cftyperef.h"
@@ -31,7 +29,8 @@
namespace base {
-typedef FilePath::StringType StringType;
+using StringType = FilePath::StringType;
+using StringPieceType = FilePath::StringPieceType;
namespace {
@@ -45,7 +44,7 @@ const FilePath::CharType kStringTerminator = FILE_PATH_LITERAL('\0');
// 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 */) {
+StringPieceType::size_type FindDriveLetter(StringPieceType /* 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.
@@ -59,26 +58,25 @@ StringType::size_type FindDriveLetter(const StringType& /* path */) {
}
#if defined(FILE_PATH_USES_DRIVE_LETTERS)
-bool EqualDriveLetterCaseInsensitive(const StringType& a,
- const StringType& b) {
+bool EqualDriveLetterCaseInsensitive(StringPieceType a, StringPieceType 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))
+ StringPieceType a_letter(a.substr(0, a_letter_pos + 1));
+ StringPieceType b_letter(b.substr(0, b_letter_pos + 1));
+ if (!StartsWith(a_letter, b_letter, CompareCase::INSENSITIVE_ASCII))
return false;
- StringType a_rest(a.substr(a_letter_pos + 1));
- StringType b_rest(b.substr(b_letter_pos + 1));
+ StringPieceType a_rest(a.substr(a_letter_pos + 1));
+ StringPieceType 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) {
+bool IsPathAbsolute(StringPieceType path) {
#if defined(FILE_PATH_USES_DRIVE_LETTERS)
StringType::size_type letter = FindDriveLetter(path);
if (letter != StringType::npos) {
@@ -177,7 +175,8 @@ FilePath::FilePath() {
FilePath::FilePath(const FilePath& that) : path_(that.path_) {
}
-FilePath::FilePath(const StringType& path) : path_(path) {
+FilePath::FilePath(StringPieceType path) {
+ path.CopyToString(&path_);
StringType::size_type nul_pos = path_.find(kStringTerminator);
if (nul_pos != StringType::npos)
path_.erase(nul_pos, StringType::npos);
@@ -279,7 +278,7 @@ bool FilePath::AppendRelativePath(const FilePath& child,
// never case sensitive.
if ((FindDriveLetter(*parent_comp) != StringType::npos) &&
(FindDriveLetter(*child_comp) != StringType::npos)) {
- if (!StartsWith(*parent_comp, *child_comp, false))
+ if (!StartsWith(*parent_comp, *child_comp, CompareCase::INSENSITIVE_ASCII))
return false;
++parent_comp;
++child_comp;
@@ -404,7 +403,7 @@ FilePath FilePath::RemoveFinalExtension() const {
return FilePath(path_.substr(0, dot));
}
-FilePath FilePath::InsertBeforeExtension(const StringType& suffix) const {
+FilePath FilePath::InsertBeforeExtension(StringPieceType suffix) const {
if (suffix.empty())
return FilePath(path_);
@@ -413,27 +412,28 @@ FilePath FilePath::InsertBeforeExtension(const StringType& suffix) const {
StringType ext = Extension();
StringType ret = RemoveExtension().value();
- ret.append(suffix);
+ suffix.AppendToString(&ret);
ret.append(ext);
return FilePath(ret);
}
-FilePath FilePath::InsertBeforeExtensionASCII(const StringPiece& suffix)
+FilePath FilePath::InsertBeforeExtensionASCII(StringPiece suffix)
const {
DCHECK(IsStringASCII(suffix));
#if defined(OS_WIN)
- return InsertBeforeExtension(ASCIIToUTF16(suffix.as_string()));
+ return InsertBeforeExtension(ASCIIToUTF16(suffix));
#elif defined(OS_POSIX)
- return InsertBeforeExtension(suffix.as_string());
+ return InsertBeforeExtension(suffix);
#endif
}
-FilePath FilePath::AddExtension(const StringType& extension) const {
+FilePath FilePath::AddExtension(StringPieceType 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))
+ if (extension.empty() ||
+ (extension.size() == 1 && extension[0] == kExtensionSeparator))
return *this;
StringType str = path_;
@@ -441,27 +441,28 @@ FilePath FilePath::AddExtension(const StringType& extension) const {
*(str.end() - 1) != kExtensionSeparator) {
str.append(1, kExtensionSeparator);
}
- str.append(extension);
+ extension.AppendToString(&str);
return FilePath(str);
}
-FilePath FilePath::ReplaceExtension(const StringType& extension) const {
+FilePath FilePath::ReplaceExtension(StringPieceType 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))
+ if (extension.empty() ||
+ (extension.size() == 1 && extension[0] == kExtensionSeparator))
return no_ext;
StringType str = no_ext.value();
if (extension[0] != kExtensionSeparator)
str.append(1, kExtensionSeparator);
- str.append(extension);
+ extension.AppendToString(&str);
return FilePath(str);
}
-bool FilePath::MatchesExtension(const StringType& extension) const {
+bool FilePath::MatchesExtension(StringPieceType extension) const {
DCHECK(extension.empty() || extension[0] == kExtensionSeparator);
StringType current_extension = Extension();
@@ -472,17 +473,17 @@ bool FilePath::MatchesExtension(const StringType& extension) const {
return FilePath::CompareEqualIgnoreCase(extension, current_extension);
}
-FilePath FilePath::Append(const StringType& component) const {
- const StringType* appended = &component;
+FilePath FilePath::Append(StringPieceType component) const {
+ StringPieceType 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;
+ if (nul_pos != StringPieceType::npos) {
+ component.substr(0, nul_pos).CopyToString(&without_nuls);
+ appended = StringPieceType(without_nuls);
}
- DCHECK(!IsPathAbsolute(*appended));
+ DCHECK(!IsPathAbsolute(appended));
if (path_.compare(kCurrentDirectory) == 0) {
// Append normally doesn't do any normalization, but as a special case,
@@ -492,7 +493,7 @@ FilePath FilePath::Append(const StringType& component) const {
// 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);
+ return FilePath(appended);
}
FilePath new_path(path_);
@@ -501,7 +502,7 @@ FilePath FilePath::Append(const StringType& component) const {
// 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) {
+ 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])) {
@@ -512,7 +513,7 @@ FilePath FilePath::Append(const StringType& component) const {
}
}
- new_path.path_.append(*appended);
+ appended.AppendToString(&new_path.path_);
return new_path;
}
@@ -520,12 +521,12 @@ FilePath FilePath::Append(const FilePath& component) const {
return Append(component.value());
}
-FilePath FilePath::AppendASCII(const StringPiece& component) const {
+FilePath FilePath::AppendASCII(StringPiece component) const {
DCHECK(base::IsStringASCII(component));
#if defined(OS_WIN)
- return Append(ASCIIToUTF16(component.as_string()));
+ return Append(ASCIIToUTF16(component));
#elif defined(OS_POSIX)
- return Append(component.as_string());
+ return Append(component);
#endif
}
@@ -680,17 +681,17 @@ bool FilePath::ReadFromPickle(PickleIterator* iter) {
}
#if defined(OS_WIN)
-// Windows specific implementation of file string comparisons
+// Windows specific implementation of file string comparisons.
-int FilePath::CompareIgnoreCase(const StringType& string1,
- const StringType& string2) {
+int FilePath::CompareIgnoreCase(StringPieceType string1,
+ StringPieceType 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();
+ StringPieceType::const_iterator i1 = string1.begin();
+ StringPieceType::const_iterator i2 = string2.begin();
+ StringPieceType::const_iterator string1end = string1.end();
+ StringPieceType::const_iterator string2end = string2.end();
for ( ; i1 != string1end && i2 != string2end; ++i1, ++i2) {
wchar_t c1 =
(wchar_t)LOWORD(::CharUpperW((LPWSTR)(DWORD_PTR)MAKELONG(*i1, 0)));
@@ -709,7 +710,7 @@ int FilePath::CompareIgnoreCase(const StringType& string1,
}
#elif defined(OS_MACOSX)
-// Mac OS X specific implementation of file string comparisons
+// Mac OS X specific implementation of file string comparisons.
// cf. http://developer.apple.com/mac/library/technotes/tn/tn1150.html#UnicodeSubtleties
//
@@ -1153,23 +1154,23 @@ inline int HFSReadNextNonIgnorableCodepoint(const char* string,
return codepoint;
}
-} // anonymous namespace
+} // 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 FilePath::HFSFastUnicodeCompare(StringPieceType string1,
+ StringPieceType string2) {
int length1 = string1.length();
int length2 = string2.length();
int index1 = 0;
int index2 = 0;
for (;;) {
- int codepoint1 = HFSReadNextNonIgnorableCodepoint(string1.c_str(),
+ int codepoint1 = HFSReadNextNonIgnorableCodepoint(string1.data(),
length1,
&index1);
- int codepoint2 = HFSReadNextNonIgnorableCodepoint(string2.c_str(),
+ int codepoint2 = HFSReadNextNonIgnorableCodepoint(string2.data(),
length2,
&index2);
if (codepoint1 != codepoint2)
@@ -1182,11 +1183,11 @@ int FilePath::HFSFastUnicodeCompare(const StringType& string1,
}
}
-StringType FilePath::GetHFSDecomposedForm(const StringType& string) {
+StringType FilePath::GetHFSDecomposedForm(StringPieceType string) {
ScopedCFTypeRef<CFStringRef> cfstring(
CFStringCreateWithBytesNoCopy(
NULL,
- reinterpret_cast<const UInt8*>(string.c_str()),
+ reinterpret_cast<const UInt8*>(string.data()),
string.length(),
kCFStringEncodingUTF8,
false,
@@ -1215,8 +1216,8 @@ StringType FilePath::GetHFSDecomposedForm(const StringType& string) {
return result;
}
-int FilePath::CompareIgnoreCase(const StringType& string1,
- const StringType& string2) {
+int FilePath::CompareIgnoreCase(StringPieceType string1,
+ StringPieceType string2) {
// Quick checks for empty strings - these speed things up a bit and make the
// following code cleaner.
if (string1.empty())
@@ -1233,7 +1234,7 @@ int FilePath::CompareIgnoreCase(const StringType& string1,
ScopedCFTypeRef<CFStringRef> cfstring1(
CFStringCreateWithBytesNoCopy(
NULL,
- reinterpret_cast<const UInt8*>(string1.c_str()),
+ reinterpret_cast<const UInt8*>(string1.data()),
string1.length(),
kCFStringEncodingUTF8,
false,
@@ -1241,7 +1242,7 @@ int FilePath::CompareIgnoreCase(const StringType& string1,
ScopedCFTypeRef<CFStringRef> cfstring2(
CFStringCreateWithBytesNoCopy(
NULL,
- reinterpret_cast<const UInt8*>(string2.c_str()),
+ reinterpret_cast<const UInt8*>(string2.data()),
string2.length(),
kCFStringEncodingUTF8,
false,
@@ -1256,11 +1257,12 @@ int FilePath::CompareIgnoreCase(const StringType& string1,
#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());
+// Generic Posix system comparisons.
+int FilePath::CompareIgnoreCase(StringPieceType string1,
+ StringPieceType string2) {
+ // Specifically need null termianted strings for this API call.
+ int comparison = strcasecmp(string1.as_string().c_str(),
+ string2.as_string().c_str());
if (comparison < 0)
return -1;
if (comparison > 0)
@@ -1313,7 +1315,7 @@ FilePath FilePath::NormalizePathSeparatorsTo(CharType /* separator */) const {
#if defined(OS_ANDROID)
bool FilePath::IsContentUri() const {
- return StartsWithASCII(path_, "content://", false /*case_sensitive*/);
+ return StartsWith(path_, "content://", base::CompareCase::INSENSITIVE_ASCII);
}
#endif
diff --git a/base/files/file_path.h b/base/files/file_path.h
index 0c84af6c85..89e9cbfb1d 100644
--- a/base/files/file_path.h
+++ b/base/files/file_path.h
@@ -111,8 +111,9 @@
#include "base/base_export.h"
#include "base/compiler_specific.h"
#include "base/containers/hash_tables.h"
+#include "base/macros.h"
#include "base/strings/string16.h"
-#include "base/strings/string_piece.h" // For implicit conversions.
+#include "base/strings/string_piece.h"
#include "build/build_config.h"
// Windows-style drive letter support and pathname separator characters can be
@@ -124,6 +125,15 @@
#define FILE_PATH_USES_WIN_SEPARATORS
#endif // OS_WIN
+// To print path names portably use PRIsFP (based on PRIuS and friends from
+// C99 and format_macros.h) like this:
+// base::StringPrintf("Path is %" PRIsFP ".\n", path.value().c_str());
+#if defined(OS_POSIX)
+#define PRIsFP "s"
+#elif defined(OS_WIN)
+#define PRIsFP "ls"
+#endif // OS_WIN
+
namespace base {
class Pickle;
@@ -144,6 +154,7 @@ class BASE_EXPORT FilePath {
typedef std::wstring StringType;
#endif // OS_WIN
+ typedef BasicStringPiece<StringType> StringPieceType;
typedef StringType::value_type CharType;
// Null-terminated array of separators used to separate components in
@@ -166,7 +177,7 @@ class BASE_EXPORT FilePath {
FilePath();
FilePath(const FilePath& that);
- explicit FilePath(const StringType& path);
+ explicit FilePath(StringPieceType path);
~FilePath();
FilePath& operator=(const FilePath& that);
@@ -268,25 +279,23 @@ class BASE_EXPORT FilePath {
// 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;
+ StringPieceType suffix) const WARN_UNUSED_RESULT;
FilePath InsertBeforeExtensionASCII(
- const base::StringPiece& suffix) const WARN_UNUSED_RESULT;
+ 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;
+ FilePath AddExtension(StringPieceType 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;
+ FilePath ReplaceExtension(StringPieceType 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;
+ bool MatchesExtension(StringPieceType 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
@@ -294,7 +303,7 @@ class BASE_EXPORT FilePath {
// 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(StringPieceType 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
@@ -303,8 +312,7 @@ class BASE_EXPORT FilePath {
// 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;
+ FilePath AppendASCII(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
@@ -388,14 +396,14 @@ class BASE_EXPORT FilePath {
// 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) {
+ static int CompareIgnoreCase(StringPieceType string1,
+ StringPieceType string2);
+ static bool CompareEqualIgnoreCase(StringPieceType string1,
+ StringPieceType string2) {
return CompareIgnoreCase(string1, string2) == 0;
}
- static bool CompareLessIgnoreCase(const StringType& string1,
- const StringType& string2) {
+ static bool CompareLessIgnoreCase(StringPieceType string1,
+ StringPieceType string2) {
return CompareIgnoreCase(string1, string2) < 0;
}
@@ -405,14 +413,14 @@ class BASE_EXPORT FilePath {
// 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);
+ static StringType GetHFSDecomposedForm(StringPieceType 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);
+ static int HFSFastUnicodeCompare(StringPieceType string1,
+ StringPieceType string2);
#endif
#if defined(OS_ANDROID)
diff --git a/base/files/file_path_constants.cc b/base/files/file_path_constants.cc
index 34b17a60b7..0b748466c2 100644
--- a/base/files/file_path_constants.cc
+++ b/base/files/file_path_constants.cc
@@ -2,7 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stddef.h>
+
#include "base/files/file_path.h"
+#include "base/macros.h"
namespace base {
diff --git a/base/files/file_path_unittest.cc b/base/files/file_path_unittest.cc
index 97851ea06d..b1d93a8bc0 100644
--- a/base/files/file_path_unittest.cc
+++ b/base/files/file_path_unittest.cc
@@ -2,12 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stddef.h>
+
#include <sstream>
-#include "base/basictypes.h"
#include "base/files/file_path.h"
+#include "base/macros.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_locale.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
@@ -1132,7 +1135,7 @@ TEST_F(FilePathTest, FromUTF8Unsafe_And_AsUTF8Unsafe) {
};
#if !defined(SYSTEM_NATIVE_UTF8) && defined(OS_LINUX)
- ScopedLocale locale("en_US.UTF-8");
+ ScopedLocale locale("en_US.UTF-8");
#endif
for (size_t i = 0; i < arraysize(cases); ++i) {
diff --git a/base/files/file_path_watcher.cc b/base/files/file_path_watcher.cc
index 59ae7059ca..955e6a2a5b 100644
--- a/base/files/file_path_watcher.cc
+++ b/base/files/file_path_watcher.cc
@@ -9,6 +9,7 @@
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
+#include "build/build_config.h"
#if defined(OS_MACOSX) && !defined(OS_IOS)
#include "base/mac/mac_util.h"
diff --git a/base/files/file_path_watcher.h b/base/files/file_path_watcher.h
index 4f132aff78..d5c6db1acf 100644
--- a/base/files/file_path_watcher.h
+++ b/base/files/file_path_watcher.h
@@ -8,9 +8,9 @@
#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/macros.h"
#include "base/memory/ref_counted.h"
#include "base/single_thread_task_runner.h"
@@ -62,9 +62,8 @@ class BASE_EXPORT FilePathWatcher {
return task_runner_;
}
- void set_task_runner(
- scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
- task_runner_ = task_runner.Pass();
+ void set_task_runner(scoped_refptr<base::SingleThreadTaskRunner> runner) {
+ task_runner_ = std::move(runner);
}
// Must be called before the PlatformDelegate is deleted.
diff --git a/base/files/file_path_watcher_fsevents.cc b/base/files/file_path_watcher_fsevents.cc
index da01c431bf..78637aa5a5 100644
--- a/base/files/file_path_watcher_fsevents.cc
+++ b/base/files/file_path_watcher_fsevents.cc
@@ -12,6 +12,7 @@
#include "base/logging.h"
#include "base/mac/libdispatch_task_runner.h"
#include "base/mac/scoped_cftyperef.h"
+#include "base/macros.h"
#include "base/message_loop/message_loop.h"
#include "base/thread_task_runner_handle.h"
diff --git a/base/files/file_path_watcher_fsevents.h b/base/files/file_path_watcher_fsevents.h
index 300aa761df..1ebe4636e4 100644
--- a/base/files/file_path_watcher_fsevents.h
+++ b/base/files/file_path_watcher_fsevents.h
@@ -6,11 +6,13 @@
#define BASE_FILES_FILE_PATH_WATCHER_FSEVENTS_H_
#include <CoreServices/CoreServices.h>
+#include <stddef.h>
#include <vector>
#include "base/files/file_path.h"
#include "base/files/file_path_watcher.h"
+#include "base/macros.h"
namespace base {
diff --git a/base/files/file_path_watcher_kqueue.cc b/base/files/file_path_watcher_kqueue.cc
index a126db708d..b6e61abe41 100644
--- a/base/files/file_path_watcher_kqueue.cc
+++ b/base/files/file_path_watcher_kqueue.cc
@@ -5,6 +5,7 @@
#include "base/files/file_path_watcher_kqueue.h"
#include <fcntl.h>
+#include <stddef.h>
#include <sys/param.h>
#include "base/bind.h"
diff --git a/base/files/file_path_watcher_kqueue.h b/base/files/file_path_watcher_kqueue.h
index 69555a3003..d9db8c2587 100644
--- a/base/files/file_path_watcher_kqueue.h
+++ b/base/files/file_path_watcher_kqueue.h
@@ -10,6 +10,7 @@
#include "base/files/file_path.h"
#include "base/files/file_path_watcher.h"
+#include "base/macros.h"
#include "base/message_loop/message_loop.h"
#include "base/single_thread_task_runner.h"
diff --git a/base/files/file_path_watcher_linux.cc b/base/files/file_path_watcher_linux.cc
index ba2f1d96c8..a75eaba7db 100644
--- a/base/files/file_path_watcher_linux.cc
+++ b/base/files/file_path_watcher_linux.cc
@@ -5,6 +5,7 @@
#include "base/files/file_path_watcher.h"
#include <errno.h>
+#include <stddef.h>
#include <string.h>
#include <sys/inotify.h>
#include <sys/ioctl.h>
@@ -25,9 +26,11 @@
#include "base/lazy_instance.h"
#include "base/location.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/posix/eintr_wrapper.h"
#include "base/single_thread_task_runner.h"
+#include "base/stl_util.h"
#include "base/synchronization/lock.h"
#include "base/thread_task_runner_handle.h"
#include "base/threading/thread.h"
@@ -167,9 +170,8 @@ class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate,
void RemoveRecursiveWatches();
// |path| is a symlink to a non-existent target. Attempt to add a watch to
- // the link target's parent directory. Returns true and update |watch_entry|
- // on success.
- bool AddWatchForBrokenSymlink(const FilePath& path, WatchEntry* watch_entry);
+ // the link target's parent directory. Update |watch_entry| on success.
+ void AddWatchForBrokenSymlink(const FilePath& path, WatchEntry* watch_entry);
bool HasValidWatchVector() const;
@@ -513,21 +515,19 @@ void FilePathWatcherImpl::UpdateWatches() {
// Walk the list of watches and update them as we go.
FilePath path(FILE_PATH_LITERAL("/"));
- bool path_valid = true;
for (size_t i = 0; i < watches_.size(); ++i) {
WatchEntry& watch_entry = watches_[i];
InotifyReader::Watch old_watch = watch_entry.watch;
watch_entry.watch = InotifyReader::kInvalidWatch;
watch_entry.linkname.clear();
- if (path_valid) {
- watch_entry.watch = g_inotify_reader.Get().AddWatch(path, this);
- if (watch_entry.watch == InotifyReader::kInvalidWatch) {
- if (IsLink(path)) {
- path_valid = AddWatchForBrokenSymlink(path, &watch_entry);
- } else {
- path_valid = false;
- }
- }
+ watch_entry.watch = g_inotify_reader.Get().AddWatch(path, this);
+ if (watch_entry.watch == InotifyReader::kInvalidWatch) {
+ // Ignore the error code (beyond symlink handling) to attempt to add
+ // watches on accessible children of unreadable directories. Note that
+ // this is a best-effort attempt; we may not catch events in this
+ // scenario.
+ if (IsLink(path))
+ AddWatchForBrokenSymlink(path, &watch_entry);
}
if (old_watch != watch_entry.watch)
g_inotify_reader.Get().RemoveWatch(old_watch, this);
@@ -643,12 +643,12 @@ void FilePathWatcherImpl::RemoveRecursiveWatches() {
recursive_watches_by_path_.clear();
}
-bool FilePathWatcherImpl::AddWatchForBrokenSymlink(const FilePath& path,
+void FilePathWatcherImpl::AddWatchForBrokenSymlink(const FilePath& path,
WatchEntry* watch_entry) {
DCHECK_EQ(InotifyReader::kInvalidWatch, watch_entry->watch);
FilePath link;
if (!ReadSymbolicLink(path, &link))
- return false;
+ return;
if (!link.IsAbsolute())
link = path.DirName().Append(link);
@@ -664,11 +664,10 @@ bool FilePathWatcherImpl::AddWatchForBrokenSymlink(const FilePath& path,
// exist. Ideally we should make sure we've watched all the components of
// the symlink path for changes. See crbug.com/91561 for details.
DPLOG(WARNING) << "Watch failed for " << link.DirName().value();
- return false;
+ return;
}
watch_entry->watch = watch;
watch_entry->linkname = link.BaseName().value();
- return true;
}
bool FilePathWatcherImpl::HasValidWatchVector() const {
diff --git a/base/files/file_path_watcher_mac.cc b/base/files/file_path_watcher_mac.cc
index 6f55ba4f89..7338eafa44 100644
--- a/base/files/file_path_watcher_mac.cc
+++ b/base/files/file_path_watcher_mac.cc
@@ -4,6 +4,7 @@
#include "base/files/file_path_watcher.h"
#include "base/files/file_path_watcher_kqueue.h"
+#include "build/build_config.h"
#if !defined(OS_IOS)
#include "base/files/file_path_watcher_fsevents.h"
diff --git a/base/files/file_path_watcher_unittest.cc b/base/files/file_path_watcher_unittest.cc
index 21e9dd137e..a860b13099 100644
--- a/base/files/file_path_watcher_unittest.cc
+++ b/base/files/file_path_watcher_unittest.cc
@@ -13,7 +13,6 @@
#include <set>
-#include "base/basictypes.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/compiler_specific.h"
@@ -21,6 +20,7 @@
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/location.h"
+#include "base/macros.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
@@ -30,6 +30,7 @@
#include "base/test/test_timeouts.h"
#include "base/thread_task_runner_handle.h"
#include "base/threading/thread.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#if defined(OS_ANDROID)
diff --git a/base/files/file_posix.cc b/base/files/file_posix.cc
index 129f5faf4b..12f80c4f8f 100644
--- a/base/files/file_posix.cc
+++ b/base/files/file_posix.cc
@@ -6,6 +6,7 @@
#include <errno.h>
#include <fcntl.h>
+#include <stdint.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -14,6 +15,7 @@
#include "base/posix/eintr_wrapper.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_restrictions.h"
+#include "build/build_config.h"
#if defined(OS_ANDROID)
#include "base/os_compat_android.h"
@@ -22,19 +24,19 @@
namespace base {
// Make sure our Whence mappings match the system headers.
-COMPILE_ASSERT(File::FROM_BEGIN == SEEK_SET &&
- File::FROM_CURRENT == SEEK_CUR &&
- File::FROM_END == SEEK_END, whence_matches_system);
+static_assert(File::FROM_BEGIN == SEEK_SET && File::FROM_CURRENT == SEEK_CUR &&
+ File::FROM_END == SEEK_END,
+ "whence mapping must match the system headers");
namespace {
#if defined(OS_BSD) || defined(OS_MACOSX) || defined(OS_NACL)
-static int CallFstat(int fd, stat_wrapper_t *sb) {
+int CallFstat(int fd, stat_wrapper_t *sb) {
ThreadRestrictions::AssertIOAllowed();
return fstat(fd, sb);
}
#else
-static int CallFstat(int fd, stat_wrapper_t *sb) {
+int CallFstat(int fd, stat_wrapper_t *sb) {
ThreadRestrictions::AssertIOAllowed();
return fstat64(fd, sb);
}
@@ -43,15 +45,15 @@ static int CallFstat(int fd, stat_wrapper_t *sb) {
// 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 bool IsOpenAppend(PlatformFile file) {
+bool IsOpenAppend(PlatformFile file) {
return (fcntl(file, F_GETFL) & O_APPEND) != 0;
}
-static int CallFtruncate(PlatformFile file, int64 length) {
+int CallFtruncate(PlatformFile file, int64_t length) {
return HANDLE_EINTR(ftruncate(file, length));
}
-static int CallFutimes(PlatformFile file, const struct timeval times[2]) {
+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/
@@ -68,36 +70,36 @@ static int CallFutimes(PlatformFile file, const struct timeval times[2]) {
#endif
}
-static File::Error CallFctnlFlock(PlatformFile file, bool do_lock) {
+File::Error CallFcntlFlock(PlatformFile file, bool do_lock) {
struct flock lock;
- lock.l_type = F_WRLCK;
+ lock.l_type = do_lock ? F_WRLCK : F_UNLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0; // Lock entire file.
- if (HANDLE_EINTR(fcntl(file, do_lock ? F_SETLK : F_UNLCK, &lock)) == -1)
+ if (HANDLE_EINTR(fcntl(file, F_SETLK, &lock)) == -1)
return File::OSErrorToFileError(errno);
return File::FILE_OK;
}
#else // defined(OS_NACL)
-static bool IsOpenAppend(PlatformFile file) {
+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) {
+int CallFtruncate(PlatformFile file, int64_t length) {
NOTIMPLEMENTED(); // NaCl doesn't implement ftruncate.
return 0;
}
-static int CallFutimes(PlatformFile file, const struct timeval times[2]) {
+int CallFutimes(PlatformFile file, const struct timeval times[2]) {
NOTIMPLEMENTED(); // NaCl doesn't implement futimes.
return 0;
}
-static File::Error CallFctnlFlock(PlatformFile file, bool do_lock) {
+File::Error CallFcntlFlock(PlatformFile file, bool do_lock) {
NOTIMPLEMENTED(); // NaCl doesn't implement flock struct.
return File::FILE_ERROR_INVALID_OPERATION;
}
@@ -112,32 +114,32 @@ void File::Info::FromStat(const stat_wrapper_t& stat_info) {
#if defined(OS_LINUX)
time_t last_modified_sec = stat_info.st_mtim.tv_sec;
- int64 last_modified_nsec = stat_info.st_mtim.tv_nsec;
+ int64_t last_modified_nsec = stat_info.st_mtim.tv_nsec;
time_t last_accessed_sec = stat_info.st_atim.tv_sec;
- int64 last_accessed_nsec = stat_info.st_atim.tv_nsec;
+ int64_t last_accessed_nsec = stat_info.st_atim.tv_nsec;
time_t creation_time_sec = stat_info.st_ctim.tv_sec;
- int64 creation_time_nsec = stat_info.st_ctim.tv_nsec;
+ int64_t creation_time_nsec = stat_info.st_ctim.tv_nsec;
#elif defined(OS_ANDROID)
time_t last_modified_sec = stat_info.st_mtime;
- int64 last_modified_nsec = stat_info.st_mtime_nsec;
+ int64_t last_modified_nsec = stat_info.st_mtime_nsec;
time_t last_accessed_sec = stat_info.st_atime;
- int64 last_accessed_nsec = stat_info.st_atime_nsec;
+ int64_t last_accessed_nsec = stat_info.st_atime_nsec;
time_t creation_time_sec = stat_info.st_ctime;
- int64 creation_time_nsec = stat_info.st_ctime_nsec;
+ int64_t creation_time_nsec = stat_info.st_ctime_nsec;
#elif defined(OS_MACOSX) || defined(OS_IOS) || defined(OS_BSD)
time_t last_modified_sec = stat_info.st_mtimespec.tv_sec;
- int64 last_modified_nsec = stat_info.st_mtimespec.tv_nsec;
+ int64_t last_modified_nsec = stat_info.st_mtimespec.tv_nsec;
time_t last_accessed_sec = stat_info.st_atimespec.tv_sec;
- int64 last_accessed_nsec = stat_info.st_atimespec.tv_nsec;
+ int64_t last_accessed_nsec = stat_info.st_atimespec.tv_nsec;
time_t creation_time_sec = stat_info.st_ctimespec.tv_sec;
- int64 creation_time_nsec = stat_info.st_ctimespec.tv_nsec;
+ int64_t creation_time_nsec = stat_info.st_ctimespec.tv_nsec;
#else
time_t last_modified_sec = stat_info.st_mtime;
- int64 last_modified_nsec = 0;
+ int64_t last_modified_nsec = 0;
time_t last_accessed_sec = stat_info.st_atime;
- int64 last_accessed_nsec = 0;
+ int64_t last_accessed_nsec = 0;
time_t creation_time_sec = stat_info.st_ctime;
- int64 creation_time_nsec = 0;
+ int64_t creation_time_nsec = 0;
#endif
last_modified =
@@ -177,7 +179,7 @@ void File::Close() {
file_.reset();
}
-int64 File::Seek(Whence whence, int64 offset) {
+int64_t File::Seek(Whence whence, int64_t offset) {
ThreadRestrictions::AssertIOAllowed();
DCHECK(IsValid());
@@ -186,17 +188,17 @@ int64 File::Seek(Whence whence, int64 offset) {
// Additionally check __BIONIC__ since older versions of Android don't define
// _FILE_OFFSET_BITS.
#if _FILE_OFFSET_BITS != 64 || defined(__BIONIC__)
- COMPILE_ASSERT(sizeof(int64) == sizeof(off64_t), off64_t_64_bit);
+ static_assert(sizeof(int64_t) == sizeof(off64_t), "off64_t must be 64 bits");
return lseek64(file_.get(), static_cast<off64_t>(offset),
static_cast<int>(whence));
#else
- COMPILE_ASSERT(sizeof(int64) == sizeof(off_t), off_t_64_bit);
+ static_assert(sizeof(int64_t) == sizeof(off_t), "off_t must be 64 bits");
return lseek(file_.get(), static_cast<off_t>(offset),
static_cast<int>(whence));
#endif
}
-int File::Read(int64 offset, char* data, int size) {
+int File::Read(int64_t offset, char* data, int size) {
ThreadRestrictions::AssertIOAllowed();
DCHECK(IsValid());
if (size < 0)
@@ -239,7 +241,7 @@ int File::ReadAtCurrentPos(char* data, int size) {
return bytes_read ? bytes_read : rv;
}
-int File::ReadNoBestEffort(int64 offset, char* data, int size) {
+int File::ReadNoBestEffort(int64_t offset, char* data, int size) {
ThreadRestrictions::AssertIOAllowed();
DCHECK(IsValid());
SCOPED_FILE_TRACE_WITH_SIZE("ReadNoBestEffort", size);
@@ -256,7 +258,7 @@ int File::ReadAtCurrentPosNoBestEffort(char* data, int size) {
return HANDLE_EINTR(read(file_.get(), data, size));
}
-int File::Write(int64 offset, const char* data, int size) {
+int File::Write(int64_t offset, const char* data, int size) {
ThreadRestrictions::AssertIOAllowed();
if (IsOpenAppend(file_.get()))
@@ -314,7 +316,7 @@ int File::WriteAtCurrentPosNoBestEffort(const char* data, int size) {
return HANDLE_EINTR(write(file_.get(), data, size));
}
-int64 File::GetLength() {
+int64_t File::GetLength() {
DCHECK(IsValid());
SCOPED_FILE_TRACE("GetLength");
@@ -326,7 +328,7 @@ int64 File::GetLength() {
return file_info.st_size;
}
-bool File::SetLength(int64 length) {
+bool File::SetLength(int64_t length) {
ThreadRestrictions::AssertIOAllowed();
DCHECK(IsValid());
@@ -362,12 +364,12 @@ bool File::GetInfo(Info* info) {
File::Error File::Lock() {
SCOPED_FILE_TRACE("Lock");
- return CallFctnlFlock(file_.get(), true);
+ return CallFcntlFlock(file_.get(), true);
}
File::Error File::Unlock() {
SCOPED_FILE_TRACE("Unlock");
- return CallFctnlFlock(file_.get(), false);
+ return CallFcntlFlock(file_.get(), false);
}
File File::Duplicate() {
@@ -383,7 +385,7 @@ File File::Duplicate() {
File other(other_fd);
if (async())
other.async_ = true;
- return other.Pass();
+ return other;
}
// Static.
@@ -422,53 +424,10 @@ File::Error File::OSErrorToFileError(int saved_errno) {
}
}
-File::MemoryCheckingScopedFD::MemoryCheckingScopedFD() {
- UpdateChecksum();
-}
-
-File::MemoryCheckingScopedFD::MemoryCheckingScopedFD(int fd) : file_(fd) {
- UpdateChecksum();
-}
-
-File::MemoryCheckingScopedFD::~MemoryCheckingScopedFD() {}
-
-// static
-void File::MemoryCheckingScopedFD::ComputeMemoryChecksum(
- unsigned int* out_checksum) const {
- // Use a single iteration of a linear congruentional generator (lcg) to
- // provide a cheap checksum unlikely to be accidentally matched by a random
- // memory corruption.
-
- // By choosing constants that satisfy the Hull-Duebell Theorem on lcg cycle
- // length, we insure that each distinct fd value maps to a distinct checksum,
- // which maximises the utility of our checksum.
-
- // This code uses "unsigned int" throughout for its defined modular semantics,
- // which implicitly gives us a divisor that is a power of two.
-
- const unsigned int kMultiplier = 13035 * 4 + 1;
- COMPILE_ASSERT(((kMultiplier - 1) & 3) == 0, pred_must_be_multiple_of_four);
- const unsigned int kIncrement = 1595649551;
- COMPILE_ASSERT(kIncrement & 1, must_be_coprime_to_powers_of_two);
-
- *out_checksum =
- static_cast<unsigned int>(file_.get()) * kMultiplier + kIncrement;
-}
-
-void File::MemoryCheckingScopedFD::Check() const {
- unsigned int computed_checksum;
- ComputeMemoryChecksum(&computed_checksum);
- CHECK_EQ(file_memory_checksum_, computed_checksum) << "corrupted fd memory";
-}
-
-void File::MemoryCheckingScopedFD::UpdateChecksum() {
- ComputeMemoryChecksum(&file_memory_checksum_);
-}
-
// NaCl doesn't implement system calls to open files directly.
#if !defined(OS_NACL)
// TODO(erikkay): does it make sense to support FLAG_EXCLUSIVE_* here?
-void File::DoInitialize(uint32 flags) {
+void File::DoInitialize(const FilePath& path, uint32_t flags) {
ThreadRestrictions::AssertIOAllowed();
DCHECK(!IsValid());
@@ -516,14 +475,14 @@ void File::DoInitialize(uint32 flags) {
else if (flags & FLAG_APPEND)
open_flags |= O_APPEND | O_WRONLY;
- COMPILE_ASSERT(O_RDONLY == 0, O_RDONLY_must_equal_zero);
+ static_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(path_.value().c_str(), open_flags, mode));
+ int descriptor = HANDLE_EINTR(open(path.value().c_str(), open_flags, mode));
if (flags & FLAG_OPEN_ALWAYS) {
if (descriptor < 0) {
@@ -531,7 +490,7 @@ void File::DoInitialize(uint32 flags) {
if (flags & FLAG_EXCLUSIVE_READ || flags & FLAG_EXCLUSIVE_WRITE)
open_flags |= O_EXCL; // together with O_CREAT implies O_NOFOLLOW
- descriptor = HANDLE_EINTR(open(path_.value().c_str(), open_flags, mode));
+ descriptor = HANDLE_EINTR(open(path.value().c_str(), open_flags, mode));
if (descriptor >= 0)
created_ = true;
}
@@ -546,7 +505,7 @@ void File::DoInitialize(uint32 flags) {
created_ = true;
if (flags & FLAG_DELETE_ON_CLOSE)
- unlink(path_.value().c_str());
+ unlink(path.value().c_str());
async_ = ((flags & FLAG_ASYNC) == FLAG_ASYNC);
error_details_ = FILE_OK;
diff --git a/base/files/file_tracing.cc b/base/files/file_tracing.cc
index c25772db8a..6d11cbc746 100644
--- a/base/files/file_tracing.cc
+++ b/base/files/file_tracing.cc
@@ -13,6 +13,11 @@ FileTracing::Provider* g_provider = nullptr;
}
// static
+bool FileTracing::IsCategoryEnabled() {
+ return g_provider && g_provider->FileTracingCategoryIsEnabled();
+}
+
+// static
void FileTracing::SetProvider(FileTracing::Provider* provider) {
g_provider = provider;
}
@@ -34,19 +39,12 @@ FileTracing::ScopedTrace::~ScopedTrace() {
g_provider->FileTracingEventEnd(name_, id_);
}
-bool FileTracing::ScopedTrace::ShouldInitialize() const {
- return g_provider && g_provider->FileTracingCategoryIsEnabled();
-}
-
-void FileTracing::ScopedTrace::Initialize(
- const char* name, File* file, int64 size) {
- if (!g_provider)
- return;
-
+void FileTracing::ScopedTrace::Initialize(const char* name,
+ File* file,
+ int64_t size) {
id_ = &file->trace_enabler_;
name_ = name;
-
- g_provider->FileTracingEventBegin(name_, id_, file->path_, size);
+ g_provider->FileTracingEventBegin(name_, id_, file->tracing_path_, size);
}
} // namespace base
diff --git a/base/files/file_tracing.h b/base/files/file_tracing.h
index aca1ff7546..bedd7be64b 100644
--- a/base/files/file_tracing.h
+++ b/base/files/file_tracing.h
@@ -5,15 +5,16 @@
#ifndef BASE_FILES_FILE_TRACING_H_
#define BASE_FILES_FILE_TRACING_H_
+#include <stdint.h>
+
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/macros.h"
#define FILE_TRACING_PREFIX "File"
#define SCOPED_FILE_TRACE_WITH_SIZE(name, size) \
FileTracing::ScopedTrace scoped_file_trace; \
- if (scoped_file_trace.ShouldInitialize()) \
+ if (FileTracing::IsCategoryEnabled()) \
scoped_file_trace.Initialize(FILE_TRACING_PREFIX "::" name, this, size)
#define SCOPED_FILE_TRACE(name) SCOPED_FILE_TRACE_WITH_SIZE(name, 0)
@@ -25,6 +26,9 @@ class FilePath;
class BASE_EXPORT FileTracing {
public:
+ // Whether the file tracing category is enabled.
+ static bool IsCategoryEnabled();
+
class Provider {
public:
virtual ~Provider() = default;
@@ -41,8 +45,10 @@ class BASE_EXPORT FileTracing {
// Begins an event for |id| with |name|. |path| tells where in the directory
// structure the event is happening (and may be blank). |size| is the number
// of bytes involved in the event.
- virtual void FileTracingEventBegin(
- const char* name, void* id, const FilePath& path, int64 size) = 0;
+ virtual void FileTracingEventBegin(const char* name,
+ void* id,
+ const FilePath& path,
+ int64_t size) = 0;
// Ends an event for |id| with |name|.
virtual void FileTracingEventEnd(const char* name, void* id) = 0;
@@ -63,14 +69,11 @@ class BASE_EXPORT FileTracing {
ScopedTrace();
~ScopedTrace();
- // Whether this trace should be initialized or not.
- bool ShouldInitialize() const;
-
// Called only if the tracing category is enabled. |name| is the name of the
// event to trace (e.g. "Read", "Write") and must have an application
// lifetime (e.g. static or literal). |file| is the file being traced; must
// outlive this class. |size| is the size (in bytes) of this event.
- void Initialize(const char* name, File* file, int64 size);
+ void Initialize(const char* name, File* file, int64_t size);
private:
// The ID of this trace. Based on the |file| passed to |Initialize()|. Must
diff --git a/base/files/file_unittest.cc b/base/files/file_unittest.cc
index 5c594242bc..2445f7e128 100644
--- a/base/files/file_unittest.cc
+++ b/base/files/file_unittest.cc
@@ -3,10 +3,15 @@
// found in the LICENSE file.
#include "base/files/file.h"
+
+#include <stdint.h>
+
+#include <utility>
+
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
-#include "base/memory/scoped_ptr.h"
#include "base/time/time.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::File;
@@ -200,7 +205,7 @@ TEST(FileTest, ReadWrite) {
EXPECT_EQ(kPartialWriteLength, bytes_written);
// Make sure the file was extended.
- int64 file_size = 0;
+ int64_t file_size = 0;
EXPECT_TRUE(GetFileSize(file_path, &file_size));
EXPECT_EQ(kOffsetBeyondEndOfFile + kPartialWriteLength, file_size);
@@ -241,7 +246,7 @@ TEST(FileTest, Append) {
ASSERT_TRUE(file2.IsValid());
// Test passing the file around.
- file = file2.Pass();
+ file = std::move(file2);
EXPECT_FALSE(file2.IsValid());
ASSERT_TRUE(file.IsValid());
@@ -282,7 +287,7 @@ TEST(FileTest, Length) {
// Extend the file.
const int kExtendedFileLength = 10;
- int64 file_size = 0;
+ int64_t file_size = 0;
EXPECT_TRUE(file.SetLength(kExtendedFileLength));
EXPECT_EQ(kExtendedFileLength, file.GetLength());
EXPECT_TRUE(GetFileSize(file_path, &file_size));
@@ -435,7 +440,7 @@ TEST(FileTest, Seek) {
base::File::FLAG_WRITE);
ASSERT_TRUE(file.IsValid());
- const int64 kOffset = 10;
+ const int64_t kOffset = 10;
EXPECT_EQ(kOffset, file.Seek(base::File::FROM_BEGIN, kOffset));
EXPECT_EQ(2 * kOffset, file.Seek(base::File::FROM_CURRENT, kOffset));
EXPECT_EQ(kOffset, file.Seek(base::File::FROM_CURRENT, -kOffset));
@@ -495,7 +500,7 @@ TEST(FileTest, GetInfoForDirectory) {
base::File dir(
::CreateFile(empty_dir.value().c_str(),
- FILE_ALL_ACCESS,
+ GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
@@ -510,71 +515,3 @@ TEST(FileTest, GetInfoForDirectory) {
EXPECT_EQ(0, info.size);
}
#endif // defined(OS_WIN)
-
-#if defined(OS_POSIX) && defined(GTEST_HAS_DEATH_TEST)
-TEST(FileTest, MemoryCorruption) {
- {
- // Test that changing the checksum value is detected.
- base::File file;
- EXPECT_NE(file.file_.file_memory_checksum_,
- implicit_cast<unsigned int>(file.GetPlatformFile()));
- file.file_.file_memory_checksum_ = file.GetPlatformFile();
- EXPECT_DEATH(file.IsValid(), "");
-
- file.file_.UpdateChecksum(); // Do not crash on File::~File().
- }
-
- {
- // Test that changing the file descriptor value is detected.
- base::File file;
- file.file_.file_.reset(17);
- EXPECT_DEATH(file.IsValid(), "");
-
- // Do not crash on File::~File().
- ignore_result(file.file_.file_.release());
- file.file_.UpdateChecksum();
- }
-
- {
- // Test that GetPlatformFile() checks for corruption.
- base::File file;
- file.file_.file_memory_checksum_ = file.GetPlatformFile();
- EXPECT_DEATH(file.GetPlatformFile(), "");
-
- file.file_.UpdateChecksum(); // Do not crash on File::~File().
- }
-
- {
- // Test that the base::File destructor checks for corruption.
- scoped_ptr<base::File> file(new File());
- file->file_.file_memory_checksum_ = file->GetPlatformFile();
- EXPECT_DEATH(file.reset(), "");
-
- // Do not crash on this thread's destructor call.
- file->file_.UpdateChecksum();
- }
-
- {
- // Test that the base::File constructor checks for corruption.
- base::File file;
- file.file_.file_memory_checksum_ = file.GetPlatformFile();
- EXPECT_DEATH(File f(file.Pass()), "");
-
- file.file_.UpdateChecksum(); // Do not crash on File::~File().
- }
-
- {
- // Test that doing IO checks for corruption.
- base::File file;
- file.file_.file_.reset(17); // A fake open FD value.
-
- EXPECT_DEATH(file.Seek(File::FROM_BEGIN, 0), "");
- EXPECT_DEATH(file.Read(0, NULL, 0), "");
- EXPECT_DEATH(file.ReadAtCurrentPos(NULL, 0), "");
- EXPECT_DEATH(file.Write(0, NULL, 0), "");
-
- ignore_result(file.file_.file_.release());
- file.file_.UpdateChecksum();
- }
-}
-#endif // defined(OS_POSIX)
diff --git a/base/files/file_util.cc b/base/files/file_util.cc
index 4b6b8886d8..9e35b671db 100644
--- a/base/files/file_util.cc
+++ b/base/files/file_util.cc
@@ -19,6 +19,7 @@
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
namespace base {
@@ -34,8 +35,8 @@ static const int kMaxUniqueFiles = 100;
} // namespace
-int64 ComputeDirectorySize(const FilePath& root_path) {
- int64 running_size = 0;
+int64_t ComputeDirectorySize(const FilePath& root_path) {
+ int64_t running_size = 0;
FileEnumerator file_iter(root_path, true, FileEnumerator::FILES);
while (!file_iter.Next().empty())
running_size += file_iter.GetInfo().GetSize();
@@ -185,7 +186,7 @@ bool CreateDirectory(const FilePath& full_path) {
return CreateDirectoryAndGetError(full_path, NULL);
}
-bool GetFileSize(const FilePath& file_path, int64* file_size) {
+bool GetFileSize(const FilePath& file_path, int64_t* file_size) {
File::Info info;
if (!GetFileInfo(file_path, &info))
return false;
diff --git a/base/files/file_util.h b/base/files/file_util.h
index 7f169f1c54..dfc10a35bf 100644
--- a/base/files/file_util.h
+++ b/base/files/file_util.h
@@ -8,15 +8,8 @@
#ifndef BASE_FILES_FILE_UTIL_H_
#define BASE_FILES_FILE_UTIL_H_
-#include "build/build_config.h"
-
-#if defined(OS_WIN)
-#include <windows.h>
-#elif defined(OS_POSIX)
-#include <sys/stat.h>
-#include <unistd.h>
-#endif
-
+#include <stddef.h>
+#include <stdint.h>
#include <stdio.h>
#include <set>
@@ -24,11 +17,18 @@
#include <vector>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/string16.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#elif defined(OS_POSIX)
+#include <sys/stat.h>
+#include <unistd.h>
+#endif
#if defined(OS_POSIX)
#include "base/file_descriptor_posix.h"
@@ -53,7 +53,7 @@ BASE_EXPORT FilePath MakeAbsoluteFilePath(const FilePath& input);
//
// 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);
+BASE_EXPORT int64_t 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
@@ -265,7 +265,7 @@ BASE_EXPORT bool CreateDirectoryAndGetError(const FilePath& full_path,
BASE_EXPORT bool CreateDirectory(const FilePath& full_path);
// Returns the file size. Returns true on success.
-BASE_EXPORT bool GetFileSize(const FilePath& file_path, int64* file_size);
+BASE_EXPORT bool GetFileSize(const FilePath& file_path, int64_t* file_size);
// Sets |real_path| to |path| with symbolic links and junctions expanded.
// On windows, make sure the path starts with a lettered drive.
@@ -350,6 +350,11 @@ BASE_EXPORT bool SetCurrentDirectory(const FilePath& path);
BASE_EXPORT int GetUniquePathNumber(const FilePath& path,
const FilePath::StringType& suffix);
+// Sets the given |fd| to non-blocking mode.
+// Returns true if it was able to set it in the non-blocking mode, otherwise
+// false.
+BASE_EXPORT bool SetNonBlocking(int fd);
+
#if defined(OS_POSIX)
// Test that |path| can only be changed by a given user and members of
// a given set of groups.
diff --git a/base/files/file_util_mac.mm b/base/files/file_util_mac.mm
index a701bad928..e9c6c65159 100644
--- a/base/files/file_util_mac.mm
+++ b/base/files/file_util_mac.mm
@@ -7,7 +7,6 @@
#include <copyfile.h>
#import <Foundation/Foundation.h>
-#include "base/basictypes.h"
#include "base/files/file_path.h"
#include "base/mac/foundation_util.h"
#include "base/strings/string_util.h"
diff --git a/base/files/file_util_posix.cc b/base/files/file_util_posix.cc
index f70a82f241..e2e44465e5 100644
--- a/base/files/file_util_posix.cc
+++ b/base/files/file_util_posix.cc
@@ -9,6 +9,7 @@
#include <fcntl.h>
#include <libgen.h>
#include <limits.h>
+#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -21,18 +22,11 @@
#include <time.h>
#include <unistd.h>
-#if defined(OS_MACOSX)
-#include <AvailabilityMacros.h>
-#include "base/mac/foundation_util.h"
-#elif !defined(OS_CHROMEOS) && defined(USE_GLIB)
-#include <glib.h> // for g_get_home_dir()
-#endif
-
-#include "base/basictypes.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_path.h"
#include "base/files/scoped_file.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/singleton.h"
#include "base/posix/eintr_wrapper.h"
@@ -44,6 +38,12 @@
#include "base/sys_info.h"
#include "base/threading/thread_restrictions.h"
#include "base/time/time.h"
+#include "build/build_config.h"
+
+#if defined(OS_MACOSX)
+#include <AvailabilityMacros.h>
+#include "base/mac/foundation_util.h"
+#endif
#if defined(OS_ANDROID)
#include "base/android/content_uri_utils.h"
@@ -350,6 +350,17 @@ bool CopyDirectory(const FilePath& from_path,
}
#endif // !defined(OS_NACL_NONSFI)
+bool SetNonBlocking(int fd) {
+ int flags = fcntl(fd, F_GETFL, 0);
+ if (flags == -1)
+ return false;
+ if (flags & O_NONBLOCK)
+ return true;
+ if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
+ return false;
+ return true;
+}
+
bool PathExists(const FilePath& path) {
ThreadRestrictions::AssertIOAllowed();
#if defined(OS_ANDROID)
@@ -480,16 +491,6 @@ FilePath GetHomeDir() {
#if defined(OS_ANDROID)
DLOG(WARNING) << "OS_ANDROID: Home directory lookup not yet implemented.";
-#elif defined(USE_GLIB) && !defined(OS_CHROMEOS)
- // g_get_home_dir calls getpwent, which can fall through to LDAP calls so
- // this may do I/O. However, it should be rare that $HOME is not defined and
- // this is typically called from the path service which has no threading
- // restrictions. The path service will cache the result which limits the
- // badness of blocking on I/O. As a result, we don't have a thread
- // restriction here.
- home_dir = g_get_home_dir();
- if (home_dir && home_dir[0])
- return FilePath(home_dir);
#endif
FilePath rv;
diff --git a/base/files/important_file_writer.cc b/base/files/important_file_writer.cc
index 814fc7b9ad..b4293053a6 100644
--- a/base/files/important_file_writer.cc
+++ b/base/files/important_file_writer.cc
@@ -4,9 +4,11 @@
#include "base/files/important_file_writer.h"
+#include <stddef.h>
+#include <stdint.h>
#include <stdio.h>
-
#include <string>
+#include <utility>
#include "base/bind.h"
#include "base/critical_closure.h"
@@ -15,13 +17,16 @@
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/metrics/histogram.h"
+#include "base/numerics/safe_conversions.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/task_runner.h"
#include "base/task_runner_util.h"
#include "base/threading/thread.h"
#include "base/time/time.h"
+#include "build/build_config.h"
namespace base {
@@ -47,8 +52,7 @@ 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;
+ DPLOG(WARNING) << "temp file failure: " << path.value() << " : " << message;
}
// Helper function to call WriteFileAtomically() with a scoped_ptr<std::string>.
@@ -72,16 +76,16 @@ bool ImportantFileWriter::WriteFileAtomically(const FilePath& path,
char path[128];
} file_info;
file_info.data_size = data.size();
- base::strlcpy(file_info.path, path.value().c_str(),
- arraysize(file_info.path));
- base::debug::Alias(&file_info);
+ strlcpy(file_info.path, path.value().c_str(), arraysize(file_info.path));
+ debug::Alias(&file_info);
#endif
+
// 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 (!base::CreateTemporaryFileInDir(path.DirName(), &tmp_file_path)) {
+ if (!CreateTemporaryFileInDir(path.DirName(), &tmp_file_path)) {
LogFailure(path, FAILED_CREATING, "could not create temporary file");
return false;
}
@@ -92,29 +96,28 @@ bool ImportantFileWriter::WriteFileAtomically(const FilePath& path,
return false;
}
- // If this happens in the wild something really bad is going on.
- CHECK_LE(data.length(), static_cast<size_t>(kint32max));
- int bytes_written = tmp_file.Write(0, data.data(),
- static_cast<int>(data.length()));
+ // If this fails in the wild, something really bad is going on.
+ const int data_length = checked_cast<int32_t>(data.length());
+ int bytes_written = tmp_file.Write(0, data.data(), data_length);
bool flush_success = tmp_file.Flush();
tmp_file.Close();
- if (bytes_written < static_cast<int>(data.length())) {
+ if (bytes_written < data_length) {
LogFailure(path, FAILED_WRITING, "error writing, bytes_written=" +
IntToString(bytes_written));
- base::DeleteFile(tmp_file_path, false);
+ DeleteFile(tmp_file_path, false);
return false;
}
if (!flush_success) {
LogFailure(path, FAILED_FLUSHING, "error flushing");
- base::DeleteFile(tmp_file_path, false);
+ DeleteFile(tmp_file_path, false);
return false;
}
- if (!base::ReplaceFile(tmp_file_path, path, NULL)) {
+ if (!ReplaceFile(tmp_file_path, path, nullptr)) {
LogFailure(path, FAILED_RENAMING, "could not rename temporary file");
- base::DeleteFile(tmp_file_path, false);
+ DeleteFile(tmp_file_path, false);
return false;
}
@@ -123,11 +126,21 @@ bool ImportantFileWriter::WriteFileAtomically(const FilePath& path,
ImportantFileWriter::ImportantFileWriter(
const FilePath& path,
- const scoped_refptr<base::SequencedTaskRunner>& task_runner)
+ const scoped_refptr<SequencedTaskRunner>& task_runner)
+ : ImportantFileWriter(
+ path,
+ task_runner,
+ TimeDelta::FromMilliseconds(kDefaultCommitIntervalMs)) {
+}
+
+ImportantFileWriter::ImportantFileWriter(
+ const FilePath& path,
+ const scoped_refptr<SequencedTaskRunner>& task_runner,
+ TimeDelta interval)
: path_(path),
task_runner_(task_runner),
- serializer_(NULL),
- commit_interval_(TimeDelta::FromMilliseconds(kDefaultCommitIntervalMs)),
+ serializer_(nullptr),
+ commit_interval_(interval),
weak_factory_(this) {
DCHECK(CalledOnValidThread());
DCHECK(task_runner_);
@@ -147,7 +160,7 @@ bool ImportantFileWriter::HasPendingWrite() const {
void ImportantFileWriter::WriteNow(scoped_ptr<std::string> data) {
DCHECK(CalledOnValidThread());
- if (data->length() > static_cast<size_t>(kint32max)) {
+ if (!IsValueInRangeForNumericType<int32_t>(data->length())) {
NOTREACHED();
return;
}
@@ -182,16 +195,16 @@ void ImportantFileWriter::DoScheduledWrite() {
DCHECK(serializer_);
scoped_ptr<std::string> data(new std::string);
if (serializer_->SerializeData(data.get())) {
- WriteNow(data.Pass());
+ WriteNow(std::move(data));
} else {
DLOG(WARNING) << "failed to serialize data to be saved in "
- << path_.value().c_str();
+ << path_.value();
}
- serializer_ = NULL;
+ serializer_ = nullptr;
}
void ImportantFileWriter::RegisterOnNextSuccessfulWriteCallback(
- const base::Closure& on_next_successful_write) {
+ const Closure& on_next_successful_write) {
DCHECK(on_next_successful_write_.is_null());
on_next_successful_write_ = on_next_successful_write;
}
@@ -203,7 +216,7 @@ bool ImportantFileWriter::PostWriteTask(const Callback<bool()>& task) {
// suppressing all of those is unrealistic hence we avoid most of them by
// using PostTask() in the typical scenario below.
if (!on_next_successful_write_.is_null()) {
- return base::PostTaskAndReplyWithResult(
+ return PostTaskAndReplyWithResult(
task_runner_.get(),
FROM_HERE,
MakeCriticalClosure(task),
@@ -212,7 +225,7 @@ bool ImportantFileWriter::PostWriteTask(const Callback<bool()>& task) {
}
return task_runner_->PostTask(
FROM_HERE,
- MakeCriticalClosure(base::Bind(IgnoreResult(task))));
+ MakeCriticalClosure(Bind(IgnoreResult(task))));
}
void ImportantFileWriter::ForwardSuccessfulWrite(bool result) {
diff --git a/base/files/important_file_writer.h b/base/files/important_file_writer.h
index 99f1a7c681..1b2ad5caed 100644
--- a/base/files/important_file_writer.h
+++ b/base/files/important_file_writer.h
@@ -8,9 +8,9 @@
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/callback.h"
#include "base/files/file_path.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/threading/non_thread_safe.h"
#include "base/time/time.h"
@@ -62,9 +62,13 @@ class BASE_EXPORT ImportantFileWriter : public NonThreadSafe {
// |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,
- const scoped_refptr<base::SequencedTaskRunner>& task_runner);
+ ImportantFileWriter(const FilePath& path,
+ const scoped_refptr<SequencedTaskRunner>& task_runner);
+
+ // Same as above, but with a custom commit interval.
+ ImportantFileWriter(const FilePath& path,
+ const scoped_refptr<SequencedTaskRunner>& task_runner,
+ TimeDelta interval);
// You have to ensure that there are no pending writes at the moment
// of destruction.
@@ -77,7 +81,7 @@ class BASE_EXPORT ImportantFileWriter : public NonThreadSafe {
bool HasPendingWrite() const;
// Save |data| to target filename. Does not block. If there is a pending write
- // scheduled by ScheduleWrite, it is cancelled.
+ // scheduled by ScheduleWrite(), it is cancelled.
void WriteNow(scoped_ptr<std::string> data);
// Schedule a save to target filename. Data will be serialized and saved
@@ -94,16 +98,12 @@ class BASE_EXPORT ImportantFileWriter : public NonThreadSafe {
// Registers |on_next_successful_write| to be called once, on the next
// successful write event. Only one callback can be set at once.
void RegisterOnNextSuccessfulWriteCallback(
- const base::Closure& on_next_successful_write);
+ const Closure& on_next_successful_write);
TimeDelta commit_interval() const {
return commit_interval_;
}
- void set_commit_interval(const TimeDelta& interval) {
- commit_interval_ = interval;
- }
-
private:
// Helper method for WriteNow().
bool PostWriteTask(const Callback<bool()>& task);
@@ -113,22 +113,22 @@ class BASE_EXPORT ImportantFileWriter : public NonThreadSafe {
void ForwardSuccessfulWrite(bool result);
// Invoked once and then reset on the next successful write event.
- base::Closure on_next_successful_write_;
+ Closure on_next_successful_write_;
// Path being written to.
const FilePath path_;
// TaskRunner for the thread on which file I/O can be done.
- const scoped_refptr<base::SequencedTaskRunner> task_runner_;
+ const scoped_refptr<SequencedTaskRunner> task_runner_;
// Timer used to schedule commit after ScheduleWrite.
- OneShotTimer<ImportantFileWriter> timer_;
+ 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_;
+ const TimeDelta commit_interval_;
WeakPtrFactory<ImportantFileWriter> weak_factory_;
diff --git a/base/files/important_file_writer_unittest.cc b/base/files/important_file_writer_unittest.cc
index d376cdc35a..28e6001a00 100644
--- a/base/files/important_file_writer_unittest.cc
+++ b/base/files/important_file_writer_unittest.cc
@@ -11,6 +11,7 @@
#include "base/files/scoped_temp_dir.h"
#include "base/location.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/thread_task_runner_handle.h"
@@ -145,8 +146,9 @@ TEST_F(ImportantFileWriterTest, BasicWithSuccessfulWriteObserver) {
}
TEST_F(ImportantFileWriterTest, ScheduleWrite) {
- ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get());
- writer.set_commit_interval(TimeDelta::FromMilliseconds(25));
+ ImportantFileWriter writer(file_,
+ ThreadTaskRunnerHandle::Get(),
+ TimeDelta::FromMilliseconds(25));
EXPECT_FALSE(writer.HasPendingWrite());
DataSerializer serializer("foo");
writer.ScheduleWrite(&serializer);
@@ -177,8 +179,9 @@ TEST_F(ImportantFileWriterTest, DoScheduledWrite) {
}
TEST_F(ImportantFileWriterTest, BatchingWrites) {
- ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get());
- writer.set_commit_interval(TimeDelta::FromMilliseconds(25));
+ ImportantFileWriter writer(file_,
+ ThreadTaskRunnerHandle::Get(),
+ TimeDelta::FromMilliseconds(25));
DataSerializer foo("foo"), bar("bar"), baz("baz");
writer.ScheduleWrite(&foo);
writer.ScheduleWrite(&bar);
diff --git a/base/files/memory_mapped_file.h b/base/files/memory_mapped_file.h
index 96d1d91f93..6362e765cb 100644
--- a/base/files/memory_mapped_file.h
+++ b/base/files/memory_mapped_file.h
@@ -5,9 +5,12 @@
#ifndef BASE_FILES_MEMORY_MAPPED_FILE_H_
#define BASE_FILES_MEMORY_MAPPED_FILE_H_
+#include <stddef.h>
+#include <stdint.h>
+
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/files/file.h"
+#include "base/macros.h"
#include "build/build_config.h"
#if defined(OS_WIN)
@@ -28,21 +31,14 @@ class BASE_EXPORT MemoryMappedFile {
struct BASE_EXPORT Region {
static const Region kWholeFile;
- Region();
- Region(int64 offset, int64 size);
-
bool operator==(const Region& other) const;
bool operator!=(const Region& other) const;
// Start of the region (measured in bytes from the beginning of the file).
- int64 offset;
+ int64_t offset;
// Length of the region in bytes.
- int64 size;
-
- private:
- // Used by kWholeFile.
- Region(base::LinkerInitialized);
+ int64_t size;
};
// Opens an existing file and maps it into memory. Access is restricted to
@@ -65,7 +61,7 @@ class BASE_EXPORT MemoryMappedFile {
bool InitializeAsImageSection(const FilePath& file_name);
#endif // OS_WIN
- const uint8* data() const { return data_; }
+ const uint8_t* data() const { return data_; }
size_t length() const { return length_; }
// Is file_ a valid file handle that points to an open, memory mapped file?
@@ -78,11 +74,11 @@ class BASE_EXPORT MemoryMappedFile {
// - |aligned_start| is page aligned and <= |start|.
// - |aligned_size| is a multiple of the VM granularity and >= |size|.
// - |offset| is the displacement of |start| w.r.t |aligned_start|.
- static void CalculateVMAlignedBoundaries(int64 start,
- int64 size,
- int64* aligned_start,
- int64* aligned_size,
- int32* offset);
+ static void CalculateVMAlignedBoundaries(int64_t start,
+ int64_t size,
+ int64_t* aligned_start,
+ int64_t* aligned_size,
+ int32_t* offset);
// 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().
@@ -92,7 +88,7 @@ class BASE_EXPORT MemoryMappedFile {
void CloseHandles();
File file_;
- uint8* data_;
+ uint8_t* data_;
size_t length_;
#if defined(OS_WIN)
diff --git a/base/files/scoped_file.cc b/base/files/scoped_file.cc
index 39f064de1c..8971280776 100644
--- a/base/files/scoped_file.cc
+++ b/base/files/scoped_file.cc
@@ -5,6 +5,7 @@
#include "base/files/scoped_file.h"
#include "base/logging.h"
+#include "build/build_config.h"
#if defined(OS_POSIX)
#include <unistd.h>
diff --git a/base/files/scoped_temp_dir.h b/base/files/scoped_temp_dir.h
index 5f63e09cff..b1f2f5b874 100644
--- a/base/files/scoped_temp_dir.h
+++ b/base/files/scoped_temp_dir.h
@@ -17,6 +17,7 @@
#include "base/base_export.h"
#include "base/files/file_path.h"
+#include "base/macros.h"
namespace base {
diff --git a/base/files/scoped_temp_dir_unittest.cc b/base/files/scoped_temp_dir_unittest.cc
index a19f34ddce..3b2f28e50e 100644
--- a/base/files/scoped_temp_dir_unittest.cc
+++ b/base/files/scoped_temp_dir_unittest.cc
@@ -7,6 +7,7 @@
#include "base/files/file.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
diff --git a/base/format_macros.h b/base/format_macros.h
index d58658d2b9..0697c6ddf2 100644
--- a/base/format_macros.h
+++ b/base/format_macros.h
@@ -21,6 +21,9 @@
// printf("xyz: %" PRIuS, size);
// The "u" in the macro corresponds to %u, and S is for "size".
+#include <stddef.h>
+#include <stdint.h>
+
#include "build/build_config.h"
#if defined(OS_POSIX) && (defined(_INTTYPES_H) || defined(_INTTYPES_H_)) && \
diff --git a/base/guid.cc b/base/guid.cc
index be5c58b535..99b037bcfa 100644
--- a/base/guid.cc
+++ b/base/guid.cc
@@ -4,6 +4,8 @@
#include "base/guid.h"
+#include <stddef.h>
+
#include "base/strings/string_util.h"
namespace base {
diff --git a/base/guid.h b/base/guid.h
index abcc589f72..c0a06f8858 100644
--- a/base/guid.h
+++ b/base/guid.h
@@ -5,10 +5,11 @@
#ifndef BASE_GUID_H_
#define BASE_GUID_H_
+#include <stdint.h>
+
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "build/build_config.h"
namespace base {
@@ -24,7 +25,7 @@ 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]);
+BASE_EXPORT std::string RandomDataToGUIDString(const uint64_t bytes[2]);
#endif
} // namespace base
diff --git a/base/guid_posix.cc b/base/guid_posix.cc
index f0fedc27e5..ec1ca515d3 100644
--- a/base/guid_posix.cc
+++ b/base/guid_posix.cc
@@ -4,13 +4,15 @@
#include "base/guid.h"
+#include <stdint.h>
+
#include "base/rand_util.h"
#include "base/strings/stringprintf.h"
namespace base {
std::string GenerateGUID() {
- uint64 sixteen_bytes[2] = { base::RandUint64(), base::RandUint64() };
+ uint64_t sixteen_bytes[2] = {base::RandUint64(), base::RandUint64()};
// Set the GUID to version 4 as described in RFC 4122, section 4.4.
// The format of GUID version 4 must be xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx,
@@ -30,7 +32,7 @@ std::string GenerateGUID() {
// TODO(cmasone): Once we're comfortable this works, migrate Windows code to
// use this as well.
-std::string RandomDataToGUIDString(const uint64 bytes[2]) {
+std::string RandomDataToGUIDString(const uint64_t bytes[2]) {
return StringPrintf("%08X-%04X-%04X-%04X-%012llX",
static_cast<unsigned int>(bytes[0] >> 32),
static_cast<unsigned int>((bytes[0] >> 16) & 0x0000ffff),
diff --git a/base/guid_unittest.cc b/base/guid_unittest.cc
index 1485497155..b6d976d8e0 100644
--- a/base/guid_unittest.cc
+++ b/base/guid_unittest.cc
@@ -4,9 +4,12 @@
#include "base/guid.h"
+#include <stdint.h>
+
#include <limits>
#include "base/strings/string_util.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
@@ -26,13 +29,13 @@ bool IsGUIDv4(const std::string& guid) {
} // namespace
TEST(GUIDTest, GUIDGeneratesAllZeroes) {
- uint64 bytes[] = { 0, 0 };
+ uint64_t bytes[] = {0, 0};
std::string clientid = RandomDataToGUIDString(bytes);
EXPECT_EQ("00000000-0000-0000-0000-000000000000", clientid);
}
TEST(GUIDTest, GUIDGeneratesCorrectly) {
- uint64 bytes[] = { 0x0123456789ABCDEFULL, 0xFEDCBA9876543210ULL };
+ uint64_t bytes[] = {0x0123456789ABCDEFULL, 0xFEDCBA9876543210ULL};
std::string clientid = RandomDataToGUIDString(bytes);
EXPECT_EQ("01234567-89AB-CDEF-FEDC-BA9876543210", clientid);
}
@@ -43,8 +46,8 @@ TEST(GUIDTest, GUIDCorrectlyFormatted) {
for (int it = 0; it < kIterations; ++it) {
std::string guid = GenerateGUID();
EXPECT_TRUE(IsValidGUID(guid));
- EXPECT_TRUE(IsValidGUID(StringToLowerASCII(guid)));
- EXPECT_TRUE(IsValidGUID(StringToUpperASCII(guid)));
+ EXPECT_TRUE(IsValidGUID(ToLowerASCII(guid)));
+ EXPECT_TRUE(IsValidGUID(ToUpperASCII(guid)));
}
}
diff --git a/base/id_map.h b/base/id_map.h
index 852c138047..15c6662309 100644
--- a/base/id_map.h
+++ b/base/id_map.h
@@ -5,12 +5,14 @@
#ifndef BASE_ID_MAP_H_
#define BASE_ID_MAP_H_
+#include <stddef.h>
+#include <stdint.h>
#include <set>
-#include "base/basictypes.h"
#include "base/containers/hash_tables.h"
#include "base/logging.h"
-#include "base/threading/non_thread_safe.h"
+#include "base/macros.h"
+#include "base/sequence_checker.h"
// Ownership semantics - own pointer means the pointer is deleted in Remove()
// & during destruction
@@ -30,26 +32,30 @@ enum IDMapOwnershipSemantics {
//
// 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<typename T, IDMapOwnershipSemantics OS = IDMapExternalPointer>
-class IDMap : public base::NonThreadSafe {
+template <typename T,
+ IDMapOwnershipSemantics OS = IDMapExternalPointer,
+ typename K = int32_t>
+class IDMap {
public:
- typedef int32 KeyType;
+ using KeyType = K;
private:
typedef base::hash_map<KeyType, T*> 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();
+ // A number of consumers of IDMap create it on one thread but always
+ // access it from a different, but consistent, thread (or sequence)
+ // post-construction. The first call to CalledOnValidSequencedThread()
+ // will re-bind it.
+ sequence_checker_.DetachFromSequence();
}
~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();
+ // Many IDMap's are static, and hence will be destroyed on the main
+ // thread. However, all the accesses may take place on another thread (or
+ // sequence), such as the IO thread. Detaching again to clean this up.
+ sequence_checker_.DetachFromSequence();
Releaser<OS, 0>::release_all(&data_);
}
@@ -59,7 +65,7 @@ class IDMap : public base::NonThreadSafe {
// Adds a view with an automatically generated unique ID. See AddWithID.
KeyType Add(T* data) {
- DCHECK(CalledOnValidThread());
+ DCHECK(sequence_checker_.CalledOnValidSequencedThread());
DCHECK(!check_on_null_data_ || data);
KeyType this_id = next_id_;
DCHECK(data_.find(this_id) == data_.end()) << "Inserting duplicate item";
@@ -73,14 +79,14 @@ class IDMap : public base::NonThreadSafe {
// 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());
+ DCHECK(sequence_checker_.CalledOnValidSequencedThread());
DCHECK(!check_on_null_data_ || data);
DCHECK(data_.find(id) == data_.end()) << "Inserting duplicate item";
data_[id] = data;
}
void Remove(KeyType id) {
- DCHECK(CalledOnValidThread());
+ DCHECK(sequence_checker_.CalledOnValidSequencedThread());
typename HashTable::iterator i = data_.find(id);
if (i == data_.end()) {
NOTREACHED() << "Attempting to remove an item not in the list";
@@ -101,7 +107,7 @@ class IDMap : public base::NonThreadSafe {
// how the existing value is treated, the IDMap does not delete the existing
// value being replaced.
T* Replace(KeyType id, T* new_data) {
- DCHECK(CalledOnValidThread());
+ DCHECK(sequence_checker_.CalledOnValidSequencedThread());
DCHECK(!check_on_null_data_ || new_data);
typename HashTable::iterator i = data_.find(id);
if (i == data_.end()) {
@@ -115,7 +121,7 @@ class IDMap : public base::NonThreadSafe {
}
void Clear() {
- DCHECK(CalledOnValidThread());
+ DCHECK(sequence_checker_.CalledOnValidSequencedThread());
if (iteration_depth_ == 0) {
Releaser<OS, 0>::release_all(&data_);
} else {
@@ -126,12 +132,12 @@ class IDMap : public base::NonThreadSafe {
}
bool IsEmpty() const {
- DCHECK(CalledOnValidThread());
+ DCHECK(sequence_checker_.CalledOnValidSequencedThread());
return size() == 0u;
}
T* Lookup(KeyType id) const {
- DCHECK(CalledOnValidThread());
+ DCHECK(sequence_checker_.CalledOnValidSequencedThread());
typename HashTable::const_iterator i = data_.find(id);
if (i == data_.end())
return NULL;
@@ -139,7 +145,7 @@ class IDMap : public base::NonThreadSafe {
}
size_t size() const {
- DCHECK(CalledOnValidThread());
+ DCHECK(sequence_checker_.CalledOnValidSequencedThread());
return data_.size() - removed_ids_.size();
}
@@ -174,7 +180,7 @@ class IDMap : public base::NonThreadSafe {
}
~Iterator() {
- DCHECK(map_->CalledOnValidThread());
+ DCHECK(map_->sequence_checker_.CalledOnValidSequencedThread());
// We're going to decrement iteration depth. Make sure it's greater than
// zero so that it doesn't become negative.
@@ -185,29 +191,29 @@ class IDMap : public base::NonThreadSafe {
}
bool IsAtEnd() const {
- DCHECK(map_->CalledOnValidThread());
+ DCHECK(map_->sequence_checker_.CalledOnValidSequencedThread());
return iter_ == map_->data_.end();
}
KeyType GetCurrentKey() const {
- DCHECK(map_->CalledOnValidThread());
+ DCHECK(map_->sequence_checker_.CalledOnValidSequencedThread());
return iter_->first;
}
ReturnType* GetCurrentValue() const {
- DCHECK(map_->CalledOnValidThread());
+ DCHECK(map_->sequence_checker_.CalledOnValidSequencedThread());
return iter_->second;
}
void Advance() {
- DCHECK(map_->CalledOnValidThread());
+ DCHECK(map_->sequence_checker_.CalledOnValidSequencedThread());
++iter_;
SkipRemovedEntries();
}
private:
void Init() {
- DCHECK(map_->CalledOnValidThread());
+ DCHECK(map_->sequence_checker_.CalledOnValidSequencedThread());
++map_->iteration_depth_;
SkipRemovedEntries();
}
@@ -249,10 +255,8 @@ class IDMap : public base::NonThreadSafe {
void Compact() {
DCHECK_EQ(0, iteration_depth_);
- for (std::set<KeyType>::const_iterator i = removed_ids_.begin();
- i != removed_ids_.end(); ++i) {
- Remove(*i);
- }
+ for (const auto& i : removed_ids_)
+ Remove(i);
removed_ids_.clear();
}
@@ -273,6 +277,8 @@ class IDMap : public base::NonThreadSafe {
// See description above setter.
bool check_on_null_data_;
+ base::SequenceChecker sequence_checker_;
+
DISALLOW_COPY_AND_ASSIGN(IDMap);
};
diff --git a/base/id_map_unittest.cc b/base/id_map_unittest.cc
index a9fb2b9dec..7a07a28db5 100644
--- a/base/id_map_unittest.cc
+++ b/base/id_map_unittest.cc
@@ -4,6 +4,8 @@
#include "base/id_map.h"
+#include <stdint.h>
+
#include "testing/gtest/include/gtest/gtest.h"
namespace {
@@ -28,12 +30,12 @@ TEST(IDMapTest, Basic) {
TestObject obj1;
TestObject obj2;
- int32 id1 = map.Add(&obj1);
+ int32_t id1 = map.Add(&obj1);
EXPECT_FALSE(map.IsEmpty());
EXPECT_EQ(1U, map.size());
EXPECT_EQ(&obj1, map.Lookup(id1));
- int32 id2 = map.Add(&obj2);
+ int32_t id2 = map.Add(&obj2);
EXPECT_FALSE(map.IsEmpty());
EXPECT_EQ(2U, map.size());
@@ -102,7 +104,7 @@ TEST(IDMapTest, IteratorRemainsValidWhenRemovingOtherElements) {
map.Add(&obj[i]);
// IDMap uses a hash_map, which has no predictable iteration order.
- int32 ids_in_iteration_order[kCount];
+ int32_t ids_in_iteration_order[kCount];
const TestObject* objs_in_iteration_order[kCount];
int counter = 0;
for (IDMap<TestObject>::const_iterator iter(&map);
@@ -212,7 +214,7 @@ TEST(IDMapTest, IteratorRemainsValidWhenClearing) {
map.Add(&obj[i]);
// IDMap uses a hash_map, which has no predictable iteration order.
- int32 ids_in_iteration_order[kCount];
+ int32_t ids_in_iteration_order[kCount];
const TestObject* objs_in_iteration_order[kCount];
int counter = 0;
for (IDMap<TestObject>::const_iterator iter(&map);
@@ -355,4 +357,16 @@ TEST(IDMapTest, OwningPointersDeletesThemOnDestruct) {
EXPECT_EQ(owned_del_count, kCount);
}
+TEST(IDMapTest, Int64KeyType) {
+ IDMap<TestObject, IDMapExternalPointer, int64_t> map;
+ TestObject obj1;
+ const int64_t kId1 = 999999999999999999;
+
+ map.AddWithID(&obj1, kId1);
+ EXPECT_EQ(&obj1, map.Lookup(kId1));
+
+ map.Remove(kId1);
+ EXPECT_TRUE(map.IsEmpty());
+}
+
} // namespace
diff --git a/base/json/BUILD.gn b/base/json/BUILD.gn
deleted file mode 100644
index 70830c15e5..0000000000
--- a/base/json/BUILD.gn
+++ /dev/null
@@ -1,37 +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.
-
-source_set("json") {
- sources = [
- "json_file_value_serializer.cc",
- "json_file_value_serializer.h",
- "json_parser.cc",
- "json_parser.h",
- "json_reader.cc",
- "json_reader.h",
- "json_string_value_serializer.cc",
- "json_string_value_serializer.h",
- "json_value_converter.cc",
- "json_value_converter.h",
- "json_writer.cc",
- "json_writer.h",
- "string_escape.cc",
- "string_escape.h",
- ]
-
- if (is_nacl) {
- sources -= [
- "json_file_value_serializer.cc",
- "json_file_value_serializer.h",
- ]
- }
-
- configs += [ "//base:base_implementation" ]
-
- deps = [
- "//base/memory",
- ]
-
- visibility = [ "//base/*" ]
-}
diff --git a/base/json/json_file_value_serializer.cc b/base/json/json_file_value_serializer.cc
new file mode 100644
index 0000000000..516f8765c4
--- /dev/null
+++ b/base/json/json_file_value_serializer.cc
@@ -0,0 +1,120 @@
+// Copyright (c) 2012 The Chromium Authors. All 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/files/file_util.h"
+#include "base/json/json_string_value_serializer.h"
+#include "base/logging.h"
+#include "build/build_config.h"
+
+using base::FilePath;
+
+const char JSONFileValueDeserializer::kAccessDenied[] = "Access denied.";
+const char JSONFileValueDeserializer::kCannotReadFile[] = "Can't read file.";
+const char JSONFileValueDeserializer::kFileLocked[] = "File locked.";
+const char JSONFileValueDeserializer::kNoSuchFile[] = "File doesn't exist.";
+
+JSONFileValueSerializer::JSONFileValueSerializer(
+ const base::FilePath& json_file_path)
+ : json_file_path_(json_file_path) {
+}
+
+JSONFileValueSerializer::~JSONFileValueSerializer() {
+}
+
+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<int>(json_string.size());
+ if (base::WriteFile(json_file_path_, json_string.data(), data_size) !=
+ data_size)
+ return false;
+
+ return true;
+}
+
+JSONFileValueDeserializer::JSONFileValueDeserializer(
+ const base::FilePath& json_file_path)
+ : json_file_path_(json_file_path),
+ allow_trailing_comma_(false),
+ last_read_size_(0U) {
+}
+
+JSONFileValueDeserializer::~JSONFileValueDeserializer() {
+}
+
+int JSONFileValueDeserializer::ReadFileToString(std::string* json_string) {
+ DCHECK(json_string);
+ if (!base::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;
+ }
+
+ last_read_size_ = json_string->size();
+ return JSON_NO_ERROR;
+}
+
+const char* JSONFileValueDeserializer::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 "";
+ }
+}
+
+scoped_ptr<base::Value> JSONFileValueDeserializer::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;
+ }
+
+ JSONStringValueDeserializer deserializer(json_string);
+ deserializer.set_allow_trailing_comma(allow_trailing_comma_);
+ return deserializer.Deserialize(error_code, error_str);
+}
diff --git a/base/json/json_file_value_serializer.h b/base/json/json_file_value_serializer.h
new file mode 100644
index 0000000000..f6b4e5fc22
--- /dev/null
+++ b/base/json/json_file_value_serializer.h
@@ -0,0 +1,106 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <stddef.h>
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "base/values.h"
+
+class BASE_EXPORT JSONFileValueSerializer : public base::ValueSerializer {
+ public:
+ // |json_file_path_| is the path of a file that will be destination of the
+ // serialization. The serializer will attempt to create the file at the
+ // specified location.
+ explicit JSONFileValueSerializer(const base::FilePath& json_file_path);
+
+ ~JSONFileValueSerializer() override;
+
+ // 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.
+ 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);
+
+ private:
+ bool SerializeInternal(const base::Value& root, bool omit_binary_values);
+
+ const base::FilePath json_file_path_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(JSONFileValueSerializer);
+};
+
+class BASE_EXPORT JSONFileValueDeserializer : public base::ValueDeserializer {
+ public:
+ // |json_file_path_| is the path of a file that will be source of the
+ // deserialization.
+ explicit JSONFileValueDeserializer(const base::FilePath& json_file_path);
+
+ ~JSONFileValueDeserializer() override;
+
+ // 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.
+ scoped_ptr<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;
+ }
+
+ // Returns the size (in bytes) of JSON string read from disk in the last
+ // successful |Deserialize()| call.
+ size_t get_last_read_size() const { return last_read_size_; }
+
+ private:
+ // A wrapper for ReadFileToString which returns a non-zero JsonFileError if
+ // there were file errors.
+ int ReadFileToString(std::string* json_string);
+
+ const base::FilePath json_file_path_;
+ bool allow_trailing_comma_;
+ size_t last_read_size_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(JSONFileValueDeserializer);
+};
+
+#endif // BASE_JSON_JSON_FILE_VALUE_SERIALIZER_H_
+
diff --git a/base/json/json_parser.cc b/base/json/json_parser.cc
index 4d79be3619..fbd4da45fb 100644
--- a/base/json/json_parser.cc
+++ b/base/json/json_parser.cc
@@ -7,6 +7,7 @@
#include <cmath>
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
@@ -24,14 +25,14 @@ namespace {
const int kStackMaxDepth = 100;
-const int32 kExtendedASCIIStart = 0x80;
+const int32_t 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 {
+class DictionaryHiddenRootValue : public DictionaryValue {
public:
DictionaryHiddenRootValue(std::string* json, Value* root) : json_(json) {
DCHECK(root->IsType(Value::TYPE_DICTIONARY));
@@ -43,7 +44,7 @@ class DictionaryHiddenRootValue : public base::DictionaryValue {
// First deep copy to convert JSONStringValue to std::string and swap that
// copy with |other|, which contains the new contents of |this|.
- scoped_ptr<base::DictionaryValue> copy(DeepCopy());
+ scoped_ptr<DictionaryValue> copy(DeepCopy());
copy->Swap(other);
// Then erase the contents of the current dictionary and swap in the
@@ -81,7 +82,7 @@ class DictionaryHiddenRootValue : public base::DictionaryValue {
DISALLOW_COPY_AND_ASSIGN(DictionaryHiddenRootValue);
};
-class ListHiddenRootValue : public base::ListValue {
+class ListHiddenRootValue : public ListValue {
public:
ListHiddenRootValue(std::string* json, Value* root) : json_(json) {
DCHECK(root->IsType(Value::TYPE_LIST));
@@ -93,7 +94,7 @@ class ListHiddenRootValue : public base::ListValue {
// First deep copy to convert JSONStringValue to std::string and swap that
// copy with |other|, which contains the new contents of |this|.
- scoped_ptr<base::ListValue> copy(DeepCopy());
+ scoped_ptr<ListValue> copy(DeepCopy());
copy->Swap(other);
// Then erase the contents of the current list and swap in the new contents,
@@ -130,14 +131,14 @@ class ListHiddenRootValue : public base::ListValue {
// 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 {
+class JSONStringValue : public Value {
public:
- explicit JSONStringValue(const base::StringPiece& piece)
+ explicit JSONStringValue(const StringPiece& piece)
: Value(TYPE_STRING),
string_piece_(piece) {
}
- // Overridden from base::Value:
+ // Overridden from Value:
bool GetAsString(std::string* out_value) const override {
string_piece_.CopyToString(out_value);
return true;
@@ -157,7 +158,7 @@ class JSONStringValue : public base::Value {
private:
// The location in the original input stream.
- base::StringPiece string_piece_;
+ StringPiece string_piece_;
DISALLOW_COPY_AND_ASSIGN(JSONStringValue);
};
@@ -227,9 +228,9 @@ Value* JSONParser::Parse(const StringPiece& input) {
// <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<uint8>(*pos_) == 0xEF &&
- static_cast<uint8>(*(pos_ + 1)) == 0xBB &&
- static_cast<uint8>(*(pos_ + 2)) == 0xBF) {
+ if (CanConsume(3) && static_cast<uint8_t>(*pos_) == 0xEF &&
+ static_cast<uint8_t>(*(pos_ + 1)) == 0xBB &&
+ static_cast<uint8_t>(*(pos_ + 2)) == 0xBF) {
NextNChars(3);
}
@@ -274,6 +275,14 @@ std::string JSONParser::GetErrorMessage() const {
JSONReader::ErrorCodeToString(error_code_));
}
+int JSONParser::error_line() const {
+ return error_line_;
+}
+
+int JSONParser::error_column() const {
+ return error_column_;
+}
+
// StringBuilder ///////////////////////////////////////////////////////////////
JSONParser::StringBuilder::StringBuilder()
@@ -613,7 +622,7 @@ bool JSONParser::ConsumeStringRaw(StringBuilder* out) {
StringBuilder string(NextChar());
int length = end_pos_ - start_pos_;
- int32 next_char = 0;
+ int32_t next_char = 0;
while (CanConsume(1)) {
pos_ = start_pos_ + index_; // CBU8_NEXT is postcrement.
@@ -774,13 +783,19 @@ bool JSONParser::DecodeUTF16(std::string* dest_string) {
return false;
}
- uint32 code_point = CBU16_GET_SUPPLEMENTARY(code_unit16_high,
- code_unit16_low);
+ uint32_t code_point =
+ CBU16_GET_SUPPLEMENTARY(code_unit16_high, code_unit16_low);
+ if (!IsValidCharacter(code_point))
+ return false;
+
offset = 0;
CBU8_APPEND_UNSAFE(code_unit8, offset, code_point);
} else {
// Not a surrogate.
DCHECK(CBU16_IS_SINGLE(code_unit16_high));
+ if (!IsValidCharacter(code_unit16_high))
+ return false;
+
CBU8_APPEND_UNSAFE(code_unit8, offset, code_unit16_high);
}
@@ -788,9 +803,11 @@ bool JSONParser::DecodeUTF16(std::string* dest_string) {
return true;
}
-void JSONParser::DecodeUTF8(const int32& point, StringBuilder* dest) {
+void JSONParser::DecodeUTF8(const int32_t& point, StringBuilder* dest) {
+ DCHECK(IsValidCharacter(point));
+
// Anything outside of the basic ASCII plane will need to be decoded from
- // int32 to a multi-byte sequence.
+ // int32_t to a multi-byte sequence.
if (point < kExtendedASCIIStart) {
dest->Append(static_cast<char>(point));
} else {
@@ -872,7 +889,7 @@ Value* JSONParser::ConsumeNumber() {
return new FundamentalValue(num_int);
double num_double;
- if (base::StringToDouble(num_string.as_string(), &num_double) &&
+ if (StringToDouble(num_string.as_string(), &num_double) &&
std::isfinite(num_double)) {
return new FundamentalValue(num_double);
}
diff --git a/base/json/json_parser.h b/base/json/json_parser.h
index b4d0b1bf97..fc04594a14 100644
--- a/base/json/json_parser.h
+++ b/base/json/json_parser.h
@@ -5,36 +5,22 @@
#ifndef BASE_JSON_JSON_PARSER_H_
#define BASE_JSON_JSON_PARSER_H_
+#include <stddef.h>
+#include <stdint.h>
+
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/compiler_specific.h"
+#include "base/gtest_prod_util.h"
#include "base/json/json_reader.h"
+#include "base/macros.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
+class Value;
-namespace base {
namespace internal {
class JSONParserTest;
@@ -57,7 +43,7 @@ class JSONParserTest;
// 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 {
+class BASE_EXPORT JSONParser {
public:
explicit JSONParser(int options);
~JSONParser();
@@ -72,6 +58,14 @@ class BASE_EXPORT_PRIVATE JSONParser {
// Returns the human-friendly error message.
std::string GetErrorMessage() const;
+ // Returns the error line number if parse error happened. Otherwise always
+ // returns 0.
+ int error_line() const;
+
+ // Returns the error column number if parse error happened. Otherwise always
+ // returns 0.
+ int error_column() const;
+
private:
enum Token {
T_OBJECT_BEGIN, // {
@@ -197,7 +191,7 @@ class BASE_EXPORT_PRIVATE JSONParser {
// 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);
+ void DecodeUTF8(const int32_t& 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.
diff --git a/base/json/json_parser_unittest.cc b/base/json/json_parser_unittest.cc
index f776ddfc2c..da86b332ea 100644
--- a/base/json/json_parser_unittest.cc
+++ b/base/json/json_parser_unittest.cc
@@ -4,6 +4,8 @@
#include "base/json/json_parser.h"
+#include <stddef.h>
+
#include "base/json/json_reader.h"
#include "base/memory/scoped_ptr.h"
#include "base/values.h"
@@ -203,17 +205,16 @@ TEST_F(JSONParserTest, ErrorMessages) {
// Error strings should not be modified in case of success.
std::string error_message;
int error_code = 0;
- scoped_ptr<Value> root;
- root.reset(JSONReader::DeprecatedReadAndReturnError(
- "[42]", JSON_PARSE_RFC, &error_code, &error_message));
+ scoped_ptr<Value> root = 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::DeprecatedReadAndReturnError(
- big_json, JSON_PARSE_RFC, &error_code, &error_message));
+ root = 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);
@@ -225,16 +226,16 @@ TEST_F(JSONParserTest, ErrorMessages) {
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::DeprecatedReadAndReturnError(
- big_json_crlf, JSON_PARSE_RFC, &error_code, &error_message));
+ root = 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::DeprecatedReadAndReturnError(
- "{},{}", JSON_PARSE_RFC, &error_code, &error_message));
+ root = JSONReader::ReadAndReturnError("{},{}", JSON_PARSE_RFC, &error_code,
+ &error_message);
EXPECT_FALSE(root.get());
EXPECT_EQ(JSONParser::FormatErrorMessage(1, 3,
JSONReader::kUnexpectedDataAfterRoot), error_message);
@@ -245,56 +246,56 @@ TEST_F(JSONParserTest, ErrorMessages) {
nested_json.insert(nested_json.begin(), '[');
nested_json.append(1, ']');
}
- root.reset(JSONReader::DeprecatedReadAndReturnError(
- nested_json, JSON_PARSE_RFC, &error_code, &error_message));
+ root = 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::DeprecatedReadAndReturnError(
- "[1,]", JSON_PARSE_RFC, &error_code, &error_message));
+ root = 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::DeprecatedReadAndReturnError(
- "{foo:\"bar\"}", JSON_PARSE_RFC, &error_code, &error_message));
+ root = 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::DeprecatedReadAndReturnError(
- "{\"foo\":\"bar\",}", JSON_PARSE_RFC, &error_code, &error_message));
+ root = 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::DeprecatedReadAndReturnError(
- "[nu]", JSON_PARSE_RFC, &error_code, &error_message));
+ root = 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::DeprecatedReadAndReturnError(
- "[\"xxx\\xq\"]", JSON_PARSE_RFC, &error_code, &error_message));
+ root = 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::DeprecatedReadAndReturnError(
- "[\"xxx\\uq\"]", JSON_PARSE_RFC, &error_code, &error_message));
+ root = 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::DeprecatedReadAndReturnError(
- "[\"xxx\\q\"]", JSON_PARSE_RFC, &error_code, &error_message));
+ root = 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);
@@ -308,10 +309,18 @@ TEST_F(JSONParserTest, Decode4ByteUtf8Char) {
"[\"😇\",[],[],[],{\"google:suggesttype\":[]}]";
std::string error_message;
int error_code = 0;
- scoped_ptr<Value> root(JSONReader::DeprecatedReadAndReturnError(
- kUtf8Data, JSON_PARSE_RFC, &error_code, &error_message));
+ scoped_ptr<Value> root = JSONReader::ReadAndReturnError(
+ kUtf8Data, JSON_PARSE_RFC, &error_code, &error_message);
EXPECT_TRUE(root.get()) << error_message;
}
+TEST_F(JSONParserTest, DecodeUnicodeNonCharacter) {
+ // Tests Unicode code points (encoded as escaped UTF-16) that are not valid
+ // characters.
+ EXPECT_FALSE(JSONReader::Read("[\"\\ufdd0\"]"));
+ EXPECT_FALSE(JSONReader::Read("[\"\\ufffe\"]"));
+ EXPECT_FALSE(JSONReader::Read("[\"\\ud83f\\udffe\"]"));
+}
+
} // namespace internal
} // namespace base
diff --git a/base/json/json_reader.cc b/base/json/json_reader.cc
index ad3ea98b31..3ab5f754b7 100644
--- a/base/json/json_reader.cc
+++ b/base/json/json_reader.cc
@@ -11,8 +11,8 @@
namespace base {
// Values 1000 and above are used by JSONFileValueSerializer::JsonFileError.
-COMPILE_ASSERT(JSONReader::JSON_PARSE_ERROR_COUNT < 1000,
- json_reader_error_out_of_bounds);
+static_assert(JSONReader::JSON_PARSE_ERROR_COUNT < 1000,
+ "JSONReader error out of bounds");
const char JSONReader::kInvalidEscape[] =
"Invalid escape sequence.";
@@ -43,41 +43,25 @@ JSONReader::~JSONReader() {
}
// static
-Value* JSONReader::DeprecatedRead(const StringPiece& json) {
- return Read(json).release();
-}
-
-// static
scoped_ptr<Value> JSONReader::Read(const StringPiece& json) {
internal::JSONParser parser(JSON_PARSE_RFC);
return make_scoped_ptr(parser.Parse(json));
}
// static
-Value* JSONReader::DeprecatedRead(const StringPiece& json, int options) {
- return Read(json, options).release();
-}
-
-// static
scoped_ptr<Value> JSONReader::Read(const StringPiece& json, int options) {
internal::JSONParser parser(options);
return make_scoped_ptr(parser.Parse(json));
}
-// static
-Value* JSONReader::DeprecatedReadAndReturnError(const StringPiece& json,
- int options,
- int* error_code_out,
- std::string* error_msg_out) {
- return ReadAndReturnError(json, options, error_code_out, error_msg_out)
- .release();
-}
// static
scoped_ptr<Value> JSONReader::ReadAndReturnError(const StringPiece& json,
int options,
int* error_code_out,
- std::string* error_msg_out) {
+ std::string* error_msg_out,
+ int* error_line_out,
+ int* error_column_out) {
internal::JSONParser parser(options);
scoped_ptr<Value> root(parser.Parse(json));
if (!root) {
@@ -85,6 +69,10 @@ scoped_ptr<Value> JSONReader::ReadAndReturnError(const StringPiece& json,
*error_code_out = parser.error_code();
if (error_msg_out)
*error_msg_out = parser.GetErrorMessage();
+ if (error_line_out)
+ *error_line_out = parser.error_line();
+ if (error_column_out)
+ *error_column_out = parser.error_column();
}
return root;
diff --git a/base/json/json_reader.h b/base/json/json_reader.h
index 378935a709..c6bcb528e3 100644
--- a/base/json/json_reader.h
+++ b/base/json/json_reader.h
@@ -31,7 +31,6 @@
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/string_piece.h"
@@ -95,15 +94,11 @@ class BASE_EXPORT 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 scoped_ptr<Value> Read(const StringPiece& json);
- // TODO(estade): remove this bare pointer version.
- static Value* DeprecatedRead(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 scoped_ptr<Value> Read(const StringPiece& json, int options);
- // TODO(estade): remove this bare pointer version.
- static Value* DeprecatedRead(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
@@ -112,12 +107,9 @@ class BASE_EXPORT JSONReader {
static scoped_ptr<Value> ReadAndReturnError(const StringPiece& json,
int options, // JSONParserOptions
int* error_code_out,
- std::string* error_msg_out);
- // TODO(estade): remove this bare pointer version.
- static Value* DeprecatedReadAndReturnError(const StringPiece& json,
- int options, // JSONParserOptions
- int* error_code_out,
- std::string* error_msg_out);
+ std::string* error_msg_out,
+ int* error_line_out = nullptr,
+ int* error_column_out = nullptr);
// Converts a JSON parse error code into a human readable message.
// Returns an empty string if error_code is JSON_NO_ERROR.
diff --git a/base/json/json_reader_unittest.cc b/base/json/json_reader_unittest.cc
new file mode 100644
index 0000000000..45c04d8bf6
--- /dev/null
+++ b/base/json/json_reader_unittest.cc
@@ -0,0 +1,664 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <stddef.h>
+
+#if !defined(__ANDROID__) && !defined(__ANDROID_HOST__)
+#include "base/base_paths.h"
+#include "base/path_service.h"
+#endif
+
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.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<Value> root = JSONReader().ReadToValue(" null ");
+ ASSERT_TRUE(root.get());
+ EXPECT_TRUE(root->IsType(Value::TYPE_NULL));
+
+ // Invalid JSON string
+ root = JSONReader().ReadToValue("nu");
+ EXPECT_FALSE(root.get());
+
+ // Simple bool
+ root = JSONReader().ReadToValue("true ");
+ ASSERT_TRUE(root.get());
+ EXPECT_TRUE(root->IsType(Value::TYPE_BOOLEAN));
+
+ // Embedded comment
+ root = JSONReader().ReadToValue("/* comment */null");
+ ASSERT_TRUE(root.get());
+ EXPECT_TRUE(root->IsType(Value::TYPE_NULL));
+ root = JSONReader().ReadToValue("40 /* comment */");
+ ASSERT_TRUE(root.get());
+ EXPECT_TRUE(root->IsType(Value::TYPE_INTEGER));
+ root = JSONReader().ReadToValue("true // comment");
+ ASSERT_TRUE(root.get());
+ EXPECT_TRUE(root->IsType(Value::TYPE_BOOLEAN));
+ root = 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 = JSONReader().ReadToValue("[1, /* comment, 2 ] */ \n 3]");
+ ASSERT_TRUE(root.get());
+ ListValue* list = static_cast<ListValue*>(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 = JSONReader().ReadToValue("[1, /*a*/2, 3]");
+ ASSERT_TRUE(root.get());
+ list = static_cast<ListValue*>(root.get());
+ EXPECT_EQ(3u, list->GetSize());
+ root = 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 = 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 = 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 = JSONReader().ReadToValue("043");
+ EXPECT_FALSE(root.get());
+ root = JSONReader().ReadToValue("0x43");
+ EXPECT_FALSE(root.get());
+ root = JSONReader().ReadToValue("00");
+ EXPECT_FALSE(root.get());
+
+ // Test 0 (which needs to be special cased because of the leading zero
+ // clause).
+ root = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = JSONReader().ReadToValue("1.");
+ EXPECT_FALSE(root.get());
+ root = JSONReader().ReadToValue(".1");
+ EXPECT_FALSE(root.get());
+ root = JSONReader().ReadToValue("1.e10");
+ EXPECT_FALSE(root.get());
+
+ // Exponent must have a digit following the 'e'.
+ root = JSONReader().ReadToValue("1e");
+ EXPECT_FALSE(root.get());
+ root = JSONReader().ReadToValue("1E");
+ EXPECT_FALSE(root.get());
+ root = JSONReader().ReadToValue("1e1.");
+ EXPECT_FALSE(root.get());
+ root = JSONReader().ReadToValue("1e1.0");
+ EXPECT_FALSE(root.get());
+
+ // INF/-INF/NaN are not valid
+ root = JSONReader().ReadToValue("1e1000");
+ EXPECT_FALSE(root.get());
+ root = JSONReader().ReadToValue("-1e1000");
+ EXPECT_FALSE(root.get());
+ root = JSONReader().ReadToValue("NaN");
+ EXPECT_FALSE(root.get());
+ root = JSONReader().ReadToValue("nan");
+ EXPECT_FALSE(root.get());
+ root = JSONReader().ReadToValue("inf");
+ EXPECT_FALSE(root.get());
+
+ // Invalid number formats
+ root = JSONReader().ReadToValue("4.3.1");
+ EXPECT_FALSE(root.get());
+ root = JSONReader().ReadToValue("4e3.1");
+ EXPECT_FALSE(root.get());
+
+ // Test string parser
+ root = 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 = 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 = 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 = 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 = JSONReader().ReadToValue("\"no closing quote");
+ EXPECT_FALSE(root.get());
+ root = JSONReader().ReadToValue("\"\\z invalid escape char\"");
+ EXPECT_FALSE(root.get());
+ root = JSONReader().ReadToValue("\"\\xAQ invalid hex code\"");
+ EXPECT_FALSE(root.get());
+ root = JSONReader().ReadToValue("not enough hex chars\\x1\"");
+ EXPECT_FALSE(root.get());
+ root = JSONReader().ReadToValue("\"not enough escape chars\\u123\"");
+ EXPECT_FALSE(root.get());
+ root = JSONReader().ReadToValue("\"extra backslash at end of input\\\"");
+ EXPECT_FALSE(root.get());
+
+ // Basic array
+ root = JSONReader::Read("[true, false, null]");
+ ASSERT_TRUE(root.get());
+ EXPECT_TRUE(root->IsType(Value::TYPE_LIST));
+ list = static_cast<ListValue*>(root.get());
+ EXPECT_EQ(3U, list->GetSize());
+
+ // Test with trailing comma. Should be parsed the same as above.
+ scoped_ptr<Value> root2 =
+ JSONReader::Read("[true, false, null, ]", JSON_ALLOW_TRAILING_COMMAS);
+ EXPECT_TRUE(root->Equals(root2.get()));
+
+ // Empty array
+ root = JSONReader::Read("[]");
+ ASSERT_TRUE(root.get());
+ EXPECT_TRUE(root->IsType(Value::TYPE_LIST));
+ list = static_cast<ListValue*>(root.get());
+ EXPECT_EQ(0U, list->GetSize());
+
+ // Nested arrays
+ root = JSONReader::Read("[[true], [], [false, [], [null]], null]");
+ ASSERT_TRUE(root.get());
+ EXPECT_TRUE(root->IsType(Value::TYPE_LIST));
+ list = static_cast<ListValue*>(root.get());
+ EXPECT_EQ(4U, list->GetSize());
+
+ // Lots of trailing commas.
+ root2 = JSONReader::Read("[[true], [], [false, [], [null, ] , ], null,]",
+ JSON_ALLOW_TRAILING_COMMAS);
+ EXPECT_TRUE(root->Equals(root2.get()));
+
+ // Invalid, missing close brace.
+ root = JSONReader::Read("[[true], [], [false, [], [null]], null");
+ EXPECT_FALSE(root.get());
+
+ // Invalid, too many commas
+ root = JSONReader::Read("[true,, null]");
+ EXPECT_FALSE(root.get());
+ root = JSONReader::Read("[true,, null]", JSON_ALLOW_TRAILING_COMMAS);
+ EXPECT_FALSE(root.get());
+
+ // Invalid, no commas
+ root = JSONReader::Read("[true null]");
+ EXPECT_FALSE(root.get());
+
+ // Invalid, trailing comma
+ root = JSONReader::Read("[true,]");
+ EXPECT_FALSE(root.get());
+
+ // Valid if we set |allow_trailing_comma| to true.
+ root = JSONReader::Read("[true,]", JSON_ALLOW_TRAILING_COMMAS);
+ ASSERT_TRUE(root.get());
+ EXPECT_TRUE(root->IsType(Value::TYPE_LIST));
+ list = static_cast<ListValue*>(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 = JSONReader::Read("[,]", JSON_ALLOW_TRAILING_COMMAS);
+ EXPECT_FALSE(root.get());
+ root = JSONReader::Read("[true,,]", JSON_ALLOW_TRAILING_COMMAS);
+ EXPECT_FALSE(root.get());
+ root = JSONReader::Read("[,true,]", JSON_ALLOW_TRAILING_COMMAS);
+ EXPECT_FALSE(root.get());
+ root = JSONReader::Read("[true,,false]", JSON_ALLOW_TRAILING_COMMAS);
+ EXPECT_FALSE(root.get());
+
+ // Test objects
+ root = JSONReader::Read("{}");
+ ASSERT_TRUE(root.get());
+ EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
+
+ root = 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<DictionaryValue*>(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 = 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 = 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 = 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 = JSONReader::Read(
+ "{\"inner\":{\"array\":[true]},\"false\":false,\"d\":{}}");
+ ASSERT_TRUE(root.get());
+ EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
+ dict_val = static_cast<DictionaryValue*>(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 = JSONReader::Read(
+ "{\"inner\": {\"array\":[true] , },\"false\":false,\"d\":{},}",
+ JSON_ALLOW_TRAILING_COMMAS);
+ EXPECT_TRUE(root->Equals(root2.get()));
+
+ // Test keys with periods
+ root = 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<DictionaryValue*>(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 = JSONReader::Read("{\"a\":{\"b\":2},\"a.b\":1}");
+ ASSERT_TRUE(root.get());
+ EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
+ dict_val = static_cast<DictionaryValue*>(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 = JSONReader::Read("{\"a\": true");
+ EXPECT_FALSE(root.get());
+
+ // Invalid, keys must be quoted
+ root = JSONReader::Read("{foo:true}");
+ EXPECT_FALSE(root.get());
+
+ // Invalid, trailing comma
+ root = JSONReader::Read("{\"a\":true,}");
+ EXPECT_FALSE(root.get());
+
+ // Invalid, too many commas
+ root = JSONReader::Read("{\"a\":true,,\"b\":false}");
+ EXPECT_FALSE(root.get());
+ root =
+ JSONReader::Read("{\"a\":true,,\"b\":false}", JSON_ALLOW_TRAILING_COMMAS);
+ EXPECT_FALSE(root.get());
+
+ // Invalid, no separator
+ root = JSONReader::Read("{\"a\" \"b\"}");
+ EXPECT_FALSE(root.get());
+
+ // Invalid, lone comma.
+ root = JSONReader::Read("{,}");
+ EXPECT_FALSE(root.get());
+ root = JSONReader::Read("{,}", JSON_ALLOW_TRAILING_COMMAS);
+ EXPECT_FALSE(root.get());
+ root = JSONReader::Read("{\"a\":true,,}", JSON_ALLOW_TRAILING_COMMAS);
+ EXPECT_FALSE(root.get());
+ root = JSONReader::Read("{,\"a\":true}", JSON_ALLOW_TRAILING_COMMAS);
+ EXPECT_FALSE(root.get());
+ root =
+ 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 = 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 = JSONReader::Read(not_evil);
+ ASSERT_TRUE(root.get());
+ EXPECT_TRUE(root->IsType(Value::TYPE_LIST));
+ list = static_cast<ListValue*>(root.get());
+ EXPECT_EQ(5001U, list->GetSize());
+
+ // Test utf8 encoded input
+ root = 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 = 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 = JSONReader().ReadToValue("\"345\xb0\xa1\xb0\xa2\"");
+ EXPECT_FALSE(root.get());
+ root = JSONReader().ReadToValue("\"123\xc0\x81\"");
+ EXPECT_FALSE(root.get());
+ root = JSONReader().ReadToValue("\"abc\xc0\xae\"");
+ EXPECT_FALSE(root.get());
+
+ // Test utf16 encoded strings.
+ root = 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 = 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* const 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 = JSONReader().ReadToValue(cases[i]);
+ EXPECT_FALSE(root.get()) << cases[i];
+ }
+
+ // Test literal root objects.
+ root = JSONReader::Read("null");
+ EXPECT_TRUE(root->IsType(Value::TYPE_NULL));
+
+ root = JSONReader::Read("true");
+ ASSERT_TRUE(root.get());
+ EXPECT_TRUE(root->GetAsBoolean(&bool_value));
+ EXPECT_TRUE(bool_value);
+
+ root = JSONReader::Read("10");
+ ASSERT_TRUE(root.get());
+ EXPECT_TRUE(root->GetAsInteger(&integer_value));
+ EXPECT_EQ(10, integer_value);
+
+ root = JSONReader::Read("\"root\"");
+ ASSERT_TRUE(root.get());
+ EXPECT_TRUE(root->GetAsString(&str_val));
+ EXPECT_EQ("root", str_val);
+}
+
+#if !defined(__ANDROID__) && !defined(__ANDROID_HOST__)
+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(ReadFileToString(
+ path.Append(FILE_PATH_LITERAL("bom_feff.json")), &input));
+
+ JSONReader reader;
+ scoped_ptr<Value> root(reader.ReadToValue(input));
+ ASSERT_TRUE(root.get()) << reader.GetErrorMessage();
+ EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
+}
+#endif // !__ANDROID__ && !__ANDROID_HOST__
+
+// Tests that the root of a JSON object can be deleted safely while its
+// children outlive it.
+TEST(JSONReaderTest, StringOptimizations) {
+ scoped_ptr<Value> dict_literal_0;
+ scoped_ptr<Value> dict_literal_1;
+ scoped_ptr<Value> dict_string_0;
+ scoped_ptr<Value> dict_string_1;
+ scoped_ptr<Value> list_value_0;
+ scoped_ptr<Value> list_value_1;
+
+ {
+ scoped_ptr<Value> 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* const 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
index 5425c7e7b9..af7e010a3a 100644
--- a/base/json/json_string_value_serializer.cc
+++ b/base/json/json_string_value_serializer.cc
@@ -48,9 +48,10 @@ JSONStringValueDeserializer::JSONStringValueDeserializer(
JSONStringValueDeserializer::~JSONStringValueDeserializer() {}
-Value* JSONStringValueDeserializer::Deserialize(int* error_code,
- std::string* error_str) {
- return base::JSONReader::DeprecatedReadAndReturnError(
+scoped_ptr<Value> JSONStringValueDeserializer::Deserialize(
+ int* error_code,
+ std::string* error_str) {
+ 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
index bc0e66d127..2459f48a8a 100644
--- a/base/json/json_string_value_serializer.h
+++ b/base/json/json_string_value_serializer.h
@@ -8,8 +8,8 @@
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/files/file_path.h"
+#include "base/macros.h"
#include "base/strings/string_piece.h"
#include "base/values.h"
@@ -59,8 +59,8 @@ class BASE_EXPORT JSONStringValueDeserializer : public base::ValueDeserializer {
// 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.
- base::Value* Deserialize(int* error_code,
- std::string* error_message) override;
+ scoped_ptr<base::Value> Deserialize(int* error_code,
+ std::string* error_message) override;
void set_allow_trailing_comma(bool new_value) {
allow_trailing_comma_ = new_value;
diff --git a/base/json/json_value_converter.cc b/base/json/json_value_converter.cc
new file mode 100644
index 0000000000..6f772f366b
--- /dev/null
+++ b/base/json/json_value_converter.cc
@@ -0,0 +1,37 @@
+// Copyright 2014 The Chromium Authors. All 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"
+
+namespace base {
+namespace internal {
+
+bool BasicValueConverter<int>::Convert(
+ const base::Value& value, int* field) const {
+ return value.GetAsInteger(field);
+}
+
+bool BasicValueConverter<std::string>::Convert(
+ const base::Value& value, std::string* field) const {
+ return value.GetAsString(field);
+}
+
+bool BasicValueConverter<string16>::Convert(
+ const base::Value& value, string16* field) const {
+ return value.GetAsString(field);
+}
+
+bool BasicValueConverter<double>::Convert(
+ const base::Value& value, double* field) const {
+ return value.GetAsDouble(field);
+}
+
+bool BasicValueConverter<bool>::Convert(
+ const base::Value& value, bool* field) const {
+ return value.GetAsBoolean(field);
+}
+
+} // namespace internal
+} // namespace base
+
diff --git a/base/json/json_value_converter.h b/base/json/json_value_converter.h
new file mode 100644
index 0000000000..a1e0d5bb5a
--- /dev/null
+++ b/base/json/json_value_converter.h
@@ -0,0 +1,516 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <stddef.h>
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/logging.h"
+#include "base/macros.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<Message>* 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<Message>* 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<Message> 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<YourEnum>(
+// "your_enum", &Message::ye, &ConvertFunc);
+// }
+// };
+
+namespace base {
+
+template <typename StructType>
+class JSONValueConverter;
+
+namespace internal {
+
+template<typename StructType>
+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 <typename FieldType>
+class ValueConverter {
+ public:
+ virtual ~ValueConverter() {}
+ virtual bool Convert(const base::Value& value, FieldType* field) const = 0;
+};
+
+template <typename StructType, typename FieldType>
+class FieldConverter : public FieldConverterBase<StructType> {
+ public:
+ explicit FieldConverter(const std::string& path,
+ FieldType StructType::* field,
+ ValueConverter<FieldType>* converter)
+ : FieldConverterBase<StructType>(path),
+ field_pointer_(field),
+ value_converter_(converter) {
+ }
+
+ 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<ValueConverter<FieldType> > value_converter_;
+ DISALLOW_COPY_AND_ASSIGN(FieldConverter);
+};
+
+template <typename FieldType>
+class BasicValueConverter;
+
+template <>
+class BASE_EXPORT BasicValueConverter<int> : public ValueConverter<int> {
+ public:
+ BasicValueConverter() {}
+
+ bool Convert(const base::Value& value, int* field) const override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
+};
+
+template <>
+class BASE_EXPORT BasicValueConverter<std::string>
+ : public ValueConverter<std::string> {
+ public:
+ BasicValueConverter() {}
+
+ bool Convert(const base::Value& value, std::string* field) const override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
+};
+
+template <>
+class BASE_EXPORT BasicValueConverter<string16>
+ : public ValueConverter<string16> {
+ public:
+ BasicValueConverter() {}
+
+ bool Convert(const base::Value& value, string16* field) const override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
+};
+
+template <>
+class BASE_EXPORT BasicValueConverter<double> : public ValueConverter<double> {
+ public:
+ BasicValueConverter() {}
+
+ bool Convert(const base::Value& value, double* field) const override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
+};
+
+template <>
+class BASE_EXPORT BasicValueConverter<bool> : public ValueConverter<bool> {
+ public:
+ BasicValueConverter() {}
+
+ bool Convert(const base::Value& value, bool* field) const override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
+};
+
+template <typename FieldType>
+class ValueFieldConverter : public ValueConverter<FieldType> {
+ public:
+ typedef bool(*ConvertFunc)(const base::Value* value, FieldType* field);
+
+ ValueFieldConverter(ConvertFunc convert_func)
+ : convert_func_(convert_func) {}
+
+ 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 <typename FieldType>
+class CustomFieldConverter : public ValueConverter<FieldType> {
+ public:
+ typedef bool(*ConvertFunc)(const StringPiece& value, FieldType* field);
+
+ CustomFieldConverter(ConvertFunc convert_func)
+ : convert_func_(convert_func) {}
+
+ 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 <typename NestedType>
+class NestedValueConverter : public ValueConverter<NestedType> {
+ public:
+ NestedValueConverter() {}
+
+ bool Convert(const base::Value& value, NestedType* field) const override {
+ return converter_.Convert(value, field);
+ }
+
+ private:
+ JSONValueConverter<NestedType> converter_;
+ DISALLOW_COPY_AND_ASSIGN(NestedValueConverter);
+};
+
+template <typename Element>
+class RepeatedValueConverter : public ValueConverter<ScopedVector<Element> > {
+ public:
+ RepeatedValueConverter() {}
+
+ bool Convert(const base::Value& value,
+ ScopedVector<Element>* 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<Element> 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<Element> basic_converter_;
+ DISALLOW_COPY_AND_ASSIGN(RepeatedValueConverter);
+};
+
+template <typename NestedType>
+class RepeatedMessageConverter
+ : public ValueConverter<ScopedVector<NestedType> > {
+ public:
+ RepeatedMessageConverter() {}
+
+ bool Convert(const base::Value& value,
+ ScopedVector<NestedType>* 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<NestedType> 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<NestedType> converter_;
+ DISALLOW_COPY_AND_ASSIGN(RepeatedMessageConverter);
+};
+
+template <typename NestedType>
+class RepeatedCustomValueConverter
+ : public ValueConverter<ScopedVector<NestedType> > {
+ public:
+ typedef bool(*ConvertFunc)(const base::Value* value, NestedType* field);
+
+ RepeatedCustomValueConverter(ConvertFunc convert_func)
+ : convert_func_(convert_func) {}
+
+ bool Convert(const base::Value& value,
+ ScopedVector<NestedType>* 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<NestedType> 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 StructType>
+class JSONValueConverter {
+ public:
+ JSONValueConverter() {
+ StructType::RegisterJSONConverter(this);
+ }
+
+ void RegisterIntField(const std::string& field_name,
+ int StructType::* field) {
+ fields_.push_back(new internal::FieldConverter<StructType, int>(
+ field_name, field, new internal::BasicValueConverter<int>));
+ }
+
+ void RegisterStringField(const std::string& field_name,
+ std::string StructType::* field) {
+ fields_.push_back(new internal::FieldConverter<StructType, std::string>(
+ field_name, field, new internal::BasicValueConverter<std::string>));
+ }
+
+ void RegisterStringField(const std::string& field_name,
+ string16 StructType::* field) {
+ fields_.push_back(new internal::FieldConverter<StructType, string16>(
+ field_name, field, new internal::BasicValueConverter<string16>));
+ }
+
+ void RegisterBoolField(const std::string& field_name,
+ bool StructType::* field) {
+ fields_.push_back(new internal::FieldConverter<StructType, bool>(
+ field_name, field, new internal::BasicValueConverter<bool>));
+ }
+
+ void RegisterDoubleField(const std::string& field_name,
+ double StructType::* field) {
+ fields_.push_back(new internal::FieldConverter<StructType, double>(
+ field_name, field, new internal::BasicValueConverter<double>));
+ }
+
+ template <class NestedType>
+ void RegisterNestedField(
+ const std::string& field_name, NestedType StructType::* field) {
+ fields_.push_back(new internal::FieldConverter<StructType, NestedType>(
+ field_name,
+ field,
+ new internal::NestedValueConverter<NestedType>));
+ }
+
+ template <typename FieldType>
+ void RegisterCustomField(
+ const std::string& field_name,
+ FieldType StructType::* field,
+ bool (*convert_func)(const StringPiece&, FieldType*)) {
+ fields_.push_back(new internal::FieldConverter<StructType, FieldType>(
+ field_name,
+ field,
+ new internal::CustomFieldConverter<FieldType>(convert_func)));
+ }
+
+ template <typename FieldType>
+ void RegisterCustomValueField(
+ const std::string& field_name,
+ FieldType StructType::* field,
+ bool (*convert_func)(const base::Value*, FieldType*)) {
+ fields_.push_back(new internal::FieldConverter<StructType, FieldType>(
+ field_name,
+ field,
+ new internal::ValueFieldConverter<FieldType>(convert_func)));
+ }
+
+ void RegisterRepeatedInt(const std::string& field_name,
+ ScopedVector<int> StructType::* field) {
+ fields_.push_back(
+ new internal::FieldConverter<StructType, ScopedVector<int> >(
+ field_name, field, new internal::RepeatedValueConverter<int>));
+ }
+
+ void RegisterRepeatedString(const std::string& field_name,
+ ScopedVector<std::string> StructType::* field) {
+ fields_.push_back(
+ new internal::FieldConverter<StructType, ScopedVector<std::string> >(
+ field_name,
+ field,
+ new internal::RepeatedValueConverter<std::string>));
+ }
+
+ void RegisterRepeatedString(const std::string& field_name,
+ ScopedVector<string16> StructType::* field) {
+ fields_.push_back(
+ new internal::FieldConverter<StructType, ScopedVector<string16> >(
+ field_name,
+ field,
+ new internal::RepeatedValueConverter<string16>));
+ }
+
+ void RegisterRepeatedDouble(const std::string& field_name,
+ ScopedVector<double> StructType::* field) {
+ fields_.push_back(
+ new internal::FieldConverter<StructType, ScopedVector<double> >(
+ field_name, field, new internal::RepeatedValueConverter<double>));
+ }
+
+ void RegisterRepeatedBool(const std::string& field_name,
+ ScopedVector<bool> StructType::* field) {
+ fields_.push_back(
+ new internal::FieldConverter<StructType, ScopedVector<bool> >(
+ field_name, field, new internal::RepeatedValueConverter<bool>));
+ }
+
+ template <class NestedType>
+ void RegisterRepeatedCustomValue(
+ const std::string& field_name,
+ ScopedVector<NestedType> StructType::* field,
+ bool (*convert_func)(const base::Value*, NestedType*)) {
+ fields_.push_back(
+ new internal::FieldConverter<StructType, ScopedVector<NestedType> >(
+ field_name,
+ field,
+ new internal::RepeatedCustomValueConverter<NestedType>(
+ convert_func)));
+ }
+
+ template <class NestedType>
+ void RegisterRepeatedMessage(const std::string& field_name,
+ ScopedVector<NestedType> StructType::* field) {
+ fields_.push_back(
+ new internal::FieldConverter<StructType, ScopedVector<NestedType> >(
+ field_name,
+ field,
+ new internal::RepeatedMessageConverter<NestedType>));
+ }
+
+ 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<StructType>* 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<internal::FieldConverterBase<StructType> > 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
new file mode 100644
index 0000000000..90386107d8
--- /dev/null
+++ b/base/json/json_value_converter_unittest.cc
@@ -0,0 +1,256 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <string>
+#include <vector>
+
+#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<int> ints;
+ ScopedVector<std::string> 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<SimpleMessage>* converter) {
+ converter->RegisterIntField("foo", &SimpleMessage::foo);
+ converter->RegisterStringField("bar", &SimpleMessage::bar);
+ converter->RegisterBoolField("baz", &SimpleMessage::baz);
+ converter->RegisterCustomField<SimpleEnum>(
+ "simple_enum", &SimpleMessage::simple_enum, &ParseSimpleEnum);
+ converter->RegisterRepeatedInt("ints", &SimpleMessage::ints);
+ converter->RegisterCustomValueField<bool>("bstruct",
+ &SimpleMessage::bstruct,
+ &HasFieldPresent);
+ converter->RegisterRepeatedCustomValue<std::string>(
+ "string_values",
+ &SimpleMessage::string_values,
+ &GetValueString);
+ }
+};
+
+// For nested messages.
+struct NestedMessage {
+ double foo;
+ SimpleMessage child;
+ ScopedVector<SimpleMessage> children;
+
+ NestedMessage() : foo(0) {}
+
+ static void RegisterJSONConverter(
+ base::JSONValueConverter<NestedMessage>* 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> value = base::JSONReader::Read(normal_data);
+ SimpleMessage message;
+ base::JSONValueConverter<SimpleMessage> 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<int>(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> value = base::JSONReader::Read(normal_data);
+ NestedMessage message;
+ base::JSONValueConverter<NestedMessage> 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<int>(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> value = base::JSONReader::Read(normal_data);
+ SimpleMessage message;
+ base::JSONValueConverter<SimpleMessage> 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> value = base::JSONReader::Read(normal_data);
+ SimpleMessage message;
+ base::JSONValueConverter<SimpleMessage> 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<int>(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> value = base::JSONReader::Read(normal_data);
+ SimpleMessage message;
+ base::JSONValueConverter<SimpleMessage> 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> value = base::JSONReader::Read(normal_data);
+ SimpleMessage message;
+ base::JSONValueConverter<SimpleMessage> 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
new file mode 100644
index 0000000000..7f2ae10f9e
--- /dev/null
+++ b/base/json/json_value_serializer_unittest.cc
@@ -0,0 +1,500 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+
+#include "base/files/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"
+#if !defined(__ANDROID__) && !defined(__ANDROID_HOST__)
+#include "base/path_service.h"
+#endif
+#include "base/strings/string_piece.h"
+#include "base/strings/string_util.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 {
+
+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";
+
+// kProperJSON with a few misc characters at the begin and end.
+const char kProperJSONPadded[] =
+ ")]}'\n"
+ "{\n"
+ " \"compound\": {\n"
+ " \"a\": 1,\n"
+ " \"b\": 2\n"
+ " },\n"
+ " \"some_String\": \"1337\",\n"
+ " \"some_int\": 42,\n"
+ " \"the_list\": [ \"val1\", \"val2\" ]\n"
+ "}\n"
+ "?!ab\n";
+
+const char kWinLineEnds[] = "\r\n";
+const char kLinuxLineEnds[] = "\n";
+
+// Verifies the generated JSON against the expected output.
+void CheckJSONIsStillTheSame(const 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<Value> root = JSONReader::Read(json);
+ ASSERT_TRUE(root.get() && root->IsType(Value::TYPE_LIST));
+ ListValue* list = static_cast<ListValue*>(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 deserialization from string is working.
+TEST(JSONValueDeserializerTest, ReadProperJSONFromString) {
+ // Try to deserialize it through the serializer.
+ JSONStringValueDeserializer str_deserializer(kProperJSON);
+
+ int error_code = 0;
+ std::string error_message;
+ scoped_ptr<Value> 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 proper JSON deserialization from a StringPiece substring.
+TEST(JSONValueDeserializerTest, ReadProperJSONFromStringPiece) {
+ // Create a StringPiece for the substring of kProperJSONPadded that matches
+ // kProperJSON.
+ base::StringPiece proper_json(kProperJSONPadded);
+ proper_json = proper_json.substr(5, proper_json.length() - 10);
+ JSONStringValueDeserializer str_deserializer(proper_json);
+
+ int error_code = 0;
+ std::string error_message;
+ scoped_ptr<Value> 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(JSONValueDeserializerTest, ReadJSONWithTrailingCommasFromString) {
+ // Try to deserialize it through the serializer.
+ JSONStringValueDeserializer str_deserializer(kProperJSONWithCommas);
+
+ int error_code = 0;
+ std::string error_message;
+ scoped_ptr<Value> 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 = 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 deserialization from file is working.
+TEST(JSONValueDeserializerTest, 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<int>(strlen(kProperJSON)),
+ WriteFile(temp_file, kProperJSON, strlen(kProperJSON)));
+
+ // Try to deserialize it through the serializer.
+ JSONFileValueDeserializer file_deserializer(temp_file);
+
+ int error_code = 0;
+ std::string error_message;
+ scoped_ptr<Value> 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(JSONValueDeserializerTest, 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<int>(strlen(kProperJSONWithCommas)),
+ WriteFile(temp_file, kProperJSONWithCommas,
+ strlen(kProperJSONWithCommas)));
+
+ // Try to deserialize it through the serializer.
+ JSONFileValueDeserializer file_deserializer(temp_file);
+ // This must fail without the proper flag.
+ int error_code = 0;
+ std::string error_message;
+ scoped_ptr<Value> 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 = 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(JSONValueDeserializerTest, AllowTrailingComma) {
+ scoped_ptr<Value> root;
+ scoped_ptr<Value> root_expected;
+ static const char kTestWithCommas[] = "{\"key\": [true,],}";
+ static const char kTestNoCommas[] = "{\"key\": [true]}";
+
+ JSONStringValueDeserializer deserializer(kTestWithCommas);
+ deserializer.set_allow_trailing_comma(true);
+ JSONStringValueDeserializer deserializer_expected(kTestNoCommas);
+ root = deserializer.Deserialize(NULL, NULL);
+ ASSERT_TRUE(root.get());
+ root_expected = deserializer_expected.Deserialize(NULL, NULL);
+ ASSERT_TRUE(root_expected.get());
+ ASSERT_TRUE(root->Equals(root_expected.get()));
+}
+
+TEST(JSONValueSerializerTest, Roundtrip) {
+ static const char kOriginalSerialization[] =
+ "{\"bool\":true,\"double\":3.14,\"int\":42,\"list\":[1,2],\"null\":null}";
+ JSONStringValueDeserializer deserializer(kOriginalSerialization);
+ scoped_ptr<Value> root = deserializer.Deserialize(NULL, NULL);
+ ASSERT_TRUE(root.get());
+ ASSERT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
+
+ DictionaryValue* root_dict = static_cast<DictionaryValue*>(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);
+
+ std::string test_serialization;
+ JSONStringValueSerializer mutable_serializer(&test_serialization);
+ ASSERT_TRUE(mutable_serializer.Serialize(*root_dict));
+ ASSERT_EQ(kOriginalSerialization, 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<char16>(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=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcde"
+ "fghijklmnopqrstuvwxyz{|}~\x7F\xC2\x80\xC2\x81\xC2\x82\xC2\x83\xC2\x84"
+ "\xC2\x85\xC2\x86\xC2\x87\xC2\x88\xC2\x89\xC2\x8A\xC2\x8B\xC2\x8C\xC2\x8D"
+ "\xC2\x8E\xC2\x8F\xC2\x90\xC2\x91\xC2\x92\xC2\x93\xC2\x94\xC2\x95\xC2\x96"
+ "\xC2\x97\xC2\x98\xC2\x99\xC2\x9A\xC2\x9B\xC2\x9C\xC2\x9D\xC2\x9E\xC2\x9F"
+ "\xC2\xA0\xC2\xA1\xC2\xA2\xC2\xA3\xC2\xA4\xC2\xA5\xC2\xA6\xC2\xA7\xC2\xA8"
+ "\xC2\xA9\xC2\xAA\xC2\xAB\xC2\xAC\xC2\xAD\xC2\xAE\xC2\xAF\xC2\xB0\xC2\xB1"
+ "\xC2\xB2\xC2\xB3\xC2\xB4\xC2\xB5\xC2\xB6\xC2\xB7\xC2\xB8\xC2\xB9\xC2\xBA"
+ "\xC2\xBB\xC2\xBC\xC2\xBD\xC2\xBE\xC2\xBF\xC3\x80\xC3\x81\xC3\x82\xC3\x83"
+ "\xC3\x84\xC3\x85\xC3\x86\xC3\x87\xC3\x88\xC3\x89\xC3\x8A\xC3\x8B\xC3\x8C"
+ "\xC3\x8D\xC3\x8E\xC3\x8F\xC3\x90\xC3\x91\xC3\x92\xC3\x93\xC3\x94\xC3\x95"
+ "\xC3\x96\xC3\x97\xC3\x98\xC3\x99\xC3\x9A\xC3\x9B\xC3\x9C\xC3\x9D\xC3\x9E"
+ "\xC3\x9F\xC3\xA0\xC3\xA1\xC3\xA2\xC3\xA3\xC3\xA4\xC3\xA5\xC3\xA6\xC3\xA7"
+ "\xC3\xA8\xC3\xA9\xC3\xAA\xC3\xAB\xC3\xAC\xC3\xAD\xC3\xAE\xC3\xAF\xC3\xB0"
+ "\xC3\xB1\xC3\xB2\xC3\xB3\xC3\xB4\xC3\xB5\xC3\xB6\xC3\xB7\xC3\xB8\xC3\xB9"
+ "\xC3\xBA\xC3\xBB\xC3\xBC\xC3\xBD\xC3\xBE\xC3\xBF";
+
+ 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);
+
+ static const char kExpected[] = "{\"web\":\"\xE7\xBD\x91\xE9\xA1\xB5\"}";
+
+ std::string actual;
+ JSONStringValueSerializer serializer(&actual);
+ ASSERT_TRUE(serializer.Serialize(root));
+ ASSERT_EQ(kExpected, actual);
+
+ // escaped ascii text -> json
+ JSONStringValueDeserializer deserializer(kExpected);
+ scoped_ptr<Value> deserial_root = deserializer.Deserialize(NULL, NULL);
+ ASSERT_TRUE(deserial_root.get());
+ DictionaryValue* dict_root =
+ static_cast<DictionaryValue*>(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);
+
+ static const char kExpected[] = "{\"test\":\"\\u0001\\u0002\"}";
+
+ std::string actual;
+ JSONStringValueSerializer serializer(&actual);
+ ASSERT_TRUE(serializer.Serialize(root));
+ ASSERT_EQ(kExpected, actual);
+
+ // escaped ascii text -> json
+ JSONStringValueDeserializer deserializer(kExpected);
+ scoped_ptr<Value> deserial_root = deserializer.Deserialize(NULL, NULL);
+ ASSERT_TRUE(deserial_root.get());
+ DictionaryValue* dict_root =
+ static_cast<DictionaryValue*>(deserial_root.get());
+ string16 test_value;
+ ASSERT_TRUE(dict_root->GetString("test", &test_value));
+ ASSERT_EQ(test, test_value);
+
+ // Test converting escaped regular chars
+ static const char kEscapedChars[] = "{\"test\":\"\\u0067\\u006f\"}";
+ JSONStringValueDeserializer deserializer2(kEscapedChars);
+ deserial_root = deserializer2.Deserialize(NULL, NULL);
+ ASSERT_TRUE(deserial_root.get());
+ dict_root = static_cast<DictionaryValue*>(deserial_root.get());
+ ASSERT_TRUE(dict_root->GetString("test", &test_value));
+ ASSERT_EQ(ASCIIToUTF16("go"), test_value);
+}
+
+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 ]");
+
+ // It's ok to have a comment in a string.
+ scoped_ptr<Value> root = JSONReader::Read("[\"// ok\\n /* foo */ \"]");
+ ASSERT_TRUE(root.get() && root->IsType(Value::TYPE_LIST));
+ ListValue* list = static_cast<ListValue*>(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 = JSONReader::Read("/* /* inner */ outer */ [ 1 ]");
+ ASSERT_FALSE(root.get());
+
+ // Not a open comment token.
+ root = JSONReader::Read("/ * * / [1]");
+ ASSERT_FALSE(root.get());
+}
+
+#if !defined(__ANDROID__) && !defined(__ANDROID_HOST__)
+class JSONFileValueSerializerTest : public testing::Test {
+ protected:
+ 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));
+
+ JSONFileValueDeserializer deserializer(original_file_path);
+ scoped_ptr<Value> root;
+ root = deserializer.Deserialize(NULL, NULL);
+
+ ASSERT_TRUE(root.get());
+ ASSERT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
+
+ DictionaryValue* root_dict = static_cast<DictionaryValue*>(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));
+
+ JSONFileValueDeserializer deserializer(original_file_path);
+ scoped_ptr<Value> root;
+ root = 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));
+ JSONFileValueDeserializer deserializer(source_file_path);
+ scoped_ptr<Value> root;
+ root = deserializer.Deserialize(NULL, NULL);
+ ASSERT_TRUE(root.get());
+}
+#endif // !__ANDROID__ && !__ANDROID_HOST__
+
+} // namespace
+
+} // namespace base
diff --git a/base/json/json_writer.cc b/base/json/json_writer.cc
index abfead8007..19bc0da972 100644
--- a/base/json/json_writer.cc
+++ b/base/json/json_writer.cc
@@ -4,13 +4,17 @@
#include "base/json/json_writer.h"
+#include <stdint.h>
+
#include <cmath>
+#include <limits>
#include "base/json/string_escape.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
+#include "build/build_config.h"
namespace base {
@@ -79,10 +83,10 @@ bool JSONWriter::BuildJSONString(const Value& node, size_t depth) {
bool result = node.GetAsDouble(&value);
DCHECK(result);
if (omit_double_type_preservation_ &&
- value <= kint64max &&
- value >= kint64min &&
+ value <= std::numeric_limits<int64_t>::max() &&
+ value >= std::numeric_limits<int64_t>::min() &&
std::floor(value) == value) {
- json_string_->append(Int64ToString(static_cast<int64>(value)));
+ json_string_->append(Int64ToString(static_cast<int64_t>(value)));
return result;
}
std::string real = DoubleToString(value);
diff --git a/base/json/json_writer.h b/base/json/json_writer.h
index 5711665cbe..ef43341409 100644
--- a/base/json/json_writer.h
+++ b/base/json/json_writer.h
@@ -5,10 +5,12 @@
#ifndef BASE_JSON_JSON_WRITER_H_
#define BASE_JSON_JSON_WRITER_H_
+#include <stddef.h>
+
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
namespace base {
diff --git a/base/json/json_writer_unittest.cc b/base/json/json_writer_unittest.cc
index 0daeafce1d..a62b3ba989 100644
--- a/base/json/json_writer_unittest.cc
+++ b/base/json/json_writer_unittest.cc
@@ -4,6 +4,7 @@
#include "base/json/json_writer.h"
#include "base/values.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
@@ -57,10 +58,10 @@ TEST(JSONWriterTest, NestedTypes) {
scoped_ptr<ListValue> list(new ListValue());
scoped_ptr<DictionaryValue> inner_dict(new DictionaryValue());
inner_dict->SetInteger("inner int", 10);
- list->Append(inner_dict.Pass());
+ list->Append(std::move(inner_dict));
list->Append(make_scoped_ptr(new ListValue()));
list->AppendBoolean(true);
- root_dict.Set("list", list.Pass());
+ root_dict.Set("list", std::move(list));
// Test the pretty-printer.
EXPECT_TRUE(JSONWriter::Write(root_dict, &output_js));
@@ -92,7 +93,7 @@ TEST(JSONWriterTest, KeysWithPeriods) {
period_dict.SetIntegerWithoutPathExpansion("c", 2);
scoped_ptr<DictionaryValue> period_dict2(new DictionaryValue());
period_dict2->SetIntegerWithoutPathExpansion("g.h.i.j", 1);
- period_dict.SetWithoutPathExpansion("d.e.f", period_dict2.Pass());
+ period_dict.SetWithoutPathExpansion("d.e.f", std::move(period_dict2));
EXPECT_TRUE(JSONWriter::Write(period_dict, &output_js));
EXPECT_EQ("{\"a.b\":3,\"c\":2,\"d.e.f\":{\"g.h.i.j\":1}}", output_js);
diff --git a/base/json/string_escape.cc b/base/json/string_escape.cc
index 469f9f98c0..f67fa93bf2 100644
--- a/base/json/string_escape.cc
+++ b/base/json/string_escape.cc
@@ -4,6 +4,10 @@
#include "base/json/string_escape.h"
+#include <stddef.h>
+#include <stdint.h>
+
+#include <limits>
#include <string>
#include "base/strings/string_util.h"
@@ -20,15 +24,15 @@ namespace {
const char kU16EscapeFormat[] = "\\u%04X";
// The code point to output for an invalid input code unit.
-const uint32 kReplacementCodePoint = 0xFFFD;
+const uint32_t kReplacementCodePoint = 0xFFFD;
// Used below in EscapeSpecialCodePoint().
-COMPILE_ASSERT('<' == 0x3C, less_than_sign_is_0x3c);
+static_assert('<' == 0x3C, "less than sign must be 0x3c");
// Try to escape the |code_point| if it is a known special character. If
// successful, returns true and appends the escape sequence to |dest|. This
// isn't required by the spec, but it's more readable by humans.
-bool EscapeSpecialCodePoint(uint32 code_point, std::string* dest) {
+bool EscapeSpecialCodePoint(uint32_t code_point, std::string* dest) {
// 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.
@@ -59,6 +63,14 @@ bool EscapeSpecialCodePoint(uint32 code_point, std::string* dest) {
case '<':
dest->append("\\u003C");
break;
+ // Escape the "Line Separator" and "Paragraph Separator" characters, since
+ // they should be treated like a new line \r or \n.
+ case 0x2028:
+ dest->append("\\u2028");
+ break;
+ case 0x2029:
+ dest->append("\\u2029");
+ break;
default:
return false;
}
@@ -72,12 +84,13 @@ bool EscapeJSONStringImpl(const S& str, bool put_in_quotes, std::string* dest) {
if (put_in_quotes)
dest->push_back('"');
- // Casting is necessary because ICU uses int32. Try and do so safely.
- CHECK_LE(str.length(), static_cast<size_t>(kint32max));
- const int32 length = static_cast<int32>(str.length());
+ // Casting is necessary because ICU uses int32_t. Try and do so safely.
+ CHECK_LE(str.length(),
+ static_cast<size_t>(std::numeric_limits<int32_t>::max()));
+ const int32_t length = static_cast<int32_t>(str.length());
- for (int32 i = 0; i < length; ++i) {
- uint32 code_point;
+ for (int32_t i = 0; i < length; ++i) {
+ uint32_t code_point;
if (!ReadUnicodeCharacter(str.data(), length, &i, &code_point)) {
code_point = kReplacementCodePoint;
did_replacement = true;
diff --git a/base/json/string_escape_unittest.cc b/base/json/string_escape_unittest.cc
index 100373fccd..ae3d82ad5e 100644
--- a/base/json/string_escape_unittest.cc
+++ b/base/json/string_escape_unittest.cc
@@ -4,6 +4,9 @@
#include "base/json/string_escape.h"
+#include <stddef.h>
+
+#include "base/macros.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -21,6 +24,8 @@ TEST(JSONStringEscapeTest, EscapeUTF8) {
{"b\x0f\x7f\xf0\xff!", // \xf0\xff is not a valid UTF-8 unit.
"b\\u000F\x7F\xEF\xBF\xBD\xEF\xBF\xBD!"},
{"c<>d", "c\\u003C>d"},
+ {"Hello\xe2\x80\xa8world", "Hello\\u2028world"},
+ {"\xe2\x80\xa9purple", "\\u2029purple"},
};
for (size_t i = 0; i < arraysize(cases); ++i) {
@@ -79,6 +84,8 @@ TEST(JSONStringEscapeTest, EscapeUTF16) {
"a\\b\\f\\n\\r\\t\\u000B\\u0001\\\\.\\\"z"},
{L"b\x0f\x7f\xf0\xff!", "b\\u000F\x7F\xC3\xB0\xC3\xBF!"},
{L"c<>d", "c\\u003C>d"},
+ {L"Hello\u2028world", "Hello\\u2028world"},
+ {L"\u2029purple", "\\u2029purple"},
};
for (size_t i = 0; i < arraysize(cases); ++i) {
diff --git a/base/lazy_instance.cc b/base/lazy_instance.cc
index 594c1fee4f..54680655a2 100644
--- a/base/lazy_instance.cc
+++ b/base/lazy_instance.cc
@@ -6,7 +6,6 @@
#include "base/at_exit.h"
#include "base/atomicops.h"
-#include "base/basictypes.h"
#include "base/threading/platform_thread.h"
namespace base {
diff --git a/base/lazy_instance.h b/base/lazy_instance.h
index 42006b9e4f..1a921e67aa 100644
--- a/base/lazy_instance.h
+++ b/base/lazy_instance.h
@@ -39,7 +39,6 @@
#include "base/atomicops.h"
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/logging.h"
#include "base/memory/aligned_memory.h"
#include "base/threading/thread_restrictions.h"
diff --git a/base/lazy_instance_unittest.cc b/base/lazy_instance_unittest.cc
index ec9ef26732..8947b1291f 100644
--- a/base/lazy_instance_unittest.cc
+++ b/base/lazy_instance_unittest.cc
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stddef.h>
+
#include "base/at_exit.h"
#include "base/atomic_sequence_num.h"
#include "base/lazy_instance.h"
diff --git a/base/location.h b/base/location.h
index 477dc02227..d3bb23c63e 100644
--- a/base/location.h
+++ b/base/location.h
@@ -5,11 +5,12 @@
#ifndef BASE_LOCATION_H_
#define BASE_LOCATION_H_
+#include <stddef.h>
+
#include <cassert>
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/containers/hash_tables.h"
namespace tracked_objects {
@@ -58,11 +59,7 @@ class BASE_EXPORT Location {
// it comes from __FILE__, so no need to check the contents of the string.
// See the definition of FROM_HERE in location.h, and how it is used
// elsewhere.
-
- // Due to inconsistent definitions of uint64_t and uintptr_t, casting the
- // file name pointer to a uintptr_t causes a compiler error for some
- // platforms. The solution is to explicitly cast it to a uint64_t.
- return base::HashPair(reinterpret_cast<uint64_t>(location.file_name()),
+ return base::HashPair(reinterpret_cast<uintptr_t>(location.file_name()),
location.line_number());
}
};
diff --git a/base/logging.cc b/base/logging.cc
index 74401f7922..3450b9a1b2 100644
--- a/base/logging.cc
+++ b/base/logging.cc
@@ -4,9 +4,17 @@
#include "base/logging.h"
+#include <limits.h>
+#include <stdint.h>
+
+#include "base/macros.h"
+#include "build/build_config.h"
+
#if defined(OS_WIN)
#include <io.h>
#include <windows.h>
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
typedef HANDLE FileHandle;
typedef HANDLE MutexHandle;
// Windows warns on using write(). It prefers _write().
@@ -14,6 +22,8 @@ typedef HANDLE MutexHandle;
// Windows doesn't define STDERR_FILENO. Define it here.
#define STDERR_FILENO 2
#elif defined(OS_MACOSX)
+#include <asl.h>
+#include <CoreFoundation/CoreFoundation.h>
#include <mach/mach.h>
#include <mach/mach_time.h>
#include <mach-o/dyld.h>
@@ -28,10 +38,12 @@ typedef HANDLE MutexHandle;
#if defined(OS_POSIX)
#include <errno.h>
+#include <paths.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/stat.h>
#include <unistd.h>
#define MAX_PATH PATH_MAX
typedef FILE* FileHandle;
@@ -56,6 +68,7 @@ typedef pthread_mutex_t* MutexHandle;
#include "base/strings/string_piece.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/synchronization/lock_impl.h"
#include "base/threading/platform_thread.h"
@@ -121,7 +134,7 @@ LogMessageHandlerFunction log_message_handler = nullptr;
// Helper functions to wrap platform differences.
-int32 CurrentProcessId() {
+int32_t CurrentProcessId() {
#if defined(OS_WIN)
return GetCurrentProcessId();
#elif defined(OS_POSIX)
@@ -129,7 +142,7 @@ int32 CurrentProcessId() {
#endif
}
-uint64 TickCount() {
+uint64_t TickCount() {
#if defined(OS_WIN)
return GetTickCount();
#elif defined(OS_MACOSX)
@@ -142,9 +155,8 @@ uint64 TickCount() {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
- uint64 absolute_micro =
- static_cast<int64>(ts.tv_sec) * 1000000 +
- static_cast<int64>(ts.tv_nsec) / 1000;
+ uint64_t absolute_micro = static_cast<int64_t>(ts.tv_sec) * 1000000 +
+ static_cast<int64_t>(ts.tv_nsec) / 1000;
return absolute_micro;
#endif
@@ -178,6 +190,9 @@ PathString GetDefaultLogFile() {
#endif
}
+// We don't need locks on Windows for atomically appending to files. The OS
+// provides this functionality.
+#if !defined(OS_WIN)
// 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
@@ -199,48 +214,17 @@ class LoggingLock {
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(nullptr, FALSE, t.c_str());
-
- if (log_mutex == nullptr) {
-#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 {
+
+ if (lock_log_file != LOCK_LOG_FILE)
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)
+#if defined(OS_POSIX)
pthread_mutex_lock(&log_mutex);
#endif
} else {
@@ -251,9 +235,7 @@ class LoggingLock {
static void UnlockLogging() {
if (lock_log_file == LOCK_LOG_FILE) {
-#if defined(OS_WIN)
- ReleaseMutex(log_mutex);
-#elif defined(OS_POSIX)
+#if defined(OS_POSIX)
pthread_mutex_unlock(&log_mutex);
#endif
} else {
@@ -268,9 +250,7 @@ class LoggingLock {
// 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)
+#if defined(OS_POSIX)
static pthread_mutex_t log_mutex;
#endif
@@ -285,13 +265,12 @@ base::internal::LockImpl* LoggingLock::log_lock = nullptr;
// static
LogLockingState LoggingLock::lock_log_file = LOCK_LOG_FILE;
-#if defined(OS_WIN)
-// static
-MutexHandle LoggingLock::log_mutex = nullptr;
-#elif defined(OS_POSIX)
+#if defined(OS_POSIX)
pthread_mutex_t LoggingLock::log_mutex = PTHREAD_MUTEX_INITIALIZER;
#endif
+#endif // OS_WIN
+
// Called by logging functions to ensure that |g_log_file| is initialized
// and can be used for writing. Returns false if the file could not be
// initialized. |g_log_file| will be nullptr in this case.
@@ -307,12 +286,23 @@ bool InitializeLogFileHandle() {
if ((g_logging_destination & LOG_TO_FILE) != 0) {
#if defined(OS_WIN)
- g_log_file = CreateFile(g_log_file_name->c_str(), GENERIC_WRITE,
+ // The FILE_APPEND_DATA access mask ensures that the file is atomically
+ // appended to across accesses from multiple threads.
+ // https://msdn.microsoft.com/en-us/library/windows/desktop/aa364399(v=vs.85).aspx
+ // https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx
+ g_log_file = CreateFile(g_log_file_name->c_str(), FILE_APPEND_DATA,
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
if (g_log_file == INVALID_HANDLE_VALUE || g_log_file == nullptr) {
// try the current directory
- g_log_file = CreateFile(L".\\debug.log", GENERIC_WRITE,
+ base::FilePath file_path;
+ if (!base::GetCurrentDirectory(&file_path))
+ return false;
+
+ *g_log_file_name = file_path.Append(
+ FILE_PATH_LITERAL("debug.log")).value();
+
+ g_log_file = CreateFile(g_log_file_name->c_str(), FILE_APPEND_DATA,
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
if (g_log_file == INVALID_HANDLE_VALUE || g_log_file == nullptr) {
@@ -320,7 +310,6 @@ bool InitializeLogFileHandle() {
return false;
}
}
- SetFilePointer(g_log_file, 0, 0, FILE_END);
#elif defined(OS_POSIX)
g_log_file = fopen(g_log_file_name->c_str(), "a");
if (g_log_file == nullptr)
@@ -385,8 +374,10 @@ bool BaseInitLoggingImpl(const LoggingSettings& settings) {
if ((g_logging_destination & LOG_TO_FILE) == 0)
return true;
+#if !defined(OS_WIN)
LoggingLock::Init(settings.lock_log, settings.log_file);
LoggingLock logging_lock;
+#endif
// Calling InitLogging twice or after some log call has already opened the
// default log file will re-initialize to the new options.
@@ -409,6 +400,17 @@ int GetMinLogLevel() {
return g_min_log_level;
}
+bool ShouldCreateLogMessage(int severity) {
+ if (severity < g_min_log_level)
+ return false;
+
+ // Return true here unless we know ~LogMessage won't do anything. Note that
+ // ~LogMessage writes to stderr if severity_ >= kAlwaysPrintErrorLevel, even
+ // when g_logging_destination is LOG_NONE.
+ return g_logging_destination != LOG_NONE || log_message_handler ||
+ severity >= kAlwaysPrintErrorLevel;
+}
+
int GetVlogVerbosity() {
return std::max(-1, LOG_INFO - GetMinLogLevel());
}
@@ -473,38 +475,8 @@ void DisplayDebugMessageInDialog(const std::string& str) {
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(nullptr, 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 = base::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], nullptr, nullptr, false, 0,
- nullptr, nullptr, &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(nullptr, &cmdline[0], L"Fatal error",
- MB_OK | MB_ICONHAND | MB_TOPMOST);
- }
+ MessageBoxW(nullptr, base::UTF8ToUTF16(str).c_str(), 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.
@@ -526,6 +498,12 @@ LogMessage::LogMessage(const char* file, int line, LogSeverity severity)
Init(file, line);
}
+LogMessage::LogMessage(const char* file, int line, const char* condition)
+ : severity_(LOG_FATAL), file_(file), line_(line) {
+ Init(file, line);
+ stream_ << "Check failed: " << condition << ". ";
+}
+
LogMessage::LogMessage(const char* file, int line, std::string* result)
: severity_(LOG_FATAL), file_(file), line_(line) {
Init(file, line);
@@ -542,9 +520,9 @@ LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
}
LogMessage::~LogMessage() {
-#if !defined(NDEBUG) && !defined(OS_NACL) && !defined(__UCLIBC__)
- if (severity_ == LOG_FATAL) {
- // Include a stack trace on a fatal.
+#if !defined(OFFICIAL_BUILD) && !defined(OS_NACL) && !defined(__UCLIBC__)
+ if (severity_ == LOG_FATAL && !base::debug::BeingDebugged()) {
+ // Include a stack trace on a fatal, unless a debugger is attached.
base::debug::StackTrace trace;
stream_ << std::endl; // Newline to separate from log message.
trace.OutputToStream(&stream_);
@@ -564,6 +542,121 @@ LogMessage::~LogMessage() {
if ((g_logging_destination & LOG_TO_SYSTEM_DEBUG_LOG) != 0) {
#if defined(OS_WIN)
OutputDebugStringA(str_newline.c_str());
+#elif defined(OS_MACOSX)
+ // In LOG_TO_SYSTEM_DEBUG_LOG mode, log messages are always written to
+ // stderr. If stderr is /dev/null, also log via ASL (Apple System Log). If
+ // there's something weird about stderr, assume that log messages are going
+ // nowhere and log via ASL too. Messages logged via ASL show up in
+ // Console.app.
+ //
+ // Programs started by launchd, as UI applications normally are, have had
+ // stderr connected to /dev/null since OS X 10.8. Prior to that, stderr was
+ // a pipe to launchd, which logged what it received (see log_redirect_fd in
+ // 10.7.5 launchd-392.39/launchd/src/launchd_core_logic.c).
+ //
+ // Another alternative would be to determine whether stderr is a pipe to
+ // launchd and avoid logging via ASL only in that case. See 10.7.5
+ // CF-635.21/CFUtilities.c also_do_stderr(). This would result in logging to
+ // both stderr and ASL even in tests, where it's undesirable to log to the
+ // system log at all.
+ //
+ // Note that the ASL client by default discards messages whose levels are
+ // below ASL_LEVEL_NOTICE. It's possible to change that with
+ // asl_set_filter(), but this is pointless because syslogd normally applies
+ // the same filter.
+ const bool log_via_asl = []() {
+ struct stat stderr_stat;
+ if (fstat(fileno(stderr), &stderr_stat) == -1) {
+ return true;
+ }
+ if (!S_ISCHR(stderr_stat.st_mode)) {
+ return false;
+ }
+
+ struct stat dev_null_stat;
+ if (stat(_PATH_DEVNULL, &dev_null_stat) == -1) {
+ return true;
+ }
+
+ return !S_ISCHR(dev_null_stat.st_mode) ||
+ stderr_stat.st_rdev == dev_null_stat.st_rdev;
+ }();
+
+ if (log_via_asl) {
+ // Log roughly the same way that CFLog() and NSLog() would. See 10.10.5
+ // CF-1153.18/CFUtilities.c __CFLogCString().
+ //
+ // The ASL facility is set to the main bundle ID if available. Otherwise,
+ // "com.apple.console" is used.
+ CFBundleRef main_bundle = CFBundleGetMainBundle();
+ CFStringRef main_bundle_id_cf =
+ main_bundle ? CFBundleGetIdentifier(main_bundle) : nullptr;
+ std::string asl_facility =
+ main_bundle_id_cf ? base::SysCFStringRefToUTF8(main_bundle_id_cf)
+ : std::string("com.apple.console");
+
+ class ASLClient {
+ public:
+ explicit ASLClient(const std::string& asl_facility)
+ : client_(asl_open(nullptr,
+ asl_facility.c_str(),
+ ASL_OPT_NO_DELAY)) {}
+ ~ASLClient() { asl_close(client_); }
+
+ aslclient get() const { return client_; }
+
+ private:
+ aslclient client_;
+ DISALLOW_COPY_AND_ASSIGN(ASLClient);
+ } asl_client(asl_facility);
+
+ class ASLMessage {
+ public:
+ ASLMessage() : message_(asl_new(ASL_TYPE_MSG)) {}
+ ~ASLMessage() { asl_free(message_); }
+
+ aslmsg get() const { return message_; }
+
+ private:
+ aslmsg message_;
+ DISALLOW_COPY_AND_ASSIGN(ASLMessage);
+ } asl_message;
+
+ // By default, messages are only readable by the admin group. Explicitly
+ // make them readable by the user generating the messages.
+ char euid_string[12];
+ snprintf(euid_string, arraysize(euid_string), "%d", geteuid());
+ asl_set(asl_message.get(), ASL_KEY_READ_UID, euid_string);
+
+ // Map Chrome log severities to ASL log levels.
+ const char* const asl_level_string = [](LogSeverity severity) {
+ // ASL_LEVEL_* are ints, but ASL needs equivalent strings. This
+ // non-obvious two-step macro trick achieves what's needed.
+ // https://gcc.gnu.org/onlinedocs/cpp/Stringification.html
+#define ASL_LEVEL_STR(level) ASL_LEVEL_STR_X(level)
+#define ASL_LEVEL_STR_X(level) #level
+ switch (severity) {
+ case LOG_INFO:
+ return ASL_LEVEL_STR(ASL_LEVEL_INFO);
+ case LOG_WARNING:
+ return ASL_LEVEL_STR(ASL_LEVEL_WARNING);
+ case LOG_ERROR:
+ return ASL_LEVEL_STR(ASL_LEVEL_ERR);
+ case LOG_FATAL:
+ return ASL_LEVEL_STR(ASL_LEVEL_CRIT);
+ default:
+ return severity < 0 ? ASL_LEVEL_STR(ASL_LEVEL_DEBUG)
+ : ASL_LEVEL_STR(ASL_LEVEL_NOTICE);
+ }
+#undef ASL_LEVEL_STR
+#undef ASL_LEVEL_STR_X
+ }(severity_);
+ asl_set(asl_message.get(), ASL_KEY_LEVEL, asl_level_string);
+
+ asl_set(asl_message.get(), ASL_KEY_MSG, str_newline.c_str());
+
+ asl_send(asl_client.get(), asl_message.get());
+ }
#elif defined(OS_ANDROID) || defined(__ANDROID__)
android_LogPriority priority =
(severity_ < 0) ? ANDROID_LOG_VERBOSE : ANDROID_LOG_UNKNOWN;
@@ -611,11 +704,12 @@ LogMessage::~LogMessage() {
// 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.
+#if !defined(OS_WIN)
LoggingLock::Init(LOCK_LOG_FILE, nullptr);
LoggingLock logging_lock;
+#endif
if (InitializeLogFileHandle()) {
#if defined(OS_WIN)
- SetFilePointer(g_log_file, 0, 0, SEEK_END);
DWORD num_written;
WriteFile(g_log_file,
static_cast<const void*>(str_newline.c_str()),
@@ -647,7 +741,11 @@ LogMessage::~LogMessage() {
// information, and displaying message boxes when the application is
// hosed can cause additional problems.
#ifndef NDEBUG
- DisplayDebugMessageInDialog(stream_.str());
+ if (!base::debug::BeingDebugged()) {
+ // Displaying a dialog is unnecessary when debugging and can complicate
+ // debugging.
+ DisplayDebugMessageInDialog(stream_.str());
+ }
#endif
// Crash the process to generate a dump.
base::debug::BreakDebugger();
@@ -772,7 +870,9 @@ ErrnoLogMessage::~ErrnoLogMessage() {
#endif // defined(OS_WIN)
void CloseLogFile() {
+#if !defined(OS_WIN)
LoggingLock logging_lock;
+#endif
CloseLogFileUnlocked();
}
@@ -811,6 +911,10 @@ void RawLog(int level, const char* message) {
#undef write
#if defined(OS_WIN)
+bool IsLoggingToFileEnabled() {
+ return g_logging_destination & LOG_TO_FILE;
+}
+
std::wstring GetLogFileFullPath() {
if (g_log_file_name)
return *g_log_file_name;
diff --git a/base/logging.h b/base/logging.h
index 6fb0dd972f..c79c84c6bc 100644
--- a/base/logging.h
+++ b/base/logging.h
@@ -5,15 +5,17 @@
#ifndef BASE_LOGGING_H_
#define BASE_LOGGING_H_
+#include <stddef.h>
+
#include <cassert>
-#include <string>
#include <cstring>
#include <sstream>
+#include <string>
#include <typeinfo>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/debug/debugger.h"
+#include "base/macros.h"
#include "build/build_config.h"
//
@@ -267,6 +269,9 @@ BASE_EXPORT void SetMinLogLevel(int level);
// Gets the current log level.
BASE_EXPORT int GetMinLogLevel();
+// Used by LOG_IS_ON to lazy-evaluate stream arguments.
+BASE_EXPORT bool ShouldCreateLogMessage(int severity);
+
// Gets the VLOG default verbosity level.
BASE_EXPORT int GetVlogVerbosity();
@@ -369,7 +374,7 @@ const LogSeverity LOG_0 = LOG_ERROR;
// 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())
+ (::logging::ShouldCreateLogMessage(::logging::LOG_##severity))
// We can't do any caching tricks with VLOG_IS_ON() like the
// google-glog version since it requires GCC extensions. This means
@@ -455,6 +460,21 @@ const LogSeverity LOG_0 = LOG_ERROR;
#define EAT_STREAM_PARAMETERS \
true ? (void) 0 : ::logging::LogMessageVoidify() & LOG_STREAM(FATAL)
+// Captures the result of a CHECK_EQ (for example) and facilitates testing as a
+// boolean.
+class CheckOpResult {
+ public:
+ // |message| must be null if and only if the check failed.
+ CheckOpResult(std::string* message) : message_(message) {}
+ // Returns true if the check succeeded.
+ operator bool() const { return !message_; }
+ // Returns the message.
+ std::string* message() { return message_; }
+
+ private:
+ std::string* message_;
+};
+
// 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.
@@ -465,7 +485,7 @@ const LogSeverity LOG_0 = LOG_ERROR;
#if defined(OFFICIAL_BUILD) && defined(NDEBUG) && !defined(OS_ANDROID)
// Make all CHECK functions discard their log strings to reduce code
-// bloat for official release builds.
+// bloat for official release builds (except Android).
// TODO(akalin): This would be more valuable if there were some way to
// remove BreakDebugger() from the backtrace, perhaps by turning it
@@ -499,9 +519,10 @@ const LogSeverity LOG_0 = LOG_ERROR;
#else // _PREFAST_
-#define CHECK(condition) \
- LAZY_STREAM(LOG_STREAM(FATAL), !(condition)) \
- << "Check failed: " #condition ". "
+// Do as much work as possible out of line to reduce inline code size.
+#define CHECK(condition) \
+ LAZY_STREAM(logging::LogMessage(__FILE__, __LINE__, #condition).stream(), \
+ !(condition))
#define PCHECK(condition) \
LAZY_STREAM(PLOG_STREAM(FATAL), !(condition)) \
@@ -511,14 +532,18 @@ const LogSeverity LOG_0 = LOG_ERROR;
// 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()
+// The 'switch' is used to prevent the 'else' from being ambiguous when the
+// macro is used in an 'if' clause such as:
+// if (a == 1)
+// CHECK_EQ(2, a);
+#define CHECK_OP(name, op, val1, val2) \
+ switch (0) case 0: default: \
+ if (logging::CheckOpResult true_if_passed = \
+ logging::Check##name##Impl((val1), (val2), \
+ #val1 " " #op " " #val2)) \
+ ; \
+ else \
+ logging::LogMessage(__FILE__, __LINE__, true_if_passed.message()).stream()
#endif
@@ -580,7 +605,6 @@ DEFINE_CHECK_OP_IMPL(GT, > )
#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)
-#define CHECK_IMPLIES(val1, val2) CHECK(!(val1) || (val2))
#if defined(NDEBUG)
#define ENABLE_DLOG 0
@@ -694,12 +718,20 @@ const LogSeverity LOG_DCHECK = LOG_INFO;
// 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()
+// The 'switch' is used to prevent the 'else' from being ambiguous when the
+// macro is used in an 'if' clause such as:
+// if (a == 1)
+// DCHECK_EQ(2, a);
+#define DCHECK_OP(name, op, val1, val2) \
+ switch (0) case 0: default: \
+ if (logging::CheckOpResult true_if_passed = \
+ DCHECK_IS_ON() ? \
+ logging::Check##name##Impl((val1), (val2), \
+ #val1 " " #op " " #val2) : nullptr) \
+ ; \
+ else \
+ logging::LogMessage(__FILE__, __LINE__, ::logging::LOG_DCHECK, \
+ true_if_passed.message()).stream()
// Equality/Inequality checks - compare two values, and log a
// LOG_DCHECK message including the two values when the result is not
@@ -726,7 +758,6 @@ const LogSeverity LOG_DCHECK = LOG_INFO;
#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 DCHECK_IMPLIES(val1, val2) DCHECK(!(val1) || (val2))
#if !DCHECK_IS_ON() && defined(OS_CHROMEOS)
// Implement logging of NOTREACHED() as a dedicated function to get function
@@ -756,6 +787,9 @@ class BASE_EXPORT LogMessage {
// Used for LOG(severity).
LogMessage(const char* file, int line, LogSeverity severity);
+ // Used for CHECK(). Implied severity = LOG_FATAL.
+ LogMessage(const char* file, int line, const char* condition);
+
// Used for CHECK_EQ(), etc. Takes ownership of the given string.
// Implied severity = LOG_FATAL.
LogMessage(const char* file, int line, std::string* result);
@@ -804,7 +838,7 @@ class BASE_EXPORT 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) {
+inline void LogAtLevel(int log_level, const std::string& msg) {
LogMessage(__FILE__, __LINE__, log_level).stream() << msg;
}
@@ -890,6 +924,9 @@ BASE_EXPORT void RawLog(int level, const char* message);
} while (0)
#if defined(OS_WIN)
+// Returns true if logging to file is enabled.
+BASE_EXPORT bool IsLoggingToFileEnabled();
+
// Returns the default log file path.
BASE_EXPORT std::wstring GetLogFileFullPath();
#endif
@@ -928,9 +965,9 @@ BASE_EXPORT std::wstring GetLogFileFullPath();
#define NOTIMPLEMENTED() EAT_STREAM_PARAMETERS
#elif NOTIMPLEMENTED_POLICY == 1
// TODO, figure out how to generate a warning
-#define NOTIMPLEMENTED() COMPILE_ASSERT(false, NOT_IMPLEMENTED)
+#define NOTIMPLEMENTED() static_assert(false, "NOT_IMPLEMENTED")
#elif NOTIMPLEMENTED_POLICY == 2
-#define NOTIMPLEMENTED() COMPILE_ASSERT(false, NOT_IMPLEMENTED)
+#define NOTIMPLEMENTED() static_assert(false, "NOT_IMPLEMENTED")
#elif NOTIMPLEMENTED_POLICY == 3
#define NOTIMPLEMENTED() NOTREACHED()
#elif NOTIMPLEMENTED_POLICY == 4
diff --git a/base/logging_unittest.cc b/base/logging_unittest.cc
index 8b9701a545..22fb855b62 100644
--- a/base/logging_unittest.cc
+++ b/base/logging_unittest.cc
@@ -2,9 +2,9 @@
// 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/compiler_specific.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -122,7 +122,7 @@ TEST_F(LoggingTest, LogIsOn) {
EXPECT_TRUE(kDfatalIsFatal == LOG_IS_ON(DFATAL));
}
-TEST_F(LoggingTest, LoggingIsLazy) {
+TEST_F(LoggingTest, LoggingIsLazyBySeverity) {
MockLogSource mock_log_source;
EXPECT_CALL(mock_log_source, Log()).Times(0);
@@ -151,6 +151,24 @@ TEST_F(LoggingTest, LoggingIsLazy) {
DVPLOG_IF(1, true) << mock_log_source.Log();
}
+TEST_F(LoggingTest, LoggingIsLazyByDestination) {
+ MockLogSource mock_log_source;
+ MockLogSource mock_log_source_error;
+ EXPECT_CALL(mock_log_source, Log()).Times(0);
+
+ // Severity >= ERROR is always printed to stderr.
+ EXPECT_CALL(mock_log_source_error, Log()).Times(1).
+ WillRepeatedly(Return("log message"));
+
+ LoggingSettings settings;
+ settings.logging_dest = LOG_NONE;
+ InitLogging(settings);
+
+ LOG(INFO) << mock_log_source.Log();
+ LOG(WARNING) << mock_log_source.Log();
+ LOG(ERROR) << mock_log_source_error.Log();
+}
+
// Official builds have CHECKs directly call BreakDebugger.
#if !defined(OFFICIAL_BUILD)
@@ -234,6 +252,30 @@ TEST_F(LoggingTest, DcheckReleaseBehavior) {
DCHECK_EQ(some_variable, 1) << "test";
}
+TEST_F(LoggingTest, DCheckEqStatements) {
+ bool reached = false;
+ if (false)
+ DCHECK_EQ(false, true); // Unreached.
+ else
+ DCHECK_EQ(true, reached = true); // Reached, passed.
+ ASSERT_EQ(DCHECK_IS_ON() ? true : false, reached);
+
+ if (false)
+ DCHECK_EQ(false, true); // Unreached.
+}
+
+TEST_F(LoggingTest, CheckEqStatements) {
+ bool reached = false;
+ if (false)
+ CHECK_EQ(false, true); // Unreached.
+ else
+ CHECK_EQ(true, reached = true); // Reached, passed.
+ ASSERT_TRUE(reached);
+
+ if (false)
+ CHECK_EQ(false, true); // Unreached.
+}
+
// Test that defining an operator<< for a type in a namespace doesn't prevent
// other code in that namespace from calling the operator<<(ostream, wstring)
// defined by logging.h. This can fail if operator<<(ostream, wstring) can't be
diff --git a/base/mac/OWNERS b/base/mac/OWNERS
index b092e06b76..093a9c8947 100644
--- a/base/mac/OWNERS
+++ b/base/mac/OWNERS
@@ -2,14 +2,5 @@ mark@chromium.org
thakis@chromium.org
# sdk_forward_declarations.[h|mm] will likely need to be modified by Cocoa
-# developers in general; keep in sync with OWNERS of //chrome/browser/ui/cocoa.
-per-file sdk_forward_declarations.*=asvitkine@chromium.org
-per-file sdk_forward_declarations.*=avi@chromium.org
-per-file sdk_forward_declarations.*=groby@chromium.org
-per-file sdk_forward_declarations.*=jeremy@chromium.org
-per-file sdk_forward_declarations.*=mark@chromium.org
-per-file sdk_forward_declarations.*=rohitrao@chromium.org
-per-file sdk_forward_declarations.*=rsesek@chromium.org
-per-file sdk_forward_declarations.*=shess@chromium.org
-per-file sdk_forward_declarations.*=tapted@chromium.org
-per-file sdk_forward_declarations.*=thakis@chromium.org
+# developers in general.
+per-file sdk_forward_declarations.*=file://chrome/browser/ui/cocoa/OWNERS
diff --git a/base/mac/foundation_util.h b/base/mac/foundation_util.h
index 353ed7c631..ee23a17fb1 100644
--- a/base/mac/foundation_util.h
+++ b/base/mac/foundation_util.h
@@ -13,6 +13,7 @@
#include "base/base_export.h"
#include "base/logging.h"
#include "base/mac/scoped_cftyperef.h"
+#include "build/build_config.h"
#if defined(__OBJC__)
#import <Foundation/Foundation.h>
@@ -373,6 +374,14 @@ 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);
+#if defined(__OBJC__)
+// Converts |range| to an NSRange, returning the new range in |range_out|.
+// Returns true if conversion was successful, false if the values of |range|
+// could not be converted to NSUIntegers.
+BASE_EXPORT bool CFRangeToNSRange(CFRange range,
+ NSRange* range_out) WARN_UNUSED_RESULT;
+#endif // defined(__OBJC__)
+
} // namespace mac
} // namespace base
diff --git a/base/mac/foundation_util.mm b/base/mac/foundation_util.mm
index 27d6e7c465..524f17cdb6 100644
--- a/base/mac/foundation_util.mm
+++ b/base/mac/foundation_util.mm
@@ -4,6 +4,7 @@
#include "base/mac/foundation_util.h"
+#include <stddef.h>
#include <stdlib.h>
#include <string.h>
@@ -11,7 +12,10 @@
#include "base/logging.h"
#include "base/mac/bundle_locations.h"
#include "base/mac/mac_logging.h"
+#include "base/macros.h"
+#include "base/numerics/safe_conversions.h"
#include "base/strings/sys_string_conversions.h"
+#include "build/build_config.h"
#if !defined(OS_IOS)
extern "C" {
@@ -430,6 +434,19 @@ FilePath NSStringToFilePath(NSString* str) {
return FilePath([str fileSystemRepresentation]);
}
+bool CFRangeToNSRange(CFRange range, NSRange* range_out) {
+ if (base::IsValueInRangeForNumericType<decltype(range_out->location)>(
+ range.location) &&
+ base::IsValueInRangeForNumericType<decltype(range_out->length)>(
+ range.length) &&
+ base::IsValueInRangeForNumericType<decltype(range_out->location)>(
+ range.location + range.length)) {
+ *range_out = NSMakeRange(range.location, range.length);
+ return true;
+ }
+ return false;
+}
+
} // namespace mac
} // namespace base
diff --git a/base/mac/libdispatch_task_runner.cc b/base/mac/libdispatch_task_runner.cc
index 7194c40fa6..9d18f97e3f 100644
--- a/base/mac/libdispatch_task_runner.cc
+++ b/base/mac/libdispatch_task_runner.cc
@@ -4,6 +4,8 @@
#include "base/mac/libdispatch_task_runner.h"
+#include <stdint.h>
+
#include "base/callback.h"
namespace base {
@@ -31,7 +33,7 @@ bool LibDispatchTaskRunner::PostDelayedTask(
task_copy.Run();
};
- int64 delay_nano =
+ int64_t delay_nano =
delay.InMicroseconds() * base::Time::kNanosecondsPerMicrosecond;
if (delay_nano > 0) {
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, delay_nano);
diff --git a/base/mac/mac_logging.h b/base/mac/mac_logging.h
index 5192b208f1..f55890285e 100644
--- a/base/mac/mac_logging.h
+++ b/base/mac/mac_logging.h
@@ -6,8 +6,8 @@
#define BASE_MAC_MAC_LOGGING_H_
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "build/build_config.h"
#if defined(OS_IOS)
diff --git a/base/mac/mac_util.h b/base/mac/mac_util.h
index f8ffa97545..7772e883fa 100644
--- a/base/mac/mac_util.h
+++ b/base/mac/mac_util.h
@@ -7,6 +7,7 @@
#include <AvailabilityMacros.h>
#include <Carbon/Carbon.h>
+#include <stdint.h>
#include <string>
#include "base/base_export.h"
@@ -145,18 +146,24 @@ BASE_EXPORT bool IsOSMavericksOrLater();
// Yosemite is Mac OS X 10.10, Darwin 14.
BASE_EXPORT bool IsOSYosemite();
+BASE_EXPORT bool IsOSYosemiteOrEarlier();
BASE_EXPORT bool IsOSYosemiteOrLater();
+// El Capitan is Mac OS X 10.11, Darwin 15.
+BASE_EXPORT bool IsOSElCapitan();
+BASE_EXPORT bool IsOSElCapitanOrLater();
+
// 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 IsOSLaterThanYosemite_DontCallThis();
+BASE_EXPORT bool IsOSLaterThanElCapitan_DontCallThis();
// Inline functions that are redundant due to version ranges being mutually-
// exclusive.
inline bool IsOSLionOrEarlier() { return !IsOSMountainLionOrLater(); }
inline bool IsOSMountainLionOrEarlier() { return !IsOSMavericksOrLater(); }
inline bool IsOSMavericksOrEarlier() { return !IsOSYosemiteOrLater(); }
+inline bool IsOSYosemiteOrEarlier() { return !IsOSElCapitanOrLater(); }
// 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
@@ -210,7 +217,19 @@ inline bool IsOSYosemiteOrLater() { return true; }
MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_10
#define BASE_MAC_MAC_UTIL_H_INLINED_GT_10_10
inline bool IsOSYosemite() { return false; }
-inline bool IsOSLaterThanYosemite_DontCallThis() { return true; }
+#endif
+
+#if defined(MAC_OS_X_VERSION_10_11) && \
+ MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11
+#define BASE_MAC_MAC_UTIL_H_INLINED_GE_10_11
+inline bool IsOSElCapitanOrLater() { return true; }
+#endif
+
+#if defined(MAC_OS_X_VERSION_10_11) && \
+ MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_11
+#define BASE_MAC_MAC_UTIL_H_INLINED_GT_10_11
+inline bool IsOSElCapitan() { return false; }
+inline bool IsOSLaterThanElCapitan_DontCallThis() { return true; }
#endif
// Retrieve the system's model identifier string from the IOKit registry:
@@ -222,8 +241,8 @@ BASE_EXPORT std::string GetModelIdentifier();
// 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);
+ int32_t* major,
+ int32_t* minor);
} // namespace mac
} // namespace base
diff --git a/base/mac/mach_logging.cc b/base/mac/mach_logging.cc
index c5ff85e662..7b939b3dd9 100644
--- a/base/mac/mach_logging.cc
+++ b/base/mac/mach_logging.cc
@@ -8,6 +8,7 @@
#include <string>
#include "base/strings/stringprintf.h"
+#include "build/build_config.h"
#if !defined(OS_IOS)
#include <servers/bootstrap.h>
diff --git a/base/mac/mach_logging.h b/base/mac/mach_logging.h
index b12e274ea8..59ab762c3c 100644
--- a/base/mac/mach_logging.h
+++ b/base/mac/mach_logging.h
@@ -8,8 +8,8 @@
#include <mach/mach.h>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "build/build_config.h"
// Use the MACH_LOG family of macros along with a mach_error_t (kern_return_t)
diff --git a/base/mac/scoped_aedesc.h b/base/mac/scoped_aedesc.h
index a1323c0cb7..73270920dd 100644
--- a/base/mac/scoped_aedesc.h
+++ b/base/mac/scoped_aedesc.h
@@ -7,7 +7,7 @@
#import <CoreServices/CoreServices.h>
-#include "base/basictypes.h"
+#include "base/macros.h"
namespace base {
namespace mac {
diff --git a/base/mac/scoped_authorizationref.h b/base/mac/scoped_authorizationref.h
index 1811488380..39afa8c9a5 100644
--- a/base/mac/scoped_authorizationref.h
+++ b/base/mac/scoped_authorizationref.h
@@ -7,8 +7,8 @@
#include <Security/Authorization.h>
-#include "base/basictypes.h"
#include "base/compiler_specific.h"
+#include "base/macros.h"
// ScopedAuthorizationRef maintains ownership of an AuthorizationRef. It is
// patterned after the scoped_ptr interface.
diff --git a/base/mac/scoped_block.h b/base/mac/scoped_block.h
index 509a1c2c19..bc2688f13a 100644
--- a/base/mac/scoped_block.h
+++ b/base/mac/scoped_block.h
@@ -7,84 +7,27 @@
#include <Block.h>
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/memory/scoped_policy.h"
+#include "base/mac/scoped_typeref.h"
namespace base {
namespace mac {
-// ScopedBlock<> is patterned after ScopedCFTypeRef<>, but uses Block_copy() and
-// Block_release() instead of CFRetain() and CFRelease().
-
-template<typename B>
-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<B>& that)
- : block_(that.block_) {
- if (block_)
- block_ = Block_copy(block_);
- }
-
- ~ScopedBlock() {
- if (block_)
- Block_release(block_);
- }
-
- ScopedBlock& operator=(const ScopedBlock<B>& 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;
- }
+namespace internal {
- 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_;
- }
+template <typename B>
+struct ScopedBlockTraits {
+ static B InvalidValue() { return nullptr; }
+ static B Retain(B block) { return Block_copy(block); }
+ static void Release(B block) { Block_release(block); }
+};
- void swap(ScopedBlock& that) {
- B temp = that.block_;
- that.block_ = block_;
- block_ = temp;
- }
+} // namespace internal
- B release() WARN_UNUSED_RESULT {
- B temp = block_;
- block_ = NULL;
- return temp;
- }
+// ScopedBlock<> is patterned after ScopedCFTypeRef<>, but uses Block_copy() and
+// Block_release() instead of CFRetain() and CFRelease().
- private:
- B block_;
-};
+template <typename B>
+using ScopedBlock = ScopedTypeRef<B, internal::ScopedBlockTraits<B>>;
} // namespace mac
} // namespace base
diff --git a/base/mac/scoped_cffiledescriptorref.h b/base/mac/scoped_cffiledescriptorref.h
index 07196aa921..923a159c76 100644
--- a/base/mac/scoped_cffiledescriptorref.h
+++ b/base/mac/scoped_cffiledescriptorref.h
@@ -7,67 +7,31 @@
#include <CoreFoundation/CoreFoundation.h>
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
+#include "base/scoped_generic.h"
namespace base {
namespace mac {
+namespace internal {
+
+struct ScopedCFFileDescriptorRefTraits {
+ static CFFileDescriptorRef InvalidValue() { return nullptr; }
+ static void Free(CFFileDescriptorRef ref) {
+ CFFileDescriptorInvalidate(ref);
+ CFRelease(ref);
+ }
+};
+
+} // namespace internal
+
// 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);
-};
+using ScopedCFFileDescriptorRef =
+ ScopedGeneric<CFFileDescriptorRef,
+ internal::ScopedCFFileDescriptorRefTraits>;
} // namespace mac
} // namespace base
diff --git a/base/mac/scoped_cftyperef.h b/base/mac/scoped_cftyperef.h
index 8567f85ffc..1be0fbe56d 100644
--- a/base/mac/scoped_cftyperef.h
+++ b/base/mac/scoped_cftyperef.h
@@ -27,11 +27,14 @@ namespace base {
namespace internal {
+template<typename CFT>
struct ScopedCFTypeRefTraits {
- static void Retain(CFTypeRef object) {
+ static CFT InvalidValue() { return nullptr; }
+ static CFT Retain(CFT object) {
CFRetain(object);
+ return object;
}
- static void Release(CFTypeRef object) {
+ static void Release(CFT object) {
CFRelease(object);
}
};
@@ -39,20 +42,8 @@ struct ScopedCFTypeRefTraits {
} // namespace internal
template<typename CFT>
-class ScopedCFTypeRef
- : public ScopedTypeRef<CFT, internal::ScopedCFTypeRefTraits> {
- public:
- typedef CFT element_type;
-
- explicit ScopedCFTypeRef(
- CFT object = NULL,
- base::scoped_policy::OwnershipPolicy policy = base::scoped_policy::ASSUME)
- : ScopedTypeRef<CFT,
- internal::ScopedCFTypeRefTraits>(object, policy) {}
-
- ScopedCFTypeRef(const ScopedCFTypeRef<CFT>& that)
- : ScopedTypeRef<CFT, internal::ScopedCFTypeRefTraits>(that) {}
-};
+using ScopedCFTypeRef =
+ ScopedTypeRef<CFT, internal::ScopedCFTypeRefTraits<CFT>>;
} // namespace base
diff --git a/base/mac/scoped_ioobject.h b/base/mac/scoped_ioobject.h
index 854039b553..c948cb5542 100644
--- a/base/mac/scoped_ioobject.h
+++ b/base/mac/scoped_ioobject.h
@@ -7,66 +7,28 @@
#include <IOKit/IOKitLib.h>
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
+#include "base/mac/scoped_typeref.h"
namespace base {
namespace mac {
-// Just like ScopedCFTypeRef but for io_object_t and subclasses.
-template<typename IOT>
-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_;
- }
+namespace internal {
- 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;
+template <typename IOT>
+struct ScopedIOObjectTraits {
+ static IOT InvalidValue() { return IO_OBJECT_NULL; }
+ static IOT Retain(IOT iot) {
+ IOObjectRetain(iot);
+ return iot;
}
+ static void Release(IOT iot) { IOObjectRelease(iot); }
+};
- private:
- IOT object_;
+} // namespce internal
- DISALLOW_COPY_AND_ASSIGN(ScopedIOObject);
-};
+// Just like ScopedCFTypeRef but for io_object_t and subclasses.
+template <typename IOT>
+using ScopedIOObject = ScopedTypeRef<IOT, internal::ScopedIOObjectTraits<IOT>>;
} // namespace mac
} // namespace base
diff --git a/base/mac/scoped_ioplugininterface.h b/base/mac/scoped_ioplugininterface.h
index 503980c3ef..872da8eaa5 100644
--- a/base/mac/scoped_ioplugininterface.h
+++ b/base/mac/scoped_ioplugininterface.h
@@ -7,68 +7,30 @@
#include <IOKit/IOKitLib.h>
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
+#include "base/mac/scoped_typeref.h"
namespace base {
namespace mac {
-// Just like ScopedCFTypeRef but for IOCFPlugInInterface and friends
-// (IOUSBInterfaceStruct and IOUSBDeviceStruct320 in particular).
-template<typename T>
-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_;
- }
+namespace internal {
- 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;
+template <typename T>
+struct ScopedIOPluginInterfaceTraits {
+ static T InvalidValue() { return nullptr; }
+ static T Retain(T t) {
+ (*t)->AddRef(t);
+ return t;
}
+ static void Release(T t) { (*t)->Release(t); }
+};
- private:
- InterfaceT object_;
+} // namespace internal
- DISALLOW_COPY_AND_ASSIGN(ScopedIOPluginInterface);
-};
+// Just like ScopedCFTypeRef but for IOCFPlugInInterface and friends
+// (IOUSBInterfaceStruct and IOUSBDeviceStruct320 in particular).
+template <typename T>
+using ScopedIOPluginInterface =
+ ScopedTypeRef<T**, internal::ScopedIOPluginInterfaceTraits<T**>>;
} // namespace mac
} // namespace base
diff --git a/base/mac/scoped_launch_data.h b/base/mac/scoped_launch_data.h
index e4343b8939..da62006bfb 100644
--- a/base/mac/scoped_launch_data.h
+++ b/base/mac/scoped_launch_data.h
@@ -7,67 +7,23 @@
#include <launch.h>
-#include <algorithm>
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
+#include "base/scoped_generic.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;
- }
+namespace internal {
- 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;
- }
+struct ScopedLaunchDataTraits {
+ static launch_data_t InvalidValue() { return nullptr; }
+ static void Free(launch_data_t ldt) { launch_data_free(ldt); }
+};
- private:
- launch_data_t object_;
+} // namespace internal
- DISALLOW_COPY_AND_ASSIGN(ScopedLaunchData);
-};
+// Just like scoped_ptr<> but for launch_data_t.
+using ScopedLaunchData =
+ ScopedGeneric<launch_data_t, internal::ScopedLaunchDataTraits>;
} // namespace mac
} // namespace base
diff --git a/base/mac/scoped_mach_port.h b/base/mac/scoped_mach_port.h
index beb62b0321..67fed6bcfd 100644
--- a/base/mac/scoped_mach_port.h
+++ b/base/mac/scoped_mach_port.h
@@ -45,40 +45,21 @@ struct PortSetTraits {
// reference counted, and this takes ownership of the right on construction
// and then removes a reference to the right on destruction. If the reference
// is the last one on the right, the right is deallocated.
-class BASE_EXPORT ScopedMachSendRight :
- public base::ScopedGeneric<mach_port_t, internal::SendRightTraits> {
- public:
- explicit ScopedMachSendRight(mach_port_t port = traits_type::InvalidValue())
- : ScopedGeneric(port) {}
-
- operator mach_port_t() const { return get(); }
-};
+using ScopedMachSendRight =
+ ScopedGeneric<mach_port_t, internal::SendRightTraits>;
// A scoper for handling a Mach port's receive right. There is only one
// receive right per port. This takes ownership of the receive right on
// construction and then destroys the right on destruction, turning all
// outstanding send rights into dead names.
-class BASE_EXPORT ScopedMachReceiveRight :
- public base::ScopedGeneric<mach_port_t, internal::ReceiveRightTraits> {
- public:
- explicit ScopedMachReceiveRight(
- mach_port_t port = traits_type::InvalidValue()) : ScopedGeneric(port) {}
-
- operator mach_port_t() const { return get(); }
-};
+using ScopedMachReceiveRight =
+ ScopedGeneric<mach_port_t, internal::ReceiveRightTraits>;
// A scoper for handling a Mach port set. A port set can have only one
// reference. This takes ownership of that single reference on construction and
// destroys the port set on destruction. Destroying a port set does not destroy
// the receive rights that are members of the port set.
-class BASE_EXPORT ScopedMachPortSet :
- public ScopedGeneric<mach_port_t, internal::PortSetTraits> {
- public:
- explicit ScopedMachPortSet(mach_port_t port = traits_type::InvalidValue())
- : ScopedGeneric(port) {}
-
- operator mach_port_t() const { return get(); }
-};
+using ScopedMachPortSet = ScopedGeneric<mach_port_t, internal::PortSetTraits>;
} // namespace mac
} // namespace base
diff --git a/base/mac/scoped_nsautorelease_pool.h b/base/mac/scoped_nsautorelease_pool.h
index 60af71ae05..4d15e6da4c 100644
--- a/base/mac/scoped_nsautorelease_pool.h
+++ b/base/mac/scoped_nsautorelease_pool.h
@@ -6,7 +6,7 @@
#define BASE_MAC_SCOPED_NSAUTORELEASE_POOL_H_
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
#if defined(__OBJC__)
@class NSAutoreleasePool;
diff --git a/base/mac/scoped_nsobject.h b/base/mac/scoped_nsobject.h
index 836bdcc350..04c5877db7 100644
--- a/base/mac/scoped_nsobject.h
+++ b/base/mac/scoped_nsobject.h
@@ -5,13 +5,15 @@
#ifndef BASE_MAC_SCOPED_NSOBJECT_H_
#define BASE_MAC_SCOPED_NSOBJECT_H_
+#include <type_traits>
+
// Include NSObject.h directly because Foundation.h pulls in many dependencies.
// (Approx 100k lines of code versus 1.5k for NSObject.h). scoped_nsobject gets
// singled out because it is most typically included from other header files.
#import <Foundation/NSObject.h>
-#include "base/basictypes.h"
#include "base/compiler_specific.h"
+#include "base/mac/scoped_typeref.h"
@class NSAutoreleasePool;
@@ -37,71 +39,26 @@ namespace base {
// We check for bad uses of scoped_nsobject and NSAutoreleasePool at compile
// time with a template specialization (see below).
-template<typename NST>
-class scoped_nsprotocol {
+namespace internal {
+
+template <typename NST>
+struct ScopedNSProtocolTraits {
+ static NST InvalidValue() { return nil; }
+ static NST Retain(NST nst) { return [nst retain]; }
+ static void Release(NST nst) { [nst release]; }
+};
+
+} // namespace internal
+
+template <typename NST>
+class scoped_nsprotocol
+ : public ScopedTypeRef<NST, internal::ScopedNSProtocolTraits<NST>> {
public:
- explicit scoped_nsprotocol(NST object = nil) : object_(object) {}
-
- scoped_nsprotocol(const scoped_nsprotocol<NST>& that)
- : object_([that.object_ retain]) {
- }
-
- template <typename NSU>
- scoped_nsprotocol(const scoped_nsprotocol<NSU>& that)
- : object_([that.get() retain]) {
- }
-
- ~scoped_nsprotocol() {
- [object_ release];
- }
-
- scoped_nsprotocol& operator=(const scoped_nsprotocol<NST>& 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;
- }
+ using ScopedTypeRef<NST,
+ internal::ScopedNSProtocolTraits<NST>>::ScopedTypeRef;
// Shift reference to the autorelease pool to be released later.
- NST autorelease() {
- return [release() autorelease];
- }
-
- private:
- NST object_;
+ NST autorelease() { return [this->release() autorelease]; }
};
// Free functions
@@ -120,56 +77,20 @@ bool operator!=(C p1, const scoped_nsprotocol<C>& p2) {
return p1 != p2.get();
}
-template<typename NST>
+template <typename NST>
class scoped_nsobject : public scoped_nsprotocol<NST*> {
public:
- explicit scoped_nsobject(NST* object = nil)
- : scoped_nsprotocol<NST*>(object) {}
-
- scoped_nsobject(const scoped_nsobject<NST>& that)
- : scoped_nsprotocol<NST*>(that) {
- }
-
- template<typename NSU>
- scoped_nsobject(const scoped_nsobject<NSU>& that)
- : scoped_nsprotocol<NST*>(that) {
- }
-
- scoped_nsobject& operator=(const scoped_nsobject<NST>& that) {
- scoped_nsprotocol<NST*>::operator=(that);
- return *this;
- }
+ using scoped_nsprotocol<NST*>::scoped_nsprotocol;
+
+ static_assert(std::is_same<NST, NSAutoreleasePool>::value == false,
+ "Use ScopedNSAutoreleasePool instead");
};
// Specialization to make scoped_nsobject<id> work.
template<>
class scoped_nsobject<id> : public scoped_nsprotocol<id> {
public:
- explicit scoped_nsobject(id object = nil) : scoped_nsprotocol<id>(object) {}
-
- scoped_nsobject(const scoped_nsobject<id>& that)
- : scoped_nsprotocol<id>(that) {
- }
-
- template<typename NSU>
- scoped_nsobject(const scoped_nsobject<NSU>& that)
- : scoped_nsprotocol<id>(that) {
- }
-
- scoped_nsobject& operator=(const scoped_nsobject<id>& that) {
- scoped_nsprotocol<id>::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<NSAutoreleasePool> {
- private:
- explicit scoped_nsobject(NSAutoreleasePool* object = nil);
- DISALLOW_COPY_AND_ASSIGN(scoped_nsobject);
+ using scoped_nsprotocol<id>::scoped_nsprotocol;
};
} // namespace base
diff --git a/base/mac/scoped_typeref.h b/base/mac/scoped_typeref.h
index 61ee311981..42114141e1 100644
--- a/base/mac/scoped_typeref.h
+++ b/base/mac/scoped_typeref.h
@@ -5,7 +5,6 @@
#ifndef BASE_MAC_SCOPED_TYPEREF_H_
#define BASE_MAC_SCOPED_TYPEREF_H_
-#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/memory/scoped_policy.h"
@@ -22,8 +21,12 @@ namespace base {
//
// template<>
// struct ScopedTypeRefTraits<CGLContextObj> {
-// void Retain(CGLContextObj object) { CGLContextRetain(object); }
-// void Release(CGLContextObj object) { CGLContextRelease(object); }
+// static CGLContextObj InvalidValue() { return nullptr; }
+// static CGLContextObj Retain(CGLContextObj object) {
+// CGLContextRetain(object);
+// return object;
+// }
+// static void Release(CGLContextObj object) { CGLContextRelease(object); }
// };
//
// For the many types that have pass-by-pointer create functions, the function
@@ -51,17 +54,17 @@ class ScopedTypeRef {
typedef T element_type;
ScopedTypeRef(
- T object = NULL,
+ T object = Traits::InvalidValue(),
base::scoped_policy::OwnershipPolicy policy = base::scoped_policy::ASSUME)
: object_(object) {
if (object_ && policy == base::scoped_policy::RETAIN)
- Traits::Retain(object_);
+ object_ = Traits::Retain(object_);
}
ScopedTypeRef(const ScopedTypeRef<T, Traits>& that)
: object_(that.object_) {
if (object_)
- Traits::Retain(object_);
+ object_ = Traits::Retain(object_);
}
~ScopedTypeRef() {
@@ -82,11 +85,11 @@ class ScopedTypeRef {
return &object_;
}
- void reset(T object = NULL,
+ void reset(T object = Traits::InvalidValue(),
base::scoped_policy::OwnershipPolicy policy =
base::scoped_policy::ASSUME) {
if (object && policy == base::scoped_policy::RETAIN)
- Traits::Retain(object);
+ object = Traits::Retain(object);
if (object_)
Traits::Release(object_);
object_ = object;
@@ -119,7 +122,7 @@ class ScopedTypeRef {
// Release(), use ScopedTypeRef<>::reset().
T release() WARN_UNUSED_RESULT {
T temp = object_;
- object_ = NULL;
+ object_ = Traits::InvalidValue();
return temp;
}
diff --git a/base/macros.h b/base/macros.h
index 71b42d15a4..c4dfdbcae5 100644
--- a/base/macros.h
+++ b/base/macros.h
@@ -11,7 +11,6 @@
#define BASE_MACROS_H_
#include <stddef.h> // For size_t.
-#include <string.h> // For memcpy.
// Put this in the declarations for a class to be uncopyable.
#define DISALLOW_COPY(TypeName) \
@@ -30,13 +29,6 @@
void operator=(const TypeName&)
#endif
-// 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.
//
@@ -44,13 +36,14 @@
// that wants to prevent anyone from instantiating it. This is
// especially useful for classes containing only static methods.
#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
- TypeName(); \
+ TypeName() = delete; \
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.
+// 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. For the technical details, refer to
+// http://blogs.msdn.com/b/the1/archive/2004/05/07/128242.aspx.
// This template function declaration is used in defining arraysize.
// Note that the function doesn't need an implementation, as we only
@@ -58,110 +51,6 @@
template <typename T, size_t N> char (&ArraySizeHelper(T (&array)[N]))[N];
#define arraysize(array) (sizeof(ArraySizeHelper(array)))
-
-// 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<ToType>(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<typename To, typename From>
-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(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.
-
-#undef COMPILE_ASSERT
-#define COMPILE_ASSERT(expr, msg) static_assert(expr, #msg)
-
-// bit_cast<Dest,Source> is a template function that implements the
-// equivalent of "*reinterpret_cast<Dest*>(&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<int32>(f);
-// // i = 0x40490fdb
-//
-// The classical address-casting method is:
-//
-// // WRONG
-// float f = 3.14159265358979; // WRONG
-// int i = * reinterpret_cast<int*>(&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<int*>(&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 <class Dest, class Source>
-inline Dest bit_cast(const Source& source) {
- COMPILE_ASSERT(sizeof(Dest) == sizeof(Source), VerifySizesAreEqual);
-
- 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:
diff --git a/base/md5.h b/base/md5.h
index 0b4cbcef3a..ef64178994 100644
--- a/base/md5.h
+++ b/base/md5.h
@@ -5,6 +5,7 @@
#ifndef BASE_MD5_H_
#define BASE_MD5_H_
+#include <stddef.h>
#include <stdint.h>
#include "base/base_export.h"
diff --git a/base/md5_unittest.cc b/base/md5_unittest.cc
index 08c99f1904..3926b66ae3 100644
--- a/base/md5_unittest.cc
+++ b/base/md5_unittest.cc
@@ -5,7 +5,6 @@
#include <string.h>
#include <string>
-#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
#include "base/md5.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/base/memory/BUILD.gn b/base/memory/BUILD.gn
deleted file mode 100644
index c3442794d8..0000000000
--- a/base/memory/BUILD.gn
+++ /dev/null
@@ -1,70 +0,0 @@
-# Copyright (c) 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-source_set("memory") {
- sources = [
- "aligned_memory.cc",
- "aligned_memory.h",
- "discardable_memory.cc",
- "discardable_memory.h",
- "discardable_memory_allocator.cc",
- "discardable_memory_allocator.h",
- "discardable_shared_memory.cc",
- "discardable_shared_memory.h",
- "linked_ptr.h",
- "manual_constructor.h",
- "memory_pressure_listener.cc",
- "memory_pressure_listener.h",
- "memory_pressure_monitor.cc",
- "memory_pressure_monitor.h",
- "memory_pressure_monitor_chromeos.cc",
- "memory_pressure_monitor_chromeos.h",
- "memory_pressure_monitor_mac.cc",
- "memory_pressure_monitor_mac.h",
- "memory_pressure_monitor_win.cc",
- "memory_pressure_monitor_win.h",
- "raw_scoped_refptr_mismatch_checker.h",
- "ref_counted.cc",
- "ref_counted.h",
- "ref_counted_delete_on_message_loop.h",
- "ref_counted_memory.cc",
- "ref_counted_memory.h",
- "scoped_policy.h",
- "scoped_ptr.h",
- "scoped_vector.h",
- "shared_memory.h",
- "shared_memory_android.cc",
- "shared_memory_nacl.cc",
- "shared_memory_posix.cc",
- "shared_memory_win.cc",
- "singleton.cc",
- "singleton.h",
- "weak_ptr.cc",
- "weak_ptr.h",
- ]
-
- if (is_nacl) {
- sources -= [
- "discardable_memory.cc",
- "discardable_memory.h",
- "discardable_memory_allocator.cc",
- "discardable_memory_allocator.h",
- "discardable_shared_memory.cc",
- "discardable_shared_memory.h",
- "shared_memory_posix.cc",
- ]
- } else {
- sources -= [ "shared_memory_nacl.cc" ]
- }
-
- if (is_android) {
- deps = [
- "//third_party/ashmem",
- ]
- }
-
- configs += [ "//base:base_implementation" ]
-
- visibility = [ "//base/*" ]
-}
diff --git a/base/memory/aligned_memory.cc b/base/memory/aligned_memory.cc
index 5ec88b16b8..526a49587a 100644
--- a/base/memory/aligned_memory.cc
+++ b/base/memory/aligned_memory.cc
@@ -5,6 +5,7 @@
#include "base/memory/aligned_memory.h"
#include "base/logging.h"
+#include "build/build_config.h"
#if defined(OS_ANDROID)
#include <malloc.h>
diff --git a/base/memory/aligned_memory.h b/base/memory/aligned_memory.h
index 1a4cba9ad8..bb7bd872cf 100644
--- a/base/memory/aligned_memory.h
+++ b/base/memory/aligned_memory.h
@@ -34,8 +34,10 @@
#ifndef BASE_MEMORY_ALIGNED_MEMORY_H_
#define BASE_MEMORY_ALIGNED_MEMORY_H_
+#include <stddef.h>
+#include <stdint.h>
+
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/compiler_specific.h"
#if defined(COMPILER_MSVC)
@@ -51,25 +53,26 @@ namespace base {
template <size_t Size, size_t ByteAlignment>
struct AlignedMemory {};
-#define BASE_DECL_ALIGNED_MEMORY(byte_alignment) \
- template <size_t Size> \
- class AlignedMemory<Size, byte_alignment> { \
- public: \
- ALIGNAS(byte_alignment) uint8 data_[Size]; \
- void* void_data() { return static_cast<void*>(data_); } \
- const void* void_data() const { \
- return static_cast<const void*>(data_); \
- } \
- template<typename Type> \
- Type* data_as() { return static_cast<Type*>(void_data()); } \
- template<typename Type> \
- const Type* data_as() const { \
- return static_cast<const Type*>(void_data()); \
- } \
- private: \
- void* operator new(size_t); \
- void operator delete(void*); \
- }
+#define BASE_DECL_ALIGNED_MEMORY(byte_alignment) \
+ template <size_t Size> \
+ class AlignedMemory<Size, byte_alignment> { \
+ public: \
+ ALIGNAS(byte_alignment) uint8_t data_[Size]; \
+ void* void_data() { return static_cast<void*>(data_); } \
+ const void* void_data() const { return static_cast<const void*>(data_); } \
+ template <typename Type> \
+ Type* data_as() { \
+ return static_cast<Type*>(void_data()); \
+ } \
+ template <typename Type> \
+ const Type* data_as() const { \
+ return static_cast<const Type*>(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).
diff --git a/base/memory/aligned_memory_unittest.cc b/base/memory/aligned_memory_unittest.cc
index 5d681f9a38..b89e341faa 100644
--- a/base/memory/aligned_memory_unittest.cc
+++ b/base/memory/aligned_memory_unittest.cc
@@ -4,6 +4,7 @@
#include "base/memory/aligned_memory.h"
#include "base/memory/scoped_ptr.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#define EXPECT_ALIGNED(ptr, align) \
diff --git a/base/memory/linked_ptr.h b/base/memory/linked_ptr.h
index 80044add81..649dc10db7 100644
--- a/base/memory/linked_ptr.h
+++ b/base/memory/linked_ptr.h
@@ -17,10 +17,6 @@
// 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!).
@@ -73,6 +69,8 @@ class linked_ptr_internal {
mutable linked_ptr_internal const* next_;
};
+// TODO(http://crbug.com/556939): DEPRECATED: Use scoped_ptr instead (now that
+// we have support for moveable types inside STL containers).
template <typename T>
class linked_ptr {
public:
diff --git a/base/memory/raw_scoped_refptr_mismatch_checker.h b/base/memory/raw_scoped_refptr_mismatch_checker.h
index 0190558805..09f982b129 100644
--- a/base/memory/raw_scoped_refptr_mismatch_checker.h
+++ b/base/memory/raw_scoped_refptr_mismatch_checker.h
@@ -51,75 +51,10 @@ struct ParamsUseScopedRefptrCorrectly<Tuple<>> {
enum { value = 1 };
};
-template <typename A>
-struct ParamsUseScopedRefptrCorrectly<Tuple<A>> {
- enum { value = !NeedsScopedRefptrButGetsRawPtr<A>::value };
-};
-
-template <typename A, typename B>
-struct ParamsUseScopedRefptrCorrectly<Tuple<A, B>> {
- enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
- NeedsScopedRefptrButGetsRawPtr<B>::value) };
-};
-
-template <typename A, typename B, typename C>
-struct ParamsUseScopedRefptrCorrectly<Tuple<A, B, C>> {
- enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
- NeedsScopedRefptrButGetsRawPtr<B>::value ||
- NeedsScopedRefptrButGetsRawPtr<C>::value) };
-};
-
-template <typename A, typename B, typename C, typename D>
-struct ParamsUseScopedRefptrCorrectly<Tuple<A, B, C, D>> {
- enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
- NeedsScopedRefptrButGetsRawPtr<B>::value ||
- NeedsScopedRefptrButGetsRawPtr<C>::value ||
- NeedsScopedRefptrButGetsRawPtr<D>::value) };
-};
-
-template <typename A, typename B, typename C, typename D, typename E>
-struct ParamsUseScopedRefptrCorrectly<Tuple<A, B, C, D, E>> {
- enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
- NeedsScopedRefptrButGetsRawPtr<B>::value ||
- NeedsScopedRefptrButGetsRawPtr<C>::value ||
- NeedsScopedRefptrButGetsRawPtr<D>::value ||
- NeedsScopedRefptrButGetsRawPtr<E>::value) };
-};
-
-template <typename A, typename B, typename C, typename D, typename E,
- typename F>
-struct ParamsUseScopedRefptrCorrectly<Tuple<A, B, C, D, E, F>> {
- enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
- NeedsScopedRefptrButGetsRawPtr<B>::value ||
- NeedsScopedRefptrButGetsRawPtr<C>::value ||
- NeedsScopedRefptrButGetsRawPtr<D>::value ||
- NeedsScopedRefptrButGetsRawPtr<E>::value ||
- NeedsScopedRefptrButGetsRawPtr<F>::value) };
-};
-
-template <typename A, typename B, typename C, typename D, typename E,
- typename F, typename G>
-struct ParamsUseScopedRefptrCorrectly<Tuple<A, B, C, D, E, F, G>> {
- enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
- NeedsScopedRefptrButGetsRawPtr<B>::value ||
- NeedsScopedRefptrButGetsRawPtr<C>::value ||
- NeedsScopedRefptrButGetsRawPtr<D>::value ||
- NeedsScopedRefptrButGetsRawPtr<E>::value ||
- NeedsScopedRefptrButGetsRawPtr<F>::value ||
- NeedsScopedRefptrButGetsRawPtr<G>::value) };
-};
-
-template <typename A, typename B, typename C, typename D, typename E,
- typename F, typename G, typename H>
-struct ParamsUseScopedRefptrCorrectly<Tuple<A, B, C, D, E, F, G, H>> {
- enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
- NeedsScopedRefptrButGetsRawPtr<B>::value ||
- NeedsScopedRefptrButGetsRawPtr<C>::value ||
- NeedsScopedRefptrButGetsRawPtr<D>::value ||
- NeedsScopedRefptrButGetsRawPtr<E>::value ||
- NeedsScopedRefptrButGetsRawPtr<F>::value ||
- NeedsScopedRefptrButGetsRawPtr<G>::value ||
- NeedsScopedRefptrButGetsRawPtr<H>::value) };
+template <typename Head, typename... Tail>
+struct ParamsUseScopedRefptrCorrectly<Tuple<Head, Tail...>> {
+ enum { value = !NeedsScopedRefptrButGetsRawPtr<Head>::value &&
+ ParamsUseScopedRefptrCorrectly<Tuple<Tail...>>::value };
};
} // namespace internal
diff --git a/base/memory/ref_counted.h b/base/memory/ref_counted.h
index 5f94b4c37a..a1c1269699 100644
--- a/base/memory/ref_counted.h
+++ b/base/memory/ref_counted.h
@@ -11,10 +11,10 @@
#include "base/atomic_ref_count.h"
#include "base/base_export.h"
#include "base/compiler_specific.h"
+#include "base/macros.h"
#ifndef NDEBUG
#include "base/logging.h"
#endif
-#include "base/move.h"
#include "base/threading/thread_collision_warner.h"
#include "build/build_config.h"
@@ -118,7 +118,7 @@ class BASE_EXPORT RefCountedThreadSafeBase {
// ~MyFoo();
// };
//
-// You should always make your destructor private, to avoid any code deleting
+// You should always make your destructor non-public, to avoid any code deleting
// the object accidently while there are references to it.
template <class T>
class RefCounted : public subtle::RefCountedBase {
@@ -265,7 +265,6 @@ class RefCountedData
//
template <class T>
class scoped_refptr {
- TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(scoped_refptr)
public:
typedef T element_type;
@@ -277,17 +276,24 @@ class scoped_refptr {
AddRef(ptr_);
}
+ // Copy constructor.
scoped_refptr(const scoped_refptr<T>& r) : ptr_(r.ptr_) {
if (ptr_)
AddRef(ptr_);
}
+ // Copy conversion constructor.
template <typename U>
scoped_refptr(const scoped_refptr<U>& r) : ptr_(r.get()) {
if (ptr_)
AddRef(ptr_);
}
+ // Move constructor. This is required in addition to the conversion
+ // constructor below in order for clang to warn about pessimizing moves.
+ scoped_refptr(scoped_refptr&& r) : ptr_(r.get()) { r.ptr_ = nullptr; }
+
+ // Move conversion constructor.
template <typename U>
scoped_refptr(scoped_refptr<U>&& r) : ptr_(r.get()) {
r.ptr_ = nullptr;
@@ -331,13 +337,13 @@ class scoped_refptr {
}
scoped_refptr<T>& operator=(scoped_refptr<T>&& r) {
- scoped_refptr<T>(r.Pass()).swap(*this);
+ scoped_refptr<T>(std::move(r)).swap(*this);
return *this;
}
template <typename U>
scoped_refptr<T>& operator=(scoped_refptr<U>&& r) {
- scoped_refptr<T>(r.Pass()).swap(*this);
+ scoped_refptr<T>(std::move(r)).swap(*this);
return *this;
}
diff --git a/base/memory/ref_counted_delete_on_message_loop.h b/base/memory/ref_counted_delete_on_message_loop.h
index 6a109e81e0..84f80d8d8f 100644
--- a/base/memory/ref_counted_delete_on_message_loop.h
+++ b/base/memory/ref_counted_delete_on_message_loop.h
@@ -7,9 +7,8 @@
#include "base/location.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
-// TODO(ricea): Remove the following include once all callers have been fixed.
-#include "base/message_loop/message_loop_proxy.h"
#include "base/single_thread_task_runner.h"
namespace base {
diff --git a/base/memory/ref_counted_memory.cc b/base/memory/ref_counted_memory.cc
index 477c941355..7bbd3171ca 100644
--- a/base/memory/ref_counted_memory.cc
+++ b/base/memory/ref_counted_memory.cc
@@ -4,8 +4,6 @@
#include "base/memory/ref_counted_memory.h"
-#include <stdlib.h>
-
#include "base/logging.h"
namespace base {
@@ -64,8 +62,9 @@ RefCountedString::RefCountedString() {}
RefCountedString::~RefCountedString() {}
// static
-RefCountedString* RefCountedString::TakeString(std::string* to_destroy) {
- RefCountedString* self = new RefCountedString;
+scoped_refptr<RefCountedString> RefCountedString::TakeString(
+ std::string* to_destroy) {
+ scoped_refptr<RefCountedString> self(new RefCountedString);
to_destroy->swap(self->data_);
return self;
}
@@ -79,22 +78,4 @@ size_t RefCountedString::size() const {
return data_.size();
}
-RefCountedMallocedMemory::RefCountedMallocedMemory(
- void* data, size_t length)
- : data_(reinterpret_cast<unsigned char*>(data)), length_(length) {
- DCHECK(data || length == 0);
-}
-
-const unsigned char* RefCountedMallocedMemory::front() const {
- return length_ ? data_ : NULL;
-}
-
-size_t RefCountedMallocedMemory::size() const {
- return length_;
-}
-
-RefCountedMallocedMemory::~RefCountedMallocedMemory() {
- free(data_);
-}
-
} // namespace base
diff --git a/base/memory/ref_counted_memory.h b/base/memory/ref_counted_memory.h
index 66dc65ff42..f37a86011a 100644
--- a/base/memory/ref_counted_memory.h
+++ b/base/memory/ref_counted_memory.h
@@ -5,11 +5,14 @@
#ifndef BASE_MEMORY_REF_COUNTED_MEMORY_H_
#define BASE_MEMORY_REF_COUNTED_MEMORY_H_
+#include <stddef.h>
+
#include <string>
#include <vector>
#include "base/base_export.h"
#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
namespace base {
@@ -104,7 +107,7 @@ class BASE_EXPORT RefCountedString : public RefCountedMemory {
// 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);
+ static scoped_refptr<RefCountedString> TakeString(std::string* to_destroy);
// Overridden from RefCountedMemory:
const unsigned char* front() const override;
@@ -121,26 +124,6 @@ class BASE_EXPORT RefCountedString : public RefCountedMemory {
DISALLOW_COPY_AND_ASSIGN(RefCountedString);
};
-// An implementation of RefCountedMemory that holds a chunk of memory
-// previously allocated with malloc or calloc, and that therefore must be freed
-// using free().
-class BASE_EXPORT RefCountedMallocedMemory : public base::RefCountedMemory {
- public:
- RefCountedMallocedMemory(void* data, size_t length);
-
- // Overridden from RefCountedMemory:
- const unsigned char* front() const override;
- size_t size() const override;
-
- private:
- ~RefCountedMallocedMemory() override;
-
- unsigned char* data_;
- size_t length_;
-
- DISALLOW_COPY_AND_ASSIGN(RefCountedMallocedMemory);
-};
-
} // 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
index 5bfc1c79a6..bd2ed01f54 100644
--- a/base/memory/ref_counted_memory_unittest.cc
+++ b/base/memory/ref_counted_memory_unittest.cc
@@ -4,6 +4,8 @@
#include "base/memory/ref_counted_memory.h"
+#include <stdint.h>
+
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
@@ -17,7 +19,7 @@ TEST(RefCountedMemoryUnitTest, RefCountedStaticMemory) {
}
TEST(RefCountedMemoryUnitTest, RefCountedBytes) {
- std::vector<uint8> data;
+ std::vector<uint8_t> data;
data.push_back(45);
data.push_back(99);
scoped_refptr<RefCountedMemory> mem = RefCountedBytes::TakeVector(&data);
@@ -50,16 +52,6 @@ TEST(RefCountedMemoryUnitTest, RefCountedString) {
EXPECT_EQ('e', mem->front()[1]);
}
-TEST(RefCountedMemoryUnitTest, RefCountedMallocedMemory) {
- void* data = malloc(6);
- memcpy(data, "hello", 6);
-
- scoped_refptr<RefCountedMemory> mem = new RefCountedMallocedMemory(data, 6);
-
- EXPECT_EQ(6U, mem->size());
- EXPECT_EQ(0, memcmp("hello", mem->front(), 6));
-}
-
TEST(RefCountedMemoryUnitTest, Equals) {
std::string s1("same");
scoped_refptr<RefCountedMemory> mem1 = RefCountedString::TakeString(&s1);
diff --git a/base/memory/ref_counted_unittest.cc b/base/memory/ref_counted_unittest.cc
index 6f8e599cbd..dbc6f33d0d 100644
--- a/base/memory/ref_counted_unittest.cc
+++ b/base/memory/ref_counted_unittest.cc
@@ -180,26 +180,6 @@ TEST(RefCountedUnitTest, ConvertibleEquality) {
EXPECT_EQ(p2, p1);
}
-TEST(RefCountedUnitTest, SelfMoveAssignment) {
- ScopedRefPtrCountBase::reset_count();
-
- {
- ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase();
- scoped_refptr<ScopedRefPtrCountBase> p(raw);
- EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
- EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
-
- p = p.Pass();
- EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
- EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
- EXPECT_EQ(raw, p.get());
-
- // p goes out of scope.
- }
- EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
- EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
-}
-
TEST(RefCountedUnitTest, MoveAssignment1) {
ScopedRefPtrCountBase::reset_count();
@@ -212,7 +192,7 @@ TEST(RefCountedUnitTest, MoveAssignment1) {
{
scoped_refptr<ScopedRefPtrCountBase> p2;
- p2 = p1.Pass();
+ p2 = std::move(p1);
EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
EXPECT_EQ(nullptr, p1.get());
@@ -243,7 +223,7 @@ TEST(RefCountedUnitTest, MoveAssignment2) {
EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
- p1 = p2.Pass();
+ p1 = std::move(p2);
EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
EXPECT_EQ(raw, p1.get());
@@ -274,7 +254,7 @@ TEST(RefCountedUnitTest, MoveAssignmentSameInstance1) {
EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
- p1 = p2.Pass();
+ p1 = std::move(p2);
EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
EXPECT_EQ(raw, p1.get());
@@ -305,7 +285,7 @@ TEST(RefCountedUnitTest, MoveAssignmentSameInstance2) {
EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
- p2 = p1.Pass();
+ p2 = std::move(p1);
EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
EXPECT_EQ(nullptr, p1.get());
@@ -337,7 +317,7 @@ TEST(RefCountedUnitTest, MoveAssignmentDifferentInstances) {
EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
- p1 = p2.Pass();
+ p1 = std::move(p2);
EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
EXPECT_EQ(raw2, p1.get());
@@ -374,7 +354,7 @@ TEST(RefCountedUnitTest, MoveAssignmentDerived) {
EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count());
- p1 = p2.Pass();
+ p1 = std::move(p2);
EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
@@ -407,7 +387,7 @@ TEST(RefCountedUnitTest, MoveConstructor) {
EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
{
- scoped_refptr<ScopedRefPtrCountBase> p2(p1.Pass());
+ scoped_refptr<ScopedRefPtrCountBase> p2(std::move(p1));
EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
EXPECT_EQ(nullptr, p1.get());
@@ -437,7 +417,7 @@ TEST(RefCountedUnitTest, MoveConstructorDerived) {
EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count());
{
- scoped_refptr<ScopedRefPtrCountBase> p2(p1.Pass());
+ scoped_refptr<ScopedRefPtrCountBase> p2(std::move(p1));
EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
diff --git a/base/memory/scoped_ptr.h b/base/memory/scoped_ptr.h
index 69a98262c8..89b90ac6af 100644
--- a/base/memory/scoped_ptr.h
+++ b/base/memory/scoped_ptr.h
@@ -37,42 +37,43 @@
// 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:
+// as the argument type, it must be called with an rvalue of a scoper, which
+// can be created by using std::move(), or the result of another function that
+// generates a temporary; passing by copy will NOT work. Here is an example
+// using scoped_ptr:
//
// void TakesOwnership(scoped_ptr<Foo> arg) {
-// // Do something with arg
+// // Do something with arg.
// }
// scoped_ptr<Foo> CreateFoo() {
-// // No need for calling Pass() because we are constructing a temporary
-// // for the return value.
+// // No need for calling std::move() for returning a move-only value, or
+// // when you already have an rvalue as we do here.
// return scoped_ptr<Foo>(new Foo("new"));
// }
// scoped_ptr<Foo> PassThru(scoped_ptr<Foo> arg) {
-// return arg.Pass();
+// return arg;
// }
//
// {
// scoped_ptr<Foo> ptr(new Foo("yay")); // ptr manages Foo("yay").
-// TakesOwnership(ptr.Pass()); // ptr no longer owns Foo("yay").
+// TakesOwnership(std::move(ptr)); // ptr no longer owns Foo("yay").
// scoped_ptr<Foo> ptr2 = CreateFoo(); // ptr2 owns the return Foo.
// scoped_ptr<Foo> ptr3 = // ptr3 now owns what was in ptr2.
-// PassThru(ptr2.Pass()); // ptr2 is correspondingly nullptr.
+// PassThru(std::move(ptr2)); // ptr2 is correspondingly nullptr.
// }
//
-// Notice that if you do not call Pass() when returning from PassThru(), or
+// Notice that if you do not call std::move() 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().
+// the std::move() 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 std::move().
//
-// Pass() properly handles upcast in initialization, i.e. you can use a
-// scoped_ptr<Child> to initialize a scoped_ptr<Parent>:
+// The conversion move-constructor properly handles upcast in initialization,
+// i.e. you can use a scoped_ptr<Child> to initialize a scoped_ptr<Parent>:
//
// scoped_ptr<Foo> foo(new Foo());
-// scoped_ptr<FooParent> parent(foo.Pass());
+// scoped_ptr<FooParent> parent(std::move(foo));
#ifndef BASE_MEMORY_SCOPED_PTR_H_
#define BASE_MEMORY_SCOPED_PTR_H_
@@ -84,11 +85,13 @@
#include <stddef.h>
#include <stdlib.h>
-#include <algorithm> // For std::swap().
#include <iosfwd>
+#include <memory>
+#include <type_traits>
+#include <utility>
-#include "base/basictypes.h"
#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "base/move.h"
#include "base/template_util.h"
@@ -99,61 +102,6 @@ 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<T>.
-template <class T>
-struct DefaultDeleter {
- DefaultDeleter() {}
- template <typename U> DefaultDeleter(const DefaultDeleter<U>& /* 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<U*, T*> 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<U*, T*>::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 <class T>
-struct DefaultDeleter<T[]> {
- 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 <typename U> void operator()(U* array) const;
-};
-
-template <class T, int n>
-struct DefaultDeleter<T[n]> {
- // Never allow someone to declare something like scoped_ptr<int[10]>.
- 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:
//
@@ -175,17 +123,6 @@ template <typename T> struct IsNotRefCounted {
};
};
-template <typename T>
-struct ShouldAbortOnSelfReset {
- template <typename U>
- static NoType Test(const typename U::AllowSelfReset*);
-
- template <typename U>
- static YesType Test(...);
-
- static const bool value = sizeof(Test<T>(0)) == sizeof(YesType);
-};
-
// Minimal implementation of the core logic of scoped_ptr, suitable for
// reuse in both scoped_ptr and its specializations.
template <class T, class D>
@@ -216,37 +153,28 @@ class scoped_ptr_impl {
}
~scoped_ptr_impl() {
- if (data_.ptr != nullptr) {
- // Not using get_deleter() saves one function call in non-optimized
- // builds.
- static_cast<D&>(data_)(data_.ptr);
- }
+ // Match libc++, which calls reset() in its destructor.
+ // Use nullptr as the new value for three reasons:
+ // 1. libc++ does it.
+ // 2. Avoids infinitely recursing into destructors if two classes are owned
+ // in a reference cycle (see ScopedPtrTest.ReferenceCycle).
+ // 3. If |this| is accessed in the future, in a use-after-free bug, attempts
+ // to dereference |this|'s pointer should cause either a failure or a
+ // segfault closer to the problem. If |this| wasn't reset to nullptr,
+ // the access would cause the deleted memory to be read or written
+ // leading to other more subtle issues.
+ reset(nullptr);
}
void reset(T* p) {
- // This is a self-reset, which is no longer allowed for default deleters:
- // https://crbug.com/162971
- assert(!ShouldAbortOnSelfReset<D>::value || p == nullptr || p != data_.ptr);
-
- // Note that running data_.ptr = p can lead to undefined behavior if
- // get_deleter()(get()) deletes this. In order to prevent 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 nullptr 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.
+ // Match C++11's definition of unique_ptr::reset(), which requires changing
+ // the pointer before invoking the deleter on the old pointer. This prevents
+ // |this| from being accessed after the deleter is run, which may destroy
+ // |this|.
T* old = data_.ptr;
- data_.ptr = nullptr;
+ data_.ptr = p;
if (old != nullptr)
static_cast<D&>(data_)(old);
- data_.ptr = p;
}
T* get() const { return data_.ptr; }
@@ -300,25 +228,27 @@ class scoped_ptr_impl {
// 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<T>) == sizeof(T*). Custom deleters will
-// increase the size proportional to whatever state they need to have. See
+// std::default_delete, sizeof(scoped_ptr<T>) == 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 T, class D = base::DefaultDeleter<T> >
+template <class T, class D = std::default_delete<T>>
class scoped_ptr {
- MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(scoped_ptr)
+ DISALLOW_COPY_AND_ASSIGN_WITH_MOVE_FOR_BIND(scoped_ptr)
- COMPILE_ASSERT(base::internal::IsNotRefCounted<T>::value,
- T_is_refcounted_type_and_needs_scoped_refptr);
+ static_assert(!std::is_array<T>::value,
+ "scoped_ptr doesn't support array with size");
+ static_assert(base::internal::IsNotRefCounted<T>::value,
+ "T is a refcounted type and needs a scoped_refptr");
public:
// The element and deleter types.
- typedef T element_type;
- typedef D deleter_type;
+ using element_type = T;
+ using deleter_type = D;
// Constructor. Defaults to initializing with nullptr.
scoped_ptr() : impl_(nullptr) {}
@@ -330,44 +260,87 @@ class scoped_ptr {
scoped_ptr(element_type* p, const D& d) : impl_(p, d) {}
// Constructor. Allows construction from a nullptr.
- scoped_ptr(decltype(nullptr)) : impl_(nullptr) {}
+ scoped_ptr(std::nullptr_t) : impl_(nullptr) {}
+
+ // Move constructor.
+ //
+ // IMPLEMENTATION NOTE: Clang requires a move constructor to be defined (and
+ // not just the conversion constructor) in order to warn on pessimizing moves.
+ // The requirements for the move constructor are specified in C++11
+ // 20.7.1.2.1.15-17, which has some subtleties around reference deleters. As
+ // we don't support reference (or move-only) deleters, the post conditions are
+ // trivially true: we always copy construct the deleter from other's deleter.
+ scoped_ptr(scoped_ptr&& other) : impl_(&other.impl_) {}
- // Constructor. Allows construction from a scoped_ptr rvalue for a
+ // Conversion 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 <typename U, typename V>
- scoped_ptr(scoped_ptr<U, V>&& other)
- : impl_(&other.impl_) {
- COMPILE_ASSERT(!base::is_array<U>::value, U_cannot_be_an_array);
+ // IMPLEMENTATION NOTE: C++ 20.7.1.2.1.19 requires this constructor to only
+ // participate in overload resolution if all the following are true:
+ // - U is implicitly convertible to T: this is important for 2 reasons:
+ // 1. So type traits don't incorrectly return true, e.g.
+ // std::is_convertible<scoped_ptr<Base>, scoped_ptr<Derived>>::value
+ // should be false.
+ // 2. To make sure code like this compiles:
+ // void F(scoped_ptr<int>);
+ // void F(scoped_ptr<Base>);
+ // // Ambiguous since both conversion constructors match.
+ // F(scoped_ptr<Derived>());
+ // - U is not an array type: to prevent conversions from scoped_ptr<T[]> to
+ // scoped_ptr<T>.
+ // - D is a reference type and E is the same type, or D is not a reference
+ // type and E is implicitly convertible to D: again, we don't support
+ // reference deleters, so we only worry about the latter requirement.
+ template <typename U,
+ typename E,
+ typename std::enable_if<!std::is_array<U>::value &&
+ std::is_convertible<U*, T*>::value &&
+ std::is_convertible<E, D>::value>::type* =
+ nullptr>
+ scoped_ptr(scoped_ptr<U, E>&& other)
+ : impl_(&other.impl_) {}
+
+ // operator=.
+ //
+ // IMPLEMENTATION NOTE: Unlike the move constructor, Clang does not appear to
+ // require a move assignment operator to trigger the pessimizing move warning:
+ // in this case, the warning triggers when moving a temporary. For consistency
+ // with the move constructor, we define it anyway. C++11 20.7.1.2.3.1-3
+ // defines several requirements around this: like the move constructor, the
+ // requirements are simplified by the fact that we don't support move-only or
+ // reference deleters.
+ scoped_ptr& operator=(scoped_ptr&& rhs) {
+ impl_.TakeState(&rhs.impl_);
+ return *this;
}
// 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 <typename U, typename V>
- scoped_ptr& operator=(scoped_ptr<U, V>&& rhs) {
- COMPILE_ASSERT(!base::is_array<U>::value, U_cannot_be_an_array);
+ // the normal move assignment operator. C++11 20.7.1.2.3.4-7 contains the
+ // requirement for this operator, but like the conversion constructor, the
+ // requirements are greatly simplified by not supporting move-only or
+ // reference deleters.
+ template <typename U,
+ typename E,
+ typename std::enable_if<!std::is_array<U>::value &&
+ std::is_convertible<U*, T*>::value &&
+ // Note that this really should be
+ // std::is_assignable, but <type_traits>
+ // appears to be missing this on some
+ // platforms. This is close enough (though
+ // it's not the same).
+ std::is_convertible<D, E>::value>::type* =
+ nullptr>
+ scoped_ptr& operator=(scoped_ptr<U, E>&& rhs) {
impl_.TakeState(&rhs.impl_);
return *this;
}
// operator=. Allows assignment from a nullptr. Deletes the currently owned
// object, if any.
- scoped_ptr& operator=(decltype(nullptr)) {
+ scoped_ptr& operator=(std::nullptr_t) {
reset();
return *this;
}
@@ -408,12 +381,6 @@ class scoped_ptr {
return impl_.get() ? &scoped_ptr::impl_ : nullptr;
}
- // 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_);
@@ -434,23 +401,16 @@ class scoped_ptr {
// 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 <class U> bool operator==(scoped_ptr<U> const& p2) const;
- template <class U> bool operator!=(scoped_ptr<U> const& p2) const;
};
template <class T, class D>
class scoped_ptr<T[], D> {
- MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(scoped_ptr)
+ DISALLOW_COPY_AND_ASSIGN_WITH_MOVE_FOR_BIND(scoped_ptr)
public:
// The element and deleter types.
- typedef T element_type;
- typedef D deleter_type;
+ using element_type = T;
+ using deleter_type = D;
// Constructor. Defaults to initializing with nullptr.
scoped_ptr() : impl_(nullptr) {}
@@ -465,13 +425,11 @@ class scoped_ptr<T[], D> {
// (C++98 [expr.delete]p3). If you're doing this, fix your code.
// - 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<const T*>().
- // However, because of the first bullet in this comment, users MUST
- // NOT use implicit_cast<Base*>() to upcast the static type of the array.
+ // to work around this may use const_cast<const T*>().
explicit scoped_ptr(element_type* array) : impl_(array) {}
// Constructor. Allows construction from a nullptr.
- scoped_ptr(decltype(nullptr)) : impl_(nullptr) {}
+ scoped_ptr(std::nullptr_t) : impl_(nullptr) {}
// Constructor. Allows construction from a scoped_ptr rvalue.
scoped_ptr(scoped_ptr&& other) : impl_(&other.impl_) {}
@@ -484,7 +442,7 @@ class scoped_ptr<T[], D> {
// operator=. Allows assignment from a nullptr. Deletes the currently owned
// array, if any.
- scoped_ptr& operator=(decltype(nullptr)) {
+ scoped_ptr& operator=(std::nullptr_t) {
reset();
return *this;
}
@@ -515,12 +473,6 @@ class scoped_ptr<T[], D> {
return impl_.get() ? &scoped_ptr::impl_ : nullptr;
}
- // 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_);
@@ -553,13 +505,6 @@ class scoped_ptr<T[], D> {
// reasons as the constructor above.
template <typename U> 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 <class U> bool operator==(scoped_ptr<U> const& p2) const;
- template <class U> bool operator!=(scoped_ptr<U> const& p2) const;
};
// Free functions
@@ -568,14 +513,84 @@ void swap(scoped_ptr<T, D>& p1, scoped_ptr<T, D>& p2) {
p1.swap(p2);
}
+template <class T1, class D1, class T2, class D2>
+bool operator==(const scoped_ptr<T1, D1>& p1, const scoped_ptr<T2, D2>& p2) {
+ return p1.get() == p2.get();
+}
+template <class T, class D>
+bool operator==(const scoped_ptr<T, D>& p, std::nullptr_t) {
+ return p.get() == nullptr;
+}
+template <class T, class D>
+bool operator==(std::nullptr_t, const scoped_ptr<T, D>& p) {
+ return p.get() == nullptr;
+}
+
+template <class T1, class D1, class T2, class D2>
+bool operator!=(const scoped_ptr<T1, D1>& p1, const scoped_ptr<T2, D2>& p2) {
+ return !(p1 == p2);
+}
+template <class T, class D>
+bool operator!=(const scoped_ptr<T, D>& p, std::nullptr_t) {
+ return !(p == nullptr);
+}
+template <class T, class D>
+bool operator!=(std::nullptr_t, const scoped_ptr<T, D>& p) {
+ return !(p == nullptr);
+}
+
+template <class T1, class D1, class T2, class D2>
+bool operator<(const scoped_ptr<T1, D1>& p1, const scoped_ptr<T2, D2>& p2) {
+ return p1.get() < p2.get();
+}
+template <class T, class D>
+bool operator<(const scoped_ptr<T, D>& p, std::nullptr_t) {
+ auto* ptr = p.get();
+ return ptr < static_cast<decltype(ptr)>(nullptr);
+}
+template <class T, class D>
+bool operator<(std::nullptr_t, const scoped_ptr<T, D>& p) {
+ auto* ptr = p.get();
+ return static_cast<decltype(ptr)>(nullptr) < ptr;
+}
+
+template <class T1, class D1, class T2, class D2>
+bool operator>(const scoped_ptr<T1, D1>& p1, const scoped_ptr<T2, D2>& p2) {
+ return p2 < p1;
+}
+template <class T, class D>
+bool operator>(const scoped_ptr<T, D>& p, std::nullptr_t) {
+ return nullptr < p;
+}
+template <class T, class D>
+bool operator>(std::nullptr_t, const scoped_ptr<T, D>& p) {
+ return p < nullptr;
+}
+
+template <class T1, class D1, class T2, class D2>
+bool operator<=(const scoped_ptr<T1, D1>& p1, const scoped_ptr<T2, D2>& p2) {
+ return !(p1 > p2);
+}
+template <class T, class D>
+bool operator<=(const scoped_ptr<T, D>& p, std::nullptr_t) {
+ return !(p > nullptr);
+}
template <class T, class D>
-bool operator==(T* p1, const scoped_ptr<T, D>& p2) {
- return p1 == p2.get();
+bool operator<=(std::nullptr_t, const scoped_ptr<T, D>& p) {
+ return !(nullptr > p);
}
+template <class T1, class D1, class T2, class D2>
+bool operator>=(const scoped_ptr<T1, D1>& p1, const scoped_ptr<T2, D2>& p2) {
+ return !(p1 < p2);
+}
+template <class T, class D>
+bool operator>=(const scoped_ptr<T, D>& p, std::nullptr_t) {
+ return !(p < nullptr);
+}
template <class T, class D>
-bool operator!=(T* p1, const scoped_ptr<T, D>& p2) {
- return p1 != p2.get();
+bool operator>=(std::nullptr_t, const scoped_ptr<T, D>& p) {
+ return !(nullptr < p);
}
// A function to convert T* into scoped_ptr<T>
diff --git a/base/memory/scoped_ptr_unittest.cc b/base/memory/scoped_ptr_unittest.cc
index 766f444400..4f0e78425f 100644
--- a/base/memory/scoped_ptr_unittest.cc
+++ b/base/memory/scoped_ptr_unittest.cc
@@ -4,11 +4,14 @@
#include "base/memory/scoped_ptr.h"
+#include <stddef.h>
+
#include <sstream>
-#include "base/basictypes.h"
#include "base/bind.h"
#include "base/callback.h"
+#include "base/macros.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
@@ -84,7 +87,7 @@ int OverloadedNewAndDelete::g_new_count = 0;
int OverloadedNewAndDelete::g_delete_count = 0;
scoped_ptr<ConDecLogger> PassThru(scoped_ptr<ConDecLogger> logger) {
- return logger.Pass();
+ return logger;
}
void GrabAndDrop(scoped_ptr<ConDecLogger> logger) {
@@ -102,8 +105,8 @@ TEST(ScopedPtrTest, ScopedPtr) {
int constructed = 0;
// Ensure size of scoped_ptr<> doesn't increase unexpectedly.
- COMPILE_ASSERT(sizeof(int*) >= sizeof(scoped_ptr<int>),
- scoped_ptr_larger_than_raw_ptr);
+ static_assert(sizeof(int*) >= sizeof(scoped_ptr<int>),
+ "scoped_ptr shouldn't be larger than the raw pointer");
{
scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed));
@@ -146,25 +149,25 @@ TEST(ScopedPtrTest, ScopedPtr) {
}
EXPECT_EQ(0, constructed);
- // Test swap(), == and !=
+ // Test swap().
{
scoped_ptr<ConDecLogger> scoper1;
scoped_ptr<ConDecLogger> scoper2;
- EXPECT_TRUE(scoper1 == scoper2.get());
- EXPECT_FALSE(scoper1 != scoper2.get());
+ EXPECT_TRUE(scoper1.get() == scoper2.get());
+ EXPECT_FALSE(scoper1.get() != 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());
+ EXPECT_FALSE(scoper1.get() == scoper2.get());
+ EXPECT_TRUE(scoper1.get() != 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_FALSE(scoper1.get() == scoper2.get());
+ EXPECT_TRUE(scoper1.get() != scoper2.get());
}
EXPECT_EQ(0, constructed);
}
@@ -178,7 +181,7 @@ TEST(ScopedPtrTest, ScopedPtrDepthSubtyping) {
EXPECT_EQ(1, constructed);
EXPECT_TRUE(scoper.get());
- scoped_ptr<ConDecLoggerParent> scoper_parent(scoper.Pass());
+ scoped_ptr<ConDecLoggerParent> scoper_parent(std::move(scoper));
EXPECT_EQ(1, constructed);
EXPECT_TRUE(scoper_parent.get());
EXPECT_FALSE(scoper.get());
@@ -196,7 +199,7 @@ TEST(ScopedPtrTest, ScopedPtrDepthSubtyping) {
EXPECT_TRUE(scoper.get());
scoped_ptr<ConDecLoggerParent> scoper_parent;
- scoper_parent = scoper.Pass();
+ scoper_parent = std::move(scoper);
EXPECT_EQ(1, constructed);
EXPECT_TRUE(scoper_parent.get());
EXPECT_FALSE(scoper.get());
@@ -209,7 +212,7 @@ TEST(ScopedPtrTest, ScopedPtrDepthSubtyping) {
EXPECT_EQ(1, constructed);
EXPECT_TRUE(scoper.get());
- scoped_ptr<const ConDecLogger> scoper_const(scoper.Pass());
+ scoped_ptr<const ConDecLogger> scoper_const(std::move(scoper));
EXPECT_EQ(1, constructed);
EXPECT_TRUE(scoper_const.get());
EXPECT_FALSE(scoper.get());
@@ -227,7 +230,7 @@ TEST(ScopedPtrTest, ScopedPtrDepthSubtyping) {
EXPECT_TRUE(scoper.get());
scoped_ptr<const ConDecLogger> scoper_const;
- scoper_const = scoper.Pass();
+ scoper_const = std::move(scoper);
EXPECT_EQ(1, constructed);
EXPECT_TRUE(scoper_const.get());
EXPECT_FALSE(scoper.get());
@@ -251,7 +254,7 @@ TEST(ScopedPtrTest, ScopedPtrDepthSubtyping) {
EXPECT_EQ(0, alternate_deletes);
// Test this compiles and correctly overwrites the deleter state.
- scoper = scoper_child.Pass();
+ scoper = std::move(scoper_child);
EXPECT_TRUE(scoper);
EXPECT_FALSE(scoper_child);
EXPECT_EQ(1, deletes);
@@ -267,7 +270,8 @@ TEST(ScopedPtrTest, ScopedPtrDepthSubtyping) {
EXPECT_TRUE(scoper_child);
EXPECT_EQ(1, deletes);
EXPECT_EQ(1, alternate_deletes);
- scoped_ptr<double, CountingDeleter> scoper_construct(scoper_child.Pass());
+ scoped_ptr<double, CountingDeleter> scoper_construct(
+ std::move(scoper_child));
EXPECT_TRUE(scoper_construct);
EXPECT_FALSE(scoper_child);
EXPECT_EQ(1, deletes);
@@ -327,12 +331,12 @@ TEST(ScopedPtrTest, ScopedPtrWithArray) {
}
EXPECT_EQ(0, constructed);
- // Test swap(), ==, !=, and type-safe Boolean.
+ // Test swap() and type-safe Boolean.
{
scoped_ptr<ConDecLogger[]> scoper1;
scoped_ptr<ConDecLogger[]> scoper2;
- EXPECT_TRUE(scoper1 == scoper2.get());
- EXPECT_FALSE(scoper1 != scoper2.get());
+ EXPECT_TRUE(scoper1.get() == scoper2.get());
+ EXPECT_FALSE(scoper1.get() != scoper2.get());
ConDecLogger* loggers = new ConDecLogger[kNumLoggers];
for (int i = 0; i < kNumLoggers; ++i) {
@@ -343,14 +347,14 @@ TEST(ScopedPtrTest, ScopedPtrWithArray) {
EXPECT_EQ(loggers, scoper1.get());
EXPECT_FALSE(scoper2);
EXPECT_FALSE(scoper2.get());
- EXPECT_FALSE(scoper1 == scoper2.get());
- EXPECT_TRUE(scoper1 != scoper2.get());
+ EXPECT_FALSE(scoper1.get() == scoper2.get());
+ EXPECT_TRUE(scoper1.get() != 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_FALSE(scoper1.get() == scoper2.get());
+ EXPECT_TRUE(scoper1.get() != scoper2.get());
}
EXPECT_EQ(0, constructed);
@@ -363,13 +367,13 @@ TEST(ScopedPtrTest, ScopedPtrWithArray) {
}
EXPECT_EQ(kNumLoggers, constructed);
- // Test Pass() with constructor;
- scoped_ptr<ConDecLogger[]> scoper2(scoper.Pass());
+ // Test moving with constructor;
+ scoped_ptr<ConDecLogger[]> scoper2(std::move(scoper));
EXPECT_EQ(kNumLoggers, constructed);
- // Test Pass() with assignment;
+ // Test moving with assignment;
scoped_ptr<ConDecLogger[]> scoper3;
- scoper3 = scoper2.Pass();
+ scoper3 = std::move(scoper2);
EXPECT_EQ(kNumLoggers, constructed);
EXPECT_FALSE(scoper);
EXPECT_FALSE(scoper2);
@@ -378,27 +382,30 @@ TEST(ScopedPtrTest, ScopedPtrWithArray) {
EXPECT_EQ(0, constructed);
}
-TEST(ScopedPtrTest, PassBehavior) {
+TEST(ScopedPtrTest, MoveBehavior) {
int constructed = 0;
{
ConDecLogger* logger = new ConDecLogger(&constructed);
scoped_ptr<ConDecLogger> scoper(logger);
EXPECT_EQ(1, constructed);
- // Test Pass() with constructor;
- scoped_ptr<ConDecLogger> scoper2(scoper.Pass());
+ // Test moving with constructor;
+ scoped_ptr<ConDecLogger> scoper2(std::move(scoper));
EXPECT_EQ(1, constructed);
- // Test Pass() with assignment;
+ // Test moving with assignment;
scoped_ptr<ConDecLogger> scoper3;
- scoper3 = scoper2.Pass();
+ scoper3 = std::move(scoper2);
EXPECT_EQ(1, constructed);
EXPECT_FALSE(scoper.get());
EXPECT_FALSE(scoper2.get());
EXPECT_TRUE(scoper3.get());
}
- // Test uncaught Pass() does not have side effects.
+#if !defined(OS_ANDROID) && !defined(OS_LINUX)
+ // Test uncaught Pass() does not have side effects, because Pass()
+ // is implemented by std::move().
+ // TODO(danakj): Remove this test case when we remove Pass().
{
ConDecLogger* logger = new ConDecLogger(&constructed);
scoped_ptr<ConDecLogger> scoper(logger);
@@ -411,6 +418,7 @@ TEST(ScopedPtrTest, PassBehavior) {
EXPECT_TRUE(rvalue);
}
EXPECT_EQ(0, constructed);
+#endif
// Test that passing to function which does nothing does not leak.
{
@@ -419,7 +427,7 @@ TEST(ScopedPtrTest, PassBehavior) {
EXPECT_EQ(1, constructed);
// Should auto-destruct logger by end of scope.
- GrabAndDrop(scoper.Pass());
+ GrabAndDrop(std::move(scoper));
EXPECT_FALSE(scoper.get());
}
EXPECT_EQ(0, constructed);
@@ -434,7 +442,7 @@ TEST(ScopedPtrTest, ReturnTypeBehavior) {
scoped_ptr<ConDecLogger> scoper(logger);
EXPECT_EQ(1, constructed);
- PassThru(scoper.Pass());
+ PassThru(std::move(scoper));
EXPECT_FALSE(scoper.get());
}
EXPECT_EQ(0, constructed);
@@ -446,7 +454,7 @@ TEST(ScopedPtrTest, ReturnTypeBehavior) {
EXPECT_EQ(1, constructed);
// Should auto-destruct logger by end of scope.
- PassThru(scoper.Pass());
+ PassThru(std::move(scoper));
EXPECT_FALSE(scoper.get());
}
EXPECT_EQ(0, constructed);
@@ -537,8 +545,8 @@ TEST(ScopedPtrTest, CustomDeleter) {
// 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<double, CountingDeleter> scoper3(scoper2.Pass());
- scoper = scoper3.Pass();
+ scoped_ptr<double, CountingDeleter> scoper3(std::move(scoper2));
+ scoper = std::move(scoper3);
EXPECT_EQ(1, deletes);
scoper2.reset(&dummy_value2);
@@ -549,33 +557,33 @@ TEST(ScopedPtrTest, CustomDeleter) {
EXPECT_EQ(1, deletes);
EXPECT_EQ(3, alternate_deletes);
- // Test swap(), ==, !=, and type-safe Boolean.
+ // Test swap(), and type-safe Boolean.
{
scoped_ptr<double, CountingDeleter> scoper1(NULL,
CountingDeleter(&deletes));
scoped_ptr<double, CountingDeleter> scoper2(NULL,
CountingDeleter(&deletes));
- EXPECT_TRUE(scoper1 == scoper2.get());
- EXPECT_FALSE(scoper1 != scoper2.get());
+ EXPECT_TRUE(scoper1.get() == scoper2.get());
+ EXPECT_FALSE(scoper1.get() != 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());
+ EXPECT_FALSE(scoper1.get() == scoper2.get());
+ EXPECT_TRUE(scoper1.get() != 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());
+ EXPECT_FALSE(scoper1.get() == scoper2.get());
+ EXPECT_TRUE(scoper1.get() != 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
+// coverage of reset/release/move operations as that is redundant with the
// above.
TEST(ScopedPtrTest, OverloadedNewAndDelete) {
{
@@ -583,7 +591,7 @@ TEST(ScopedPtrTest, OverloadedNewAndDelete) {
scoped_ptr<OverloadedNewAndDelete> scoper(new OverloadedNewAndDelete());
EXPECT_TRUE(scoper.get());
- scoped_ptr<OverloadedNewAndDelete> scoper2(scoper.Pass());
+ scoped_ptr<OverloadedNewAndDelete> scoper2(std::move(scoper));
}
EXPECT_EQ(1, OverloadedNewAndDelete::delete_count());
EXPECT_EQ(1, OverloadedNewAndDelete::new_count());
@@ -632,55 +640,15 @@ TEST(ScopedPtrTest, Conversion) {
scoped_ptr<Sub> sub1(new Sub);
scoped_ptr<Sub> sub2(new Sub);
- // Upcast with Pass() works.
- scoped_ptr<Super> super1 = sub1.Pass();
- super1 = sub2.Pass();
+ // Upcast with move works.
+ scoped_ptr<Super> super1 = std::move(sub1);
+ super1 = std::move(sub2);
// Upcast with an rvalue works.
scoped_ptr<Super> super2 = SubClassReturn();
super2 = SubClassReturn();
}
-// Android death tests don't work properly with assert(). Yay.
-#if !defined(NDEBUG) && defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
-TEST(ScopedPtrTest, SelfResetAbortsWithDefaultDeleter) {
- scoped_ptr<int> x(new int);
- EXPECT_DEATH(x.reset(x.get()), "");
-}
-
-TEST(ScopedPtrTest, SelfResetAbortsWithDefaultArrayDeleter) {
- scoped_ptr<int[]> y(new int[4]);
- EXPECT_DEATH(y.reset(y.get()), "");
-}
-
-TEST(ScopedPtrTest, SelfResetAbortsWithDefaultFreeDeleter) {
- scoped_ptr<int, base::FreeDeleter> z(static_cast<int*>(malloc(sizeof(int))));
- EXPECT_DEATH(z.reset(z.get()), "");
-}
-
-// A custom deleter that doesn't opt out should still crash.
-TEST(ScopedPtrTest, SelfResetAbortsWithCustomDeleter) {
- struct CustomDeleter {
- inline void operator()(int* x) { delete x; }
- };
- scoped_ptr<int, CustomDeleter> x(new int);
- EXPECT_DEATH(x.reset(x.get()), "");
-}
-#endif
-
-TEST(ScopedPtrTest, SelfResetWithCustomDeleterOptOut) {
- // A custom deleter should be able to opt out of self-reset abort behavior.
- struct NoOpDeleter {
-#if !defined(NDEBUG)
- typedef void AllowSelfReset;
-#endif
- inline void operator()(int*) {}
- };
- scoped_ptr<int> owner(new int);
- scoped_ptr<int, NoOpDeleter> x(owner.get());
- x.reset(x.get());
-}
-
// Logging a scoped_ptr<T> to an ostream shouldn't convert it to a boolean
// value first.
TEST(ScopedPtrTest, LoggingDoesntConvertToBoolean) {
@@ -693,3 +661,182 @@ TEST(ScopedPtrTest, LoggingDoesntConvertToBoolean) {
EXPECT_EQ(s2.str(), s1.str());
}
+
+TEST(ScopedPtrTest, ReferenceCycle) {
+ struct StructB;
+ struct StructA {
+ scoped_ptr<StructB> b;
+ };
+
+ struct StructB {
+ scoped_ptr<StructA> a;
+ };
+
+ // Create a reference cycle.
+ StructA* a = new StructA;
+ a->b.reset(new StructB);
+ a->b->a.reset(a);
+
+ // Break the cycle by calling reset(). This will cause |a| (and hence, |a->b|)
+ // to be deleted before the call to reset() returns. This tests that the
+ // implementation of scoped_ptr::reset() doesn't access |this| after it
+ // deletes the underlying pointer. This behaviour is consistent with the
+ // definition of unique_ptr::reset in C++11.
+ a->b.reset();
+
+ // Go again, but this time, break the cycle by invoking |a|'s destructor. This
+ // tests that the implementation of ~scoped_ptr doesn't infinitely recurse
+ // into the destructors of |a| and |a->b|. Note, deleting |a| instead will
+ // cause |a| to be double-free'd because |a->b| owns |a| and deletes it via
+ // its destructor.
+ a = new StructA;
+ a->b.reset(new StructB);
+ a->b->a.reset(a);
+ a->~StructA();
+}
+
+TEST(ScopedPtrTest, Operators) {
+ struct Parent {};
+ struct Child : public Parent {};
+
+ scoped_ptr<Parent> p(new Parent);
+ scoped_ptr<Parent> p2(new Parent);
+ scoped_ptr<Child> c(new Child);
+ scoped_ptr<Parent> pnull;
+
+ // Operator==.
+ EXPECT_TRUE(p == p);
+ EXPECT_FALSE(p == c);
+ EXPECT_FALSE(p == p2);
+ EXPECT_FALSE(p == pnull);
+
+ EXPECT_FALSE(p == nullptr);
+ EXPECT_FALSE(nullptr == p);
+ EXPECT_TRUE(pnull == nullptr);
+ EXPECT_TRUE(nullptr == pnull);
+
+ // Operator!=.
+ EXPECT_FALSE(p != p);
+ EXPECT_TRUE(p != c);
+ EXPECT_TRUE(p != p2);
+ EXPECT_TRUE(p != pnull);
+
+ EXPECT_TRUE(p != nullptr);
+ EXPECT_TRUE(nullptr != p);
+ EXPECT_FALSE(pnull != nullptr);
+ EXPECT_FALSE(nullptr != pnull);
+
+ // Compare two scoped_ptr<T>.
+ EXPECT_EQ(p.get() < p2.get(), p < p2);
+ EXPECT_EQ(p.get() <= p2.get(), p <= p2);
+ EXPECT_EQ(p.get() > p2.get(), p > p2);
+ EXPECT_EQ(p.get() >= p2.get(), p >= p2);
+ EXPECT_EQ(p2.get() < p.get(), p2 < p);
+ EXPECT_EQ(p2.get() <= p.get(), p2 <= p);
+ EXPECT_EQ(p2.get() > p.get(), p2 > p);
+ EXPECT_EQ(p2.get() >= p.get(), p2 >= p);
+
+ // And convertible scoped_ptr<T> and scoped_ptr<U>.
+ EXPECT_EQ(p.get() < c.get(), p < c);
+ EXPECT_EQ(p.get() <= c.get(), p <= c);
+ EXPECT_EQ(p.get() > c.get(), p > c);
+ EXPECT_EQ(p.get() >= c.get(), p >= c);
+ EXPECT_EQ(c.get() < p.get(), c < p);
+ EXPECT_EQ(c.get() <= p.get(), c <= p);
+ EXPECT_EQ(c.get() > p.get(), c > p);
+ EXPECT_EQ(c.get() >= p.get(), c >= p);
+
+ // Compare to nullptr.
+ EXPECT_TRUE(p > nullptr);
+ EXPECT_FALSE(nullptr > p);
+ EXPECT_FALSE(pnull > nullptr);
+ EXPECT_FALSE(nullptr > pnull);
+
+ EXPECT_TRUE(p >= nullptr);
+ EXPECT_FALSE(nullptr >= p);
+ EXPECT_TRUE(pnull >= nullptr);
+ EXPECT_TRUE(nullptr >= pnull);
+
+ EXPECT_FALSE(p < nullptr);
+ EXPECT_TRUE(nullptr < p);
+ EXPECT_FALSE(pnull < nullptr);
+ EXPECT_FALSE(nullptr < pnull);
+
+ EXPECT_FALSE(p <= nullptr);
+ EXPECT_TRUE(nullptr <= p);
+ EXPECT_TRUE(pnull <= nullptr);
+ EXPECT_TRUE(nullptr <= pnull);
+};
+
+TEST(ScopedPtrTest, ArrayOperators) {
+ struct Parent {};
+ struct Child : public Parent {};
+
+ scoped_ptr<Parent[]> p(new Parent[1]);
+ scoped_ptr<Parent[]> p2(new Parent[1]);
+ scoped_ptr<Child[]> c(new Child[1]);
+ scoped_ptr<Parent[]> pnull;
+
+ // Operator==.
+ EXPECT_TRUE(p == p);
+ EXPECT_FALSE(p == c);
+ EXPECT_FALSE(p == p2);
+ EXPECT_FALSE(p == pnull);
+
+ EXPECT_FALSE(p == nullptr);
+ EXPECT_FALSE(nullptr == p);
+ EXPECT_TRUE(pnull == nullptr);
+ EXPECT_TRUE(nullptr == pnull);
+
+ // Operator!=.
+ EXPECT_FALSE(p != p);
+ EXPECT_TRUE(p != c);
+ EXPECT_TRUE(p != p2);
+ EXPECT_TRUE(p != pnull);
+
+ EXPECT_TRUE(p != nullptr);
+ EXPECT_TRUE(nullptr != p);
+ EXPECT_FALSE(pnull != nullptr);
+ EXPECT_FALSE(nullptr != pnull);
+
+ // Compare two scoped_ptr<T>.
+ EXPECT_EQ(p.get() < p2.get(), p < p2);
+ EXPECT_EQ(p.get() <= p2.get(), p <= p2);
+ EXPECT_EQ(p.get() > p2.get(), p > p2);
+ EXPECT_EQ(p.get() >= p2.get(), p >= p2);
+ EXPECT_EQ(p2.get() < p.get(), p2 < p);
+ EXPECT_EQ(p2.get() <= p.get(), p2 <= p);
+ EXPECT_EQ(p2.get() > p.get(), p2 > p);
+ EXPECT_EQ(p2.get() >= p.get(), p2 >= p);
+
+ // And convertible scoped_ptr<T> and scoped_ptr<U>.
+ EXPECT_EQ(p.get() < c.get(), p < c);
+ EXPECT_EQ(p.get() <= c.get(), p <= c);
+ EXPECT_EQ(p.get() > c.get(), p > c);
+ EXPECT_EQ(p.get() >= c.get(), p >= c);
+ EXPECT_EQ(c.get() < p.get(), c < p);
+ EXPECT_EQ(c.get() <= p.get(), c <= p);
+ EXPECT_EQ(c.get() > p.get(), c > p);
+ EXPECT_EQ(c.get() >= p.get(), c >= p);
+
+ // Compare to nullptr.
+ EXPECT_TRUE(p > nullptr);
+ EXPECT_FALSE(nullptr > p);
+ EXPECT_FALSE(pnull > nullptr);
+ EXPECT_FALSE(nullptr > pnull);
+
+ EXPECT_TRUE(p >= nullptr);
+ EXPECT_FALSE(nullptr >= p);
+ EXPECT_TRUE(pnull >= nullptr);
+ EXPECT_TRUE(nullptr >= pnull);
+
+ EXPECT_FALSE(p < nullptr);
+ EXPECT_TRUE(nullptr < p);
+ EXPECT_FALSE(pnull < nullptr);
+ EXPECT_FALSE(nullptr < pnull);
+
+ EXPECT_FALSE(p <= nullptr);
+ EXPECT_TRUE(nullptr <= p);
+ EXPECT_TRUE(pnull <= nullptr);
+ EXPECT_TRUE(nullptr <= pnull);
+}
diff --git a/base/memory/scoped_ptr_unittest.nc b/base/memory/scoped_ptr_unittest.nc
index b62703c339..10b45a1897 100644
--- a/base/memory/scoped_ptr_unittest.nc
+++ b/base/memory/scoped_ptr_unittest.nc
@@ -2,8 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/basictypes.h"
+// This is a "No Compile Test" suite.
+// http://dev.chromium.org/developers/testing/no-compile-tests
+
#include "base/memory/scoped_ptr.h"
+
+#include <utility>
+
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
namespace {
@@ -19,31 +25,31 @@ class RefCountedClass : public base::RefCountedThreadSafe<RefCountedClass> {
} // namespace
-#if defined(NCTEST_NO_PASS_DOWNCAST) // [r"fatal error: no matching constructor for initialization of 'base::internal::scoped_ptr_impl<\(anonymous namespace\)::Child, base::DefaultDeleter<\(anonymous namespace\)::Child> >::Data'"]
+#if defined(NCTEST_NO_PASS_DOWNCAST) // [r"fatal error: no viable conversion from returned value of type 'scoped_ptr<\(anonymous namespace\)::Parent>' to function return type 'scoped_ptr<\(anonymous namespace\)::Child>'"]
scoped_ptr<Child> DowncastUsingPassAs(scoped_ptr<Parent> object) {
- return object.Pass();
+ return object;
}
-#elif defined(NCTEST_NO_REF_COUNTED_SCOPED_PTR) // [r"fatal error: static_assert failed \"T_is_refcounted_type_and_needs_scoped_refptr\""]
+#elif defined(NCTEST_NO_REF_COUNTED_SCOPED_PTR) // [r"fatal error: static_assert failed \"T is a refcounted type and needs a scoped_refptr\""]
// scoped_ptr<> should not work for ref-counted objects.
void WontCompile() {
scoped_ptr<RefCountedClass> x;
}
-#elif defined(NCTEST_NO_ARRAY_WITH_SIZE) // [r"fatal error: static_assert failed \"do_not_use_array_with_size_as_type\""]
+#elif defined(NCTEST_NO_ARRAY_WITH_SIZE) // [r"fatal error: static_assert failed \"scoped_ptr doesn't support array with size\""]
void WontCompile() {
scoped_ptr<int[10]> x;
}
-#elif defined(NCTEST_NO_PASS_FROM_ARRAY) // [r"fatal error: static_assert failed \"U_cannot_be_an_array\""]
+#elif defined(NCTEST_NO_PASS_FROM_ARRAY) // [r"fatal error: no viable overloaded '='"]
void WontCompile() {
scoped_ptr<int[]> a;
scoped_ptr<int*> b;
- b = a.Pass();
+ b = std::move(a);
}
#elif defined(NCTEST_NO_PASS_TO_ARRAY) // [r"fatal error: no viable overloaded '='"]
@@ -51,21 +57,21 @@ void WontCompile() {
void WontCompile() {
scoped_ptr<int*> a;
scoped_ptr<int[]> b;
- b = a.Pass();
+ b = std::move(a);
}
-#elif defined(NCTEST_NO_CONSTRUCT_FROM_ARRAY) // [r"fatal error: 'impl_' is a private member of 'scoped_ptr<int \[\], base::DefaultDeleter<int \[\]> >'"]
+#elif defined(NCTEST_NO_CONSTRUCT_FROM_ARRAY) // [r"fatal error: no matching constructor for initialization of 'scoped_ptr<int \*>'"]
void WontCompile() {
scoped_ptr<int[]> a;
- scoped_ptr<int*> b(a.Pass());
+ scoped_ptr<int*> b(std::move(a));
}
#elif defined(NCTEST_NO_CONSTRUCT_TO_ARRAY) // [r"fatal error: no matching constructor for initialization of 'scoped_ptr<int \[\]>'"]
void WontCompile() {
scoped_ptr<int*> a;
- scoped_ptr<int[]> b(a.Pass());
+ scoped_ptr<int[]> b(std::move(a));
}
#elif defined(NCTEST_NO_CONSTRUCT_SCOPED_PTR_ARRAY_FROM_NULL) // [r"is ambiguous"]
@@ -74,7 +80,7 @@ void WontCompile() {
scoped_ptr<int[]> x(NULL);
}
-#elif defined(NCTEST_NO_CONSTRUCT_SCOPED_PTR_ARRAY_FROM_DERIVED) // [r"fatal error: calling a private constructor of class 'scoped_ptr<\(anonymous namespace\)::Parent \[\], base::DefaultDeleter<\(anonymous namespace\)::Parent \[\]> >'"]
+#elif defined(NCTEST_NO_CONSTRUCT_SCOPED_PTR_ARRAY_FROM_DERIVED) // [r"fatal error: calling a private constructor of class 'scoped_ptr<\(anonymous namespace\)::Parent \[\], std::default_delete<\(anonymous namespace\)::Parent \[\]> >'"]
void WontCompile() {
scoped_ptr<Parent[]> x(new Child[1]);
@@ -87,7 +93,7 @@ void WontCompile() {
x.reset(NULL);
}
-#elif defined(NCTEST_NO_RESET_SCOPED_PTR_ARRAY_FROM_DERIVED) // [r"fatal error: 'reset' is a private member of 'scoped_ptr<\(anonymous namespace\)::Parent \[\], base::DefaultDeleter<\(anonymous namespace\)::Parent \[\]> >'"]
+#elif defined(NCTEST_NO_RESET_SCOPED_PTR_ARRAY_FROM_DERIVED) // [r"fatal error: 'reset' is a private member of 'scoped_ptr<\(anonymous namespace\)::Parent \[\], std::default_delete<\(anonymous namespace\)::Parent \[\]> >'"]
void WontCompile() {
scoped_ptr<Parent[]> x;
diff --git a/base/memory/scoped_vector.h b/base/memory/scoped_vector.h
index 173ea5a1d6..6730612abc 100644
--- a/base/memory/scoped_vector.h
+++ b/base/memory/scoped_vector.h
@@ -5,9 +5,10 @@
#ifndef BASE_MEMORY_SCOPED_VECTOR_H_
#define BASE_MEMORY_SCOPED_VECTOR_H_
+#include <stddef.h>
+
#include <vector>
-#include "base/basictypes.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/move.h"
@@ -15,9 +16,12 @@
// ScopedVector wraps a vector deleting the elements from its
// destructor.
+//
+// TODO(http://crbug.com/554289): DEPRECATED: Use std::vector instead (now that
+// we have support for moveable types inside containers).
template <class T>
class ScopedVector {
- MOVE_ONLY_TYPE_FOR_CPP_03(ScopedVector, RValue)
+ MOVE_ONLY_TYPE_FOR_CPP_03(ScopedVector)
public:
typedef typename std::vector<T*>::allocator_type allocator_type;
@@ -36,10 +40,10 @@ class ScopedVector {
ScopedVector() {}
~ScopedVector() { clear(); }
- ScopedVector(RValue other) { swap(*other.object); }
+ ScopedVector(ScopedVector&& other) { swap(other); }
- ScopedVector& operator=(RValue rhs) {
- swap(*rhs.object);
+ ScopedVector& operator=(ScopedVector&& rhs) {
+ swap(rhs);
return *this;
}
@@ -106,6 +110,10 @@ class ScopedVector {
return v_.insert(position, x);
}
+ iterator insert(iterator position, scoped_ptr<T> x) {
+ return v_.insert(position, x.release());
+ }
+
// Lets the ScopedVector take ownership of elements in [first,last).
template<typename InputIterator>
void insert(iterator position, InputIterator first, InputIterator last) {
diff --git a/base/memory/scoped_vector_unittest.cc b/base/memory/scoped_vector_unittest.cc
index 220cfb0468..8638ecee55 100644
--- a/base/memory/scoped_vector_unittest.cc
+++ b/base/memory/scoped_vector_unittest.cc
@@ -4,8 +4,11 @@
#include "base/memory/scoped_vector.h"
+#include <utility>
+
#include "base/bind.h"
#include "base/callback.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -24,7 +27,8 @@ class LifeCycleObject {
};
~LifeCycleObject() {
- observer_->OnLifeCycleDestroy(this);
+ if (observer_)
+ observer_->OnLifeCycleDestroy(this);
}
private:
@@ -35,6 +39,10 @@ class LifeCycleObject {
observer_->OnLifeCycleConstruct(this);
}
+ void DisconnectObserver() {
+ observer_ = nullptr;
+ }
+
Observer* observer_;
DISALLOW_COPY_AND_ASSIGN(LifeCycleObject);
@@ -62,7 +70,13 @@ enum LifeCycleState {
class LifeCycleWatcher : public LifeCycleObject::Observer {
public:
LifeCycleWatcher() : life_cycle_state_(LC_INITIAL) {}
- ~LifeCycleWatcher() override {}
+ ~LifeCycleWatcher() override {
+ // Stop watching the watched object. Without this, the object's destructor
+ // will call into OnLifeCycleDestroy when destructed, which happens after
+ // this destructor has finished running.
+ if (constructed_life_cycle_object_)
+ constructed_life_cycle_object_->DisconnectObserver();
+ }
// Assert INITIAL -> CONSTRUCTED and no LifeCycleObject associated with this
// LifeCycleWatcher.
@@ -214,7 +228,7 @@ TEST(ScopedVectorTest, MoveConstruct) {
EXPECT_FALSE(scoped_vector.empty());
EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
- ScopedVector<LifeCycleObject> scoped_vector_copy(scoped_vector.Pass());
+ ScopedVector<LifeCycleObject> scoped_vector_copy(std::move(scoped_vector));
EXPECT_TRUE(scoped_vector.empty());
EXPECT_FALSE(scoped_vector_copy.empty());
EXPECT_TRUE(watcher.IsWatching(scoped_vector_copy.back()));
@@ -234,7 +248,7 @@ TEST(ScopedVectorTest, MoveAssign) {
EXPECT_FALSE(scoped_vector.empty());
EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
- scoped_vector_assign = scoped_vector.Pass();
+ scoped_vector_assign = std::move(scoped_vector);
EXPECT_TRUE(scoped_vector.empty());
EXPECT_FALSE(scoped_vector_assign.empty());
EXPECT_TRUE(watcher.IsWatching(scoped_vector_assign.back()));
@@ -264,7 +278,7 @@ class DeleteCounter {
template <typename T>
ScopedVector<T> PassThru(ScopedVector<T> scoper) {
- return scoper.Pass();
+ return scoper;
}
TEST(ScopedVectorTest, Passed) {
@@ -315,7 +329,7 @@ TEST(ScopedVectorTest, PushBackScopedPtr) {
EXPECT_EQ(0, delete_counter);
{
ScopedVector<DeleteCounter> v;
- v.push_back(elem.Pass());
+ v.push_back(std::move(elem));
EXPECT_EQ(0, delete_counter);
}
EXPECT_EQ(1, delete_counter);
diff --git a/base/memory/shared_memory.h b/base/memory/shared_memory.h
index 008bb01066..a94b399a6a 100644
--- a/base/memory/shared_memory.h
+++ b/base/memory/shared_memory.h
@@ -5,21 +5,20 @@
#ifndef BASE_MEMORY_SHARED_MEMORY_H_
#define BASE_MEMORY_SHARED_MEMORY_H_
-#include "build/build_config.h"
+#include <stddef.h>
#include <string>
-#if defined(OS_POSIX)
-#include <stdio.h>
-#include <sys/types.h>
-#include <semaphore.h>
-#endif
-
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
+#include "base/memory/shared_memory_handle.h"
#include "base/process/process_handle.h"
+#include "build/build_config.h"
#if defined(OS_POSIX)
+#include <stdio.h>
+#include <sys/types.h>
+#include <semaphore.h>
#include "base/file_descriptor_posix.h"
#include "base/files/file_util.h"
#include "base/files/scoped_file.h"
@@ -29,38 +28,30 @@ 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;
-#elif defined(OS_POSIX)
-typedef FileDescriptor SharedMemoryHandle;
-#endif
-
// Options for creating a shared memory object.
-struct SharedMemoryCreateOptions {
- SharedMemoryCreateOptions()
- : name_deprecated(NULL),
- size(0),
- open_existing_deprecated(false),
- executable(false),
- share_read_only(false) {}
+struct BASE_EXPORT SharedMemoryCreateOptions {
+ SharedMemoryCreateOptions();
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+ // The type of OS primitive that should back the SharedMemory object.
+ SharedMemoryHandle::Type type;
+#else
// DEPRECATED (crbug.com/345734):
// 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_deprecated;
- // Size of the shared memory object to be created.
- // When opening an existing object, this has no effect.
- size_t size;
-
// DEPRECATED (crbug.com/345734):
// 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_deprecated is non-NULL.
bool open_existing_deprecated;
+#endif // defined(OS_MACOSX) && !defined(OS_IOS)
+
+ // Size of the shared memory object to be created.
+ // When opening an existing object, this has no effect.
+ size_t size;
// If true, mappings might need to be made executable later.
bool executable;
@@ -89,13 +80,16 @@ class BASE_EXPORT SharedMemory {
// only affects how the SharedMemory will be mmapped. Use
// ShareReadOnlyToProcess to drop permissions. TODO(jln,jyasskin): DCHECK
// that |read_only| matches the permissions of the handle.
- SharedMemory(SharedMemoryHandle handle, bool read_only);
+ SharedMemory(const SharedMemoryHandle& handle, bool read_only);
+#if defined(OS_WIN)
// 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,
+ SharedMemory(const SharedMemoryHandle& handle,
+ bool read_only,
ProcessHandle process);
+#endif
// Closes any open files.
~SharedMemory();
@@ -123,9 +117,11 @@ class BASE_EXPORT SharedMemory {
#endif
#if defined(OS_POSIX) && !defined(OS_ANDROID)
- // Returns the size of the shared memory region referred to by |handle|.
- // Returns '-1' on a failure to determine the size.
- static int GetSizeFromSharedMemoryHandle(const SharedMemoryHandle& handle);
+ // Gets the size of the shared memory region referred to by |handle|.
+ // Returns false on a failure to determine the size. On success, populates the
+ // output variable |size|.
+ static bool GetSizeFromSharedMemoryHandle(const SharedMemoryHandle& handle,
+ size_t* size);
#endif // defined(OS_POSIX) && !defined(OS_ANDROID)
// Creates a shared memory object as described by the options struct.
@@ -136,6 +132,16 @@ class BASE_EXPORT SharedMemory {
// Returns true on success and false on failure.
bool CreateAndMapAnonymous(size_t size);
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+ // These two methods are analogs of CreateAndMapAnonymous and CreateAnonymous
+ // that force the underlying OS primitive to be a POSIX fd. Do not add new
+ // uses of these methods unless absolutely necessary, since constructing a
+ // fd-backed SharedMemory object frequently takes 100ms+.
+ // http://crbug.com/466437.
+ bool CreateAndMapAnonymousPosix(size_t size);
+ bool CreateAnonymousPosix(size_t size);
+#endif // defined(OS_MACOSX) && !defined(OS_IOS)
+
// Creates an anonymous shared memory segment of size size.
// Returns true on success and false on failure.
bool CreateAnonymous(size_t size) {
@@ -144,6 +150,7 @@ class BASE_EXPORT SharedMemory {
return Create(options);
}
+#if !defined(OS_MACOSX) || defined(OS_IOS)
// DEPRECATED (crbug.com/345734):
// Creates or opens a shared memory segment based on a name.
// If open_existing is true, and the shared memory already exists,
@@ -168,6 +175,7 @@ class BASE_EXPORT SharedMemory {
// 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);
+#endif // !defined(OS_MACOSX) || defined(OS_IOS)
// Maps the shared memory into the caller's address space.
// Returns true on success, false otherwise. The memory address
@@ -197,7 +205,7 @@ class BASE_EXPORT SharedMemory {
// 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_; }
+ void* memory() const { return memory_; }
// Returns the underlying OS handle for this segment.
// Use of this handle for anything other than an opaque
@@ -257,27 +265,13 @@ class BASE_EXPORT SharedMemory {
return ShareToProcessCommon(process, new_handle, true, SHARE_CURRENT_MODE);
}
- // DEPRECATED (crbug.com/345734):
- // Locks the shared memory.
- //
- // WARNING: on POSIX the memory locking primitive only works across
- // processes, not across threads. The LockDeprecated method is not currently
- // used in inner loops, so we protect against multiple threads in a
- // critical section using a class global lock.
- void LockDeprecated();
-
- // DEPRECATED (crbug.com/345734):
- // Releases the shared memory lock.
- void UnlockDeprecated();
-
private:
-#if defined(OS_POSIX) && !defined(OS_NACL)
-#if !defined(OS_ANDROID)
+#if defined(OS_POSIX) && !defined(OS_NACL) && !defined(OS_ANDROID)
bool PrepareMapFile(ScopedFILE fp, ScopedFD readonly);
+#if !(defined(OS_MACOSX) && !defined(OS_IOS))
bool FilePathForMemoryName(const std::string& mem_name, FilePath* path);
#endif
- void LockOrUnlockCommon(int function);
-#endif // defined(OS_POSIX) && !defined(OS_NACL)
+#endif // defined(OS_POSIX) && !defined(OS_NACL) && !defined(OS_ANDROID)
enum ShareMode {
SHARE_READONLY,
SHARE_CURRENT_MODE,
@@ -288,8 +282,20 @@ class BASE_EXPORT SharedMemory {
ShareMode);
#if defined(OS_WIN)
+ // If true indicates this came from an external source so needs extra checks
+ // before being mapped.
+ bool external_section_;
std::wstring name_;
HANDLE mapped_file_;
+#elif defined(OS_MACOSX) && !defined(OS_IOS)
+ // The OS primitive that backs the shared memory region.
+ SharedMemoryHandle shm_;
+
+ // The mechanism by which the memory is mapped. Only valid if |memory_| is not
+ // |nullptr|.
+ SharedMemoryHandle::Type mapped_memory_mechanism_;
+
+ int readonly_mapped_file_;
#elif defined(OS_POSIX)
int mapped_file_;
int readonly_mapped_file_;
@@ -298,32 +304,9 @@ class BASE_EXPORT SharedMemory {
void* memory_;
bool read_only_;
size_t requested_size_;
-#if !defined(OS_POSIX)
- HANDLE lock_;
-#endif
DISALLOW_COPY_AND_ASSIGN(SharedMemory);
};
-
-// DEPRECATED (crbug.com/345734):
-// A helper class that acquires the shared memory lock while
-// the SharedMemoryAutoLockDeprecated is in scope.
-class SharedMemoryAutoLockDeprecated {
- public:
- explicit SharedMemoryAutoLockDeprecated(SharedMemory* shared_memory)
- : shared_memory_(shared_memory) {
- shared_memory_->LockDeprecated();
- }
-
- ~SharedMemoryAutoLockDeprecated() {
- shared_memory_->UnlockDeprecated();
- }
-
- private:
- SharedMemory* shared_memory_;
- DISALLOW_COPY_AND_ASSIGN(SharedMemoryAutoLockDeprecated);
-};
-
} // namespace base
#endif // BASE_MEMORY_SHARED_MEMORY_H_
diff --git a/base/memory/singleton.h b/base/memory/singleton.h
index e50bdc05f3..79e4441a8e 100644
--- a/base/memory/singleton.h
+++ b/base/memory/singleton.h
@@ -22,6 +22,7 @@
#include "base/at_exit.h"
#include "base/atomicops.h"
#include "base/base_export.h"
+#include "base/macros.h"
#include "base/memory/aligned_memory.h"
#include "base/threading/thread_restrictions.h"
@@ -36,10 +37,10 @@ static const subtle::AtomicWord kBeingCreatedMarker = 1;
// we can implement the more complicated pieces out of line in the .cc file.
BASE_EXPORT subtle::AtomicWord WaitForInstance(subtle::AtomicWord* instance);
+class DeleteTraceLogForTesting;
+
} // namespace internal
-} // namespace base
-// TODO(joth): Move more of this file into namespace base
// Default traits for Singleton<Type>. Calls operator new and operator delete on
// the object. Registers automatic deletion at process exit.
@@ -110,7 +111,7 @@ struct StaticMemorySingletonTraits {
// 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))
+ if (subtle::NoBarrier_AtomicExchange(&dead_, 1))
return NULL;
return new(buffer_.void_data()) Type();
@@ -125,20 +126,19 @@ struct StaticMemorySingletonTraits {
static const bool kAllowedToAccessOnNonjoinableThread = true;
// Exposed for unittesting.
- static void Resurrect() {
- base::subtle::NoBarrier_Store(&dead_, 0);
- }
+ static void Resurrect() { subtle::NoBarrier_Store(&dead_, 0); }
private:
- static base::AlignedMemory<sizeof(Type), ALIGNOF(Type)> buffer_;
+ static AlignedMemory<sizeof(Type), ALIGNOF(Type)> buffer_;
// Signal the object was already deleted, so it is not revived.
- static base::subtle::Atomic32 dead_;
+ static subtle::Atomic32 dead_;
};
-template <typename Type> base::AlignedMemory<sizeof(Type), ALIGNOF(Type)>
+template <typename Type>
+AlignedMemory<sizeof(Type), ALIGNOF(Type)>
StaticMemorySingletonTraits<Type>::buffer_;
-template <typename Type> base::subtle::Atomic32
- StaticMemorySingletonTraits<Type>::dead_ = 0;
+template <typename Type>
+subtle::Atomic32 StaticMemorySingletonTraits<Type>::dead_ = 0;
// The Singleton<Type, Traits, DifferentiatingType> class manages a single
// instance of Type which will be created on first use and will be destroyed at
@@ -190,7 +190,7 @@ template <typename Type> base::subtle::Atomic32
// 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
+// process exit. More precisely it uses 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.
@@ -209,6 +209,7 @@ template <typename Type> base::subtle::Atomic32
// (b) Your factory function must never throw an exception. This class is not
// exception-safe.
//
+
template <typename Type,
typename Traits = DefaultSingletonTraits<Type>,
typename DifferentiatingType = Type>
@@ -219,7 +220,7 @@ class Singleton {
friend Type* Type::GetInstance();
// Allow TraceLog tests to test tracing after OnExit.
- friend class DeleteTraceLogForTesting;
+ friend class internal::DeleteTraceLogForTesting;
// This class is safe to be constructed and copy-constructed since it has no
// member.
@@ -229,36 +230,36 @@ class Singleton {
#ifndef NDEBUG
// Avoid making TLS lookup on release builds.
if (!Traits::kAllowedToAccessOnNonjoinableThread)
- base::ThreadRestrictions::AssertSingletonAllowed();
+ ThreadRestrictions::AssertSingletonAllowed();
#endif
// The load has acquire memory ordering as the thread which reads the
// instance_ pointer must acquire visibility over the singleton data.
- base::subtle::AtomicWord value = base::subtle::Acquire_Load(&instance_);
- if (value != 0 && value != base::internal::kBeingCreatedMarker) {
+ subtle::AtomicWord value = subtle::Acquire_Load(&instance_);
+ if (value != 0 && value != internal::kBeingCreatedMarker) {
return reinterpret_cast<Type*>(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) {
+ if (subtle::Acquire_CompareAndSwap(&instance_, 0,
+ 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();
// Releases the visibility over instance_ to the readers.
- base::subtle::Release_Store(
- &instance_, reinterpret_cast<base::subtle::AtomicWord>(newval));
+ subtle::Release_Store(&instance_,
+ reinterpret_cast<subtle::AtomicWord>(newval));
if (newval != NULL && Traits::kRegisterAtExit)
- base::AtExitManager::RegisterCallback(OnExit, NULL);
+ AtExitManager::RegisterCallback(OnExit, NULL);
return newval;
}
// We hit a race. Wait for the other thread to complete it.
- value = base::internal::WaitForInstance(&instance_);
+ value = internal::WaitForInstance(&instance_);
return reinterpret_cast<Type*>(value);
}
@@ -269,15 +270,15 @@ class Singleton {
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<Type*>(base::subtle::NoBarrier_Load(&instance_)));
+ Traits::Delete(reinterpret_cast<Type*>(subtle::NoBarrier_Load(&instance_)));
instance_ = 0;
}
- static base::subtle::AtomicWord instance_;
+ static subtle::AtomicWord instance_;
};
template <typename Type, typename Traits, typename DifferentiatingType>
-base::subtle::AtomicWord Singleton<Type, Traits, DifferentiatingType>::
- instance_ = 0;
+subtle::AtomicWord Singleton<Type, Traits, DifferentiatingType>::instance_ = 0;
+
+} // namespace base
#endif // BASE_MEMORY_SINGLETON_H_
diff --git a/base/memory/singleton_unittest.cc b/base/memory/singleton_unittest.cc
index dbff007ada..a15145c874 100644
--- a/base/memory/singleton_unittest.cc
+++ b/base/memory/singleton_unittest.cc
@@ -2,13 +2,17 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stdint.h>
+
#include "base/at_exit.h"
#include "base/memory/singleton.h"
#include "testing/gtest/include/gtest/gtest.h"
+namespace base {
namespace {
-COMPILE_ASSERT(DefaultSingletonTraits<int>::kRegisterAtExit == true, a);
+static_assert(DefaultSingletonTraits<int>::kRegisterAtExit == true,
+ "object must be deleted on process exit");
typedef void (*CallbackFunc)();
@@ -115,7 +119,7 @@ class AlignedTestSingleton {
~AlignedTestSingleton() {}
static AlignedTestSingleton* GetInstance() {
return Singleton<AlignedTestSingleton,
- StaticMemorySingletonTraits<AlignedTestSingleton> >::get();
+ StaticMemorySingletonTraits<AlignedTestSingleton>>::get();
}
Type type_;
@@ -147,7 +151,6 @@ CallbackFunc* GetStaticSingleton() {
return &CallbackSingletonWithStaticTrait::GetInstance()->callback_;
}
-} // namespace
class SingletonTest : public testing::Test {
public:
@@ -207,7 +210,7 @@ TEST_F(SingletonTest, Basic) {
CallbackFunc* static_singleton;
{
- base::ShadowingAtExitManager sem;
+ ShadowingAtExitManager sem;
{
singleton_int = SingletonInt();
}
@@ -241,7 +244,7 @@ TEST_F(SingletonTest, Basic) {
EXPECT_EQ(NULL, GetStaticSingleton());
{
- base::ShadowingAtExitManager sem;
+ ShadowingAtExitManager sem;
// Verifiy that the variables were reset.
{
singleton_int = SingletonInt();
@@ -271,8 +274,8 @@ TEST_F(SingletonTest, Alignment) {
// 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<int32>* align4 =
- AlignedTestSingleton<int32>::GetInstance();
+ AlignedTestSingleton<int32_t>* align4 =
+ AlignedTestSingleton<int32_t>::GetInstance();
AlignedTestSingleton<AlignedMemory<32, 32> >* align32 =
AlignedTestSingleton<AlignedMemory<32, 32> >::GetInstance();
AlignedTestSingleton<AlignedMemory<128, 128> >* align128 =
@@ -285,3 +288,6 @@ TEST_F(SingletonTest, Alignment) {
EXPECT_ALIGNED(align128, 128);
EXPECT_ALIGNED(align4096, 4096);
}
+
+} // namespace
+} // namespace base
diff --git a/base/memory/weak_ptr.h b/base/memory/weak_ptr.h
index 8a433922fd..33d1e47362 100644
--- a/base/memory/weak_ptr.h
+++ b/base/memory/weak_ptr.h
@@ -16,6 +16,7 @@
//
// class Controller {
// public:
+// Controller() : weak_factory_(this) {}
// void SpawnWorker() { Worker::StartNew(weak_factory_.GetWeakPtr()); }
// void WorkComplete(const Result& result) { ... }
// private:
@@ -58,15 +59,20 @@
// off to other task runners, e.g. to use to post tasks back to object on the
// bound sequence.
//
-// Invalidating the factory's WeakPtrs un-binds it from the sequence, allowing
-// it to be passed for a different sequence to use or delete it.
+// If all WeakPtr objects are destroyed or invalidated then the factory is
+// unbound from the SequencedTaskRunner/Thread. The WeakPtrFactory may then be
+// destroyed, or new WeakPtr objects may be used, from a different sequence.
+//
+// Thus, at least one WeakPtr object must exist and have been dereferenced on
+// the correct thread to enforce that other WeakPtr objects will enforce they
+// are used on the desired thread.
#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/macros.h"
#include "base/memory/ref_counted.h"
#include "base/sequence_checker.h"
#include "base/template_util.h"
@@ -155,8 +161,8 @@ class SupportsWeakPtrBase {
static WeakPtr<Derived> StaticAsWeakPtr(Derived* t) {
typedef
is_convertible<Derived, internal::SupportsWeakPtrBase&> convertible;
- COMPILE_ASSERT(convertible::value,
- AsWeakPtr_argument_inherits_from_SupportsWeakPtr);
+ static_assert(convertible::value,
+ "AsWeakPtr argument must inherit from SupportsWeakPtr");
return AsWeakPtrImpl<Derived>(t, *t);
}
diff --git a/base/memory/weak_ptr_unittest.nc b/base/memory/weak_ptr_unittest.nc
index 2ab428d2ab..bad1c97ef9 100644
--- a/base/memory/weak_ptr_unittest.nc
+++ b/base/memory/weak_ptr_unittest.nc
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// This is a "No Compile Test" suite.
+// http://dev.chromium.org/developers/testing/no-compile-tests
+
#include "base/memory/weak_ptr.h"
namespace base {
@@ -112,14 +115,14 @@ void WontCompile() {
WeakPtr<Unrelated> ptr = AsWeakPtr<Unrelated>(&f);
}
-#elif defined(NCTEST_COMPLETELY_UNRELATED_HELPER) // [r"fatal error: static_assert failed \"AsWeakPtr_argument_inherits_from_SupportsWeakPtr\""]
+#elif defined(NCTEST_COMPLETELY_UNRELATED_HELPER) // [r"fatal error: static_assert failed \"AsWeakPtr argument must inherit from SupportsWeakPtr\""]
void WontCompile() {
Unrelated f;
WeakPtr<Unrelated> ptr = AsWeakPtr(&f);
}
-#elif defined(NCTEST_DERIVED_COMPLETELY_UNRELATED_HELPER) // [r"fatal error: static_assert failed \"AsWeakPtr_argument_inherits_from_SupportsWeakPtr\""]
+#elif defined(NCTEST_DERIVED_COMPLETELY_UNRELATED_HELPER) // [r"fatal error: static_assert failed \"AsWeakPtr argument must inherit from SupportsWeakPtr\""]
void WontCompile() {
DerivedUnrelated f;
diff --git a/base/message_loop/incoming_task_queue.cc b/base/message_loop/incoming_task_queue.cc
index 67a813f3bf..9e3cdc9489 100644
--- a/base/message_loop/incoming_task_queue.cc
+++ b/base/message_loop/incoming_task_queue.cc
@@ -11,6 +11,7 @@
#include "base/metrics/histogram.h"
#include "base/synchronization/waitable_event.h"
#include "base/time/time.h"
+#include "build/build_config.h"
namespace base {
namespace internal {
@@ -120,11 +121,6 @@ void IncomingTaskQueue::StartScheduling() {
ScheduleWork();
}
-TimeTicks IncomingTaskQueue::GetNewlyAddedTaskDelay() {
- return !incoming_queue_.empty() ? incoming_queue_.front().delayed_run_time :
- TimeTicks();
-}
-
IncomingTaskQueue::~IncomingTaskQueue() {
// Verify that WillDestroyCurrentMessageLoop() has been called.
DCHECK(!message_loop_);
@@ -153,7 +149,7 @@ bool IncomingTaskQueue::PostPendingTask(PendingTask* pending_task) {
}
// Initialize the sequence number. The sequence number is used for delayed
- // tasks (to faciliate FIFO sorting when two tasks have the same
+ // tasks (to facilitate 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_++;
diff --git a/base/message_loop/incoming_task_queue.h b/base/message_loop/incoming_task_queue.h
index 544f3e907e..e450aa164f 100644
--- a/base/message_loop/incoming_task_queue.h
+++ b/base/message_loop/incoming_task_queue.h
@@ -6,6 +6,7 @@
#define BASE_MESSAGE_LOOP_INCOMING_TASK_QUEUE_H_
#include "base/base_export.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/pending_task.h"
#include "base/synchronization/lock.h"
@@ -57,9 +58,6 @@ class BASE_EXPORT IncomingTaskQueue
// scheduling work.
void StartScheduling();
- // Returns the delay for the most recently added task.
- TimeTicks GetNewlyAddedTaskDelay();
-
private:
friend class RefCountedThreadSafe<IncomingTaskQueue>;
virtual ~IncomingTaskQueue();
diff --git a/base/message_loop/message_loop.cc b/base/message_loop/message_loop.cc
index c0cc4f7552..e2b8bcaf0c 100644
--- a/base/message_loop/message_loop.cc
+++ b/base/message_loop/message_loop.cc
@@ -5,6 +5,7 @@
#include "base/message_loop/message_loop.h"
#include <algorithm>
+#include <utility>
#include "base/bind.h"
#include "base/compiler_specific.h"
@@ -18,7 +19,9 @@
#include "base/thread_task_runner_handle.h"
#include "base/threading/thread_local.h"
#include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
#include "base/tracked_objects.h"
+#include "build/build_config.h"
#if defined(OS_MACOSX)
#include "base/message_loop/message_pump_mac.h"
@@ -42,7 +45,7 @@ namespace {
LazyInstance<base::ThreadLocalPointer<MessageLoop> >::Leaky lazy_tls_ptr =
LAZY_INSTANCE_INITIALIZER;
-// Logical events for Histogram profiling. Run with -message-loop-histogrammer
+// 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;
#if !defined(OS_NACL)
@@ -54,9 +57,9 @@ 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,
+// constant) and creates a pair to initialize 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
+// of the expression (i.e., the expression put in quotes). For example, if
// we have:
// #define FOO 2
// #define BAR 5
@@ -77,7 +80,7 @@ const LinearHistogram::DescriptionPair event_descriptions_[] = {
VALUE_TO_NUMBER_AND_NAME(kTaskRunEvent)
VALUE_TO_NUMBER_AND_NAME(kTimerEvent)
- {-1, NULL} // The list must be null terminated, per API to histogram.
+ {-1, NULL} // The list must be null-terminated, per API to histogram.
};
#endif // !defined(OS_NACL)
@@ -129,9 +132,11 @@ MessageLoop::MessageLoop(scoped_ptr<MessagePump> pump)
}
MessageLoop::~MessageLoop() {
- // current() could be NULL if this message loop is destructed before it is
- // bound to a thread.
- DCHECK(current() == this || !current());
+ // If |pump_| is non-null, this message loop has been bound and should be the
+ // current one on this thread. Otherwise, this loop is being destructed before
+ // it was bound to a thread, so a different message loop (or no loop at all)
+ // may be current.
+ DCHECK((pump_ && current() == this) || (!pump_ && current() != this));
// iOS just attaches to the loop, it doesn't Run it.
// TODO(stuartmorgan): Consider wiring up a Detach().
@@ -169,10 +174,12 @@ MessageLoop::~MessageLoop() {
// Tell the incoming queue that we are dying.
incoming_task_queue_->WillDestroyCurrentMessageLoop();
incoming_task_queue_ = NULL;
- message_loop_proxy_ = NULL;
+ unbound_task_runner_ = NULL;
+ task_runner_ = NULL;
// OK, now make it so that no one can find us.
- lazy_tls_ptr.Pointer()->Set(NULL);
+ if (current() == this)
+ lazy_tls_ptr.Pointer()->Set(nullptr);
}
// static
@@ -256,27 +263,27 @@ void MessageLoop::RemoveDestructionObserver(
void MessageLoop::PostTask(
const tracked_objects::Location& from_here,
const Closure& task) {
- message_loop_proxy_->PostTask(from_here, task);
+ task_runner_->PostTask(from_here, task);
}
void MessageLoop::PostDelayedTask(
const tracked_objects::Location& from_here,
const Closure& task,
TimeDelta delay) {
- message_loop_proxy_->PostDelayedTask(from_here, task, delay);
+ task_runner_->PostDelayedTask(from_here, task, delay);
}
void MessageLoop::PostNonNestableTask(
const tracked_objects::Location& from_here,
const Closure& task) {
- message_loop_proxy_->PostNonNestableTask(from_here, task);
+ task_runner_->PostNonNestableTask(from_here, task);
}
void MessageLoop::PostNonNestableDelayedTask(
const tracked_objects::Location& from_here,
const Closure& task,
TimeDelta delay) {
- message_loop_proxy_->PostNonNestableDelayedTask(from_here, task, delay);
+ task_runner_->PostNonNestableDelayedTask(from_here, task, delay);
}
void MessageLoop::Run() {
@@ -359,13 +366,14 @@ bool MessageLoop::HasHighResolutionTasks() {
}
bool MessageLoop::IsIdleForTesting() {
- // We only check the imcoming queue|, since we don't want to lock the work
+ // We only check the incoming queue, since we don't want to lock the work
// queue.
return incoming_task_queue_->IsIdleForTesting();
}
//------------------------------------------------------------------------------
+// static
scoped_ptr<MessageLoop> MessageLoop::CreateUnbound(
Type type, MessagePumpFactoryCallback pump_factory) {
return make_scoped_ptr(new MessageLoop(type, pump_factory));
@@ -385,8 +393,9 @@ MessageLoop::MessageLoop(Type type, MessagePumpFactoryCallback pump_factory)
message_histogram_(NULL),
run_loop_(NULL),
incoming_task_queue_(new internal::IncomingTaskQueue(this)),
- message_loop_proxy_(
- new internal::MessageLoopProxyImpl(incoming_task_queue_)) {
+ unbound_task_runner_(
+ new internal::MessageLoopTaskRunner(incoming_task_queue_)),
+ task_runner_(unbound_task_runner_) {
// If type is TYPE_CUSTOM non-null pump_factory must be given.
DCHECK_EQ(type_ == TYPE_CUSTOM, !pump_factory_.is_null());
}
@@ -402,9 +411,26 @@ void MessageLoop::BindToCurrentThread() {
lazy_tls_ptr.Pointer()->Set(this);
incoming_task_queue_->StartScheduling();
- message_loop_proxy_->BindToCurrentThread();
- thread_task_runner_handle_.reset(
- new ThreadTaskRunnerHandle(message_loop_proxy_));
+ unbound_task_runner_->BindToCurrentThread();
+ unbound_task_runner_ = nullptr;
+ SetThreadTaskRunnerHandle();
+}
+
+void MessageLoop::SetTaskRunner(
+ scoped_refptr<SingleThreadTaskRunner> task_runner) {
+ DCHECK_EQ(this, current());
+ DCHECK(task_runner->BelongsToCurrentThread());
+ DCHECK(!unbound_task_runner_);
+ task_runner_ = std::move(task_runner);
+ SetThreadTaskRunnerHandle();
+}
+
+void MessageLoop::SetThreadTaskRunnerHandle() {
+ DCHECK_EQ(this, current());
+ // Clear the previous thread task runner first, because only one can exist at
+ // a time.
+ thread_task_runner_handle_.reset();
+ thread_task_runner_handle_.reset(new ThreadTaskRunnerHandle(task_runner_));
}
void MessageLoop::RunHandler() {
@@ -452,10 +478,11 @@ void MessageLoop::RunTask(const PendingTask& pending_task) {
HistogramEvent(kTaskRunEvent);
+ TRACE_TASK_EXECUTION("MessageLoop::RunTask", pending_task);
+
FOR_EACH_OBSERVER(TaskObserver, task_observers_,
WillProcessTask(pending_task));
- task_annotator_.RunTask(
- "MessageLoop::PostTask", "MessageLoop::RunTask", pending_task);
+ task_annotator_.RunTask("MessageLoop::PostTask", pending_task);
FOR_EACH_OBSERVER(TaskObserver, task_observers_,
DidProcessTask(pending_task));
@@ -542,7 +569,7 @@ void MessageLoop::StartHistogrammer() {
"MsgLoop:" + thread_name_,
kLeastNonZeroMessageId, kMaxMessageId,
kNumberOfDistinctMessagesDisplayed,
- message_histogram_->kHexRangePrintingFlag,
+ HistogramBase::kHexRangePrintingFlag,
event_descriptions_);
}
#endif
@@ -592,7 +619,7 @@ bool MessageLoop::DoDelayedWork(TimeTicks* next_delayed_work_time) {
return false;
}
- // When we "fall behind," there will be a lot of tasks in the delayed work
+ // 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
@@ -639,10 +666,6 @@ bool MessageLoop::DoIdleWork() {
return false;
}
-TimeTicks MessageLoop::GetNewlyAddedTaskDelay() {
- return incoming_task_queue_->GetNewlyAddedTaskDelay();
-}
-
void MessageLoop::DeleteSoonInternal(const tracked_objects::Location& from_here,
void(*deleter)(const void*),
const void* object) {
diff --git a/base/message_loop/message_loop.h b/base/message_loop/message_loop.h
index f26b9ecfa7..e78b70497d 100644
--- a/base/message_loop/message_loop.h
+++ b/base/message_loop/message_loop.h
@@ -9,15 +9,15 @@
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/callback_forward.h"
#include "base/debug/task_annotator.h"
+#include "base/gtest_prod_util.h"
#include "base/location.h"
+#include "base/macros.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_loop_task_runner.h"
#include "base/message_loop/message_pump.h"
#include "base/message_loop/timer_slack.h"
#include "base/observer_list.h"
@@ -26,6 +26,7 @@
#include "base/synchronization/lock.h"
#include "base/time/time.h"
#include "base/tracking_info.h"
+#include "build/build_config.h"
// TODO(sky): these includes should not be necessary. Nuke them.
#if defined(OS_WIN)
@@ -243,9 +244,6 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate {
// 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
@@ -269,9 +267,6 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate {
// 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.
@@ -296,33 +291,31 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate {
}
const std::string& thread_name() const { return thread_name_; }
- // Gets the message loop proxy associated with this message loop.
- //
- // NOTE: Deprecated; prefer task_runner() and the TaskRunner interfaces
- scoped_refptr<MessageLoopProxy> message_loop_proxy() {
- return message_loop_proxy_;
- }
-
// Gets the TaskRunner associated with this message loop.
- // TODO(skyostil): Change this to return a const reference to a refptr
- // once the internal type matches what is being returned (crbug.com/465354).
- scoped_refptr<SingleThreadTaskRunner> task_runner() {
- return message_loop_proxy_;
+ const scoped_refptr<SingleThreadTaskRunner>& task_runner() {
+ return task_runner_;
}
+ // Sets a new TaskRunner for this message loop. The message loop must already
+ // have been bound to a thread prior to this call, and the task runner must
+ // belong to that thread. Note that changing the task runner will also affect
+ // the ThreadTaskRunnerHandle for the target thread. Must be called on the
+ // thread to which the message loop is bound.
+ void SetTaskRunner(scoped_refptr<SingleThreadTaskRunner> task_runner);
+
// Enables or disables the recursive task processing. This happens in the case
- // of recursive message loops. Some unwanted message loop may occurs when
+ // of recursive message loops. Some unwanted message loops may occur 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
+ // Please use |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
+ // - It receives a task #1 and executes it.
+ // - The task #1 implicitly starts 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.
@@ -411,6 +404,7 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate {
friend class internal::IncomingTaskQueue;
friend class ScheduleWorkTest;
friend class Thread;
+ FRIEND_TEST_ALL_PREFIXES(MessageLoopTest, DeleteUnboundLoop);
using MessagePumpFactoryCallback = Callback<scoped_ptr<MessagePump>()>;
@@ -423,9 +417,9 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate {
// and then pass it to the thread where the message loop actually runs.
// The message loop's BindToCurrentThread() method must be called on the
// thread the message loop runs on, before calling Run().
- // Before BindToCurrentThread() is called only Post*Task() functions can
+ // Before BindToCurrentThread() is called, only Post*Task() functions can
// be called on the message loop.
- scoped_ptr<MessageLoop> CreateUnbound(
+ static scoped_ptr<MessageLoop> CreateUnbound(
Type type,
MessagePumpFactoryCallback pump_factory);
@@ -436,6 +430,10 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate {
// Configure various members and bind this message loop to the current thread.
void BindToCurrentThread();
+ // Sets the ThreadTaskRunnerHandle for the current thread to point to the
+ // task runner for this message loop.
+ void SetThreadTaskRunnerHandle();
+
// Invokes the actual run loop using the message pump.
void RunHandler();
@@ -475,7 +473,6 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate {
bool DoWork() override;
bool DoDelayedWork(TimeTicks* next_delayed_work_time) override;
bool DoIdleWork() override;
- TimeTicks GetNewlyAddedTaskDelay() override;
const Type type_;
@@ -511,7 +508,7 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate {
bool nestable_tasks_allowed_;
#if defined(OS_WIN)
- // Should be set to true before calling Windows APIs like TrackPopupMenu, etc
+ // Should be set to true before calling Windows APIs like TrackPopupMenu, etc.
// which enter a modal message loop.
bool os_modal_loop_;
#endif
@@ -532,8 +529,11 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate {
scoped_refptr<internal::IncomingTaskQueue> incoming_task_queue_;
- // The message loop proxy associated with this message loop.
- scoped_refptr<internal::MessageLoopProxyImpl> message_loop_proxy_;
+ // A task runner which we haven't bound to a thread yet.
+ scoped_refptr<internal::MessageLoopTaskRunner> unbound_task_runner_;
+
+ // The task runner associated with this message loop.
+ scoped_refptr<SingleThreadTaskRunner> task_runner_;
scoped_ptr<ThreadTaskRunnerHandle> thread_task_runner_handle_;
template <class T, class R> friend class base::subtle::DeleteHelperInternal;
@@ -604,8 +604,8 @@ class BASE_EXPORT MessageLoopForUI : public MessageLoop {
// 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);
+static_assert(sizeof(MessageLoop) == sizeof(MessageLoopForUI),
+ "MessageLoopForUI should not have extra member variables");
#endif // !defined(OS_NACL)
@@ -684,8 +684,8 @@ class BASE_EXPORT MessageLoopForIO : public MessageLoop {
// 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);
+static_assert(sizeof(MessageLoop) == sizeof(MessageLoopForIO),
+ "MessageLoopForIO should not have extra member variables");
} // namespace base
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 d5ecc041b6..0000000000
--- a/base/message_loop/message_loop_proxy.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.
-
-#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"
-
-// MessageLoopProxy is deprecated. Code should prefer to depend on TaskRunner
-// (or the various specializations) for passing task runners around, and should
-// use ThreadTaskRunnerHandle::Get() to get the thread's associated task runner.
-//
-// See http://crbug.com/391045 for more details.
-// Example for these changes:
-//
-// base::MessageLoopProxy::current() -> base::ThreadTaskRunnerHandle::Get()
-// scoped_refptr<base::MessageLoopProxy> ->
-// scoped_refptr<base::SingleThreadTaskRunner>
-// base::MessageLoopProxy -> base::SingleThreadTaskRunner
-
-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<MessageLoopProxy> current();
-
- protected:
- MessageLoopProxy();
- ~MessageLoopProxy() override;
-};
-
-} // namespace base
-
-#endif // BASE_MESSAGE_LOOP_MESSAGE_LOOP_PROXY_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 fa25371765..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:
- void SetUp() override {
- io_thread_.reset(new Thread("MessageLoopProxyImplTest_IO"));
- file_thread_.reset(new Thread("MessageLoopProxyImplTest_File"));
- io_thread_->Start();
- file_thread_->Start();
- }
-
- 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<Thread> io_thread_;
- scoped_ptr<Thread> 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<Thread> test_thread(
- new Thread("MessageLoopProxyImplTest_Dummy"));
- test_thread->Start();
- scoped_refptr<MessageLoopProxy> 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<MessageLoopProxy> message_loop_proxy;
- {
- scoped_ptr<Thread> 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_impl.cc b/base/message_loop/message_loop_task_runner.cc
index 580620d6bd..c9b5ffe3f7 100644
--- a/base/message_loop/message_loop_proxy_impl.cc
+++ b/base/message_loop/message_loop_task_runner.cc
@@ -2,29 +2,27 @@
// 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/message_loop/message_loop_task_runner.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(
+MessageLoopTaskRunner::MessageLoopTaskRunner(
scoped_refptr<IncomingTaskQueue> incoming_queue)
- : incoming_queue_(incoming_queue),
- valid_thread_id_(kInvalidThreadId) {
+ : incoming_queue_(incoming_queue), valid_thread_id_(kInvalidThreadId) {
}
-void MessageLoopProxyImpl::BindToCurrentThread() {
+void MessageLoopTaskRunner::BindToCurrentThread() {
AutoLock lock(valid_thread_id_lock_);
DCHECK_EQ(kInvalidThreadId, valid_thread_id_);
valid_thread_id_ = PlatformThread::CurrentId();
}
-bool MessageLoopProxyImpl::PostDelayedTask(
+bool MessageLoopTaskRunner::PostDelayedTask(
const tracked_objects::Location& from_here,
const base::Closure& task,
base::TimeDelta delay) {
@@ -32,7 +30,7 @@ bool MessageLoopProxyImpl::PostDelayedTask(
return incoming_queue_->AddToIncomingQueue(from_here, task, delay, true);
}
-bool MessageLoopProxyImpl::PostNonNestableDelayedTask(
+bool MessageLoopTaskRunner::PostNonNestableDelayedTask(
const tracked_objects::Location& from_here,
const base::Closure& task,
base::TimeDelta delay) {
@@ -40,22 +38,14 @@ bool MessageLoopProxyImpl::PostNonNestableDelayedTask(
return incoming_queue_->AddToIncomingQueue(from_here, task, delay, false);
}
-bool MessageLoopProxyImpl::RunsTasksOnCurrentThread() const {
+bool MessageLoopTaskRunner::RunsTasksOnCurrentThread() const {
AutoLock lock(valid_thread_id_lock_);
return valid_thread_id_ == PlatformThread::CurrentId();
}
-MessageLoopProxyImpl::~MessageLoopProxyImpl() {
+MessageLoopTaskRunner::~MessageLoopTaskRunner() {
}
} // namespace internal
-scoped_refptr<MessageLoopProxy>
-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_task_runner.h
index fa611c2908..5e70b128b2 100644
--- a/base/message_loop/message_loop_proxy_impl.h
+++ b/base/message_loop/message_loop_task_runner.h
@@ -2,13 +2,14 @@
// 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_
+#ifndef BASE_MESSAGE_LOOP_MESSAGE_LOOP_TASK_RUNNER_H_
+#define BASE_MESSAGE_LOOP_MESSAGE_LOOP_TASK_RUNNER_H_
#include "base/base_export.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop_proxy.h"
#include "base/pending_task.h"
+#include "base/single_thread_task_runner.h"
#include "base/synchronization/lock.h"
#include "base/threading/platform_thread.h"
@@ -17,18 +18,18 @@ 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 {
+// A stock implementation of SingleThreadTaskRunner that is created and managed
+// by a MessageLoop. For now a MessageLoopTaskRunner can only be created as
+// part of a MessageLoop.
+class BASE_EXPORT MessageLoopTaskRunner : public SingleThreadTaskRunner {
public:
- explicit MessageLoopProxyImpl(
+ explicit MessageLoopTaskRunner(
scoped_refptr<IncomingTaskQueue> incoming_queue);
- // Initialize this message loop proxy on the current thread.
+ // Initialize this message loop task runner on the current thread.
void BindToCurrentThread();
- // MessageLoopProxy implementation
+ // SingleThreadTaskRunner implementation
bool PostDelayedTask(const tracked_objects::Location& from_here,
const base::Closure& task,
base::TimeDelta delay) override;
@@ -38,10 +39,10 @@ class BASE_EXPORT MessageLoopProxyImpl : public MessageLoopProxy {
bool RunsTasksOnCurrentThread() const override;
private:
- friend class RefCountedThreadSafe<MessageLoopProxyImpl>;
- ~MessageLoopProxyImpl() override;
+ friend class RefCountedThreadSafe<MessageLoopTaskRunner>;
+ ~MessageLoopTaskRunner() override;
- // THe incoming queue receiving all posted tasks.
+ // The incoming queue receiving all posted tasks.
scoped_refptr<IncomingTaskQueue> incoming_queue_;
// ID of the thread |this| was created on. Could be accessed on multiple
@@ -49,10 +50,10 @@ class BASE_EXPORT MessageLoopProxyImpl : public MessageLoopProxy {
PlatformThreadId valid_thread_id_;
mutable Lock valid_thread_id_lock_;
- DISALLOW_COPY_AND_ASSIGN(MessageLoopProxyImpl);
+ DISALLOW_COPY_AND_ASSIGN(MessageLoopTaskRunner);
};
} // namespace internal
} // namespace base
-#endif // BASE_MESSAGE_LOOP_MESSAGE_LOOP_PROXY_IMPL_H_
+#endif // BASE_MESSAGE_LOOP_MESSAGE_LOOP_TASK_RUNNER_H_
diff --git a/base/message_loop/message_loop_proxy_unittest.cc b/base/message_loop/message_loop_task_runner_unittest.cc
index 17699be038..0442e7c2ae 100644
--- a/base/message_loop/message_loop_proxy_unittest.cc
+++ b/base/message_loop/message_loop_task_runner_unittest.cc
@@ -2,48 +2,45 @@
// 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/message_loop/message_loop_task_runner.h"
#include "base/atomic_sequence_num.h"
#include "base/bind.h"
-#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_task_runner.h"
#include "base/synchronization/waitable_event.h"
+#include "base/thread_task_runner_handle.h"
#include "base/threading/thread.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
namespace base {
-namespace {
-
-class MessageLoopProxyTest : public testing::Test {
+class MessageLoopTaskRunnerTest : public testing::Test {
public:
- MessageLoopProxyTest()
+ MessageLoopTaskRunnerTest()
: current_loop_(new MessageLoop()),
task_thread_("task_thread"),
- thread_sync_(true, false) {
- }
+ thread_sync_(true, false) {}
- void DeleteCurrentMessageLoop() {
- current_loop_.reset();
- }
+ void DeleteCurrentMessageLoop() { current_loop_.reset(); }
protected:
void SetUp() override {
// Use SetUp() instead of the constructor to avoid posting a task to a
- // partialy constructed object.
+ // partially 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)));
+ FROM_HERE, Bind(&MessageLoopTaskRunnerTest::BlockTaskThreadHelper,
+ Unretained(this)));
}
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
+ // fully before destruction because its tasks may still depend on the
// |thread_sync_| event.
thread_sync_.Signal();
task_thread_.Stop();
@@ -54,16 +51,14 @@ class MessageLoopProxyTest : public testing::Test {
// threading mistake sneaks into the PostTaskAndReplyRelay implementation.
class LoopRecorder : public RefCountedThreadSafe<LoopRecorder> {
public:
- LoopRecorder(MessageLoop** run_on, MessageLoop** deleted_on,
+ LoopRecorder(MessageLoop** run_on,
+ MessageLoop** deleted_on,
int* destruct_order)
: run_on_(run_on),
deleted_on_(deleted_on),
- destruct_order_(destruct_order) {
- }
+ destruct_order_(destruct_order) {}
- void RecordRun() {
- *run_on_ = MessageLoop::current();
- }
+ void RecordRun() { *run_on_ = MessageLoop::current(); }
private:
friend class RefCountedThreadSafe<LoopRecorder>;
@@ -86,13 +81,9 @@ class MessageLoopProxyTest : public testing::Test {
MessageLoop::current()->QuitWhenIdle();
}
- void UnblockTaskThread() {
- thread_sync_.Signal();
- }
+ void UnblockTaskThread() { thread_sync_.Signal(); }
- void BlockTaskThreadHelper() {
- thread_sync_.Wait();
- }
+ void BlockTaskThreadHelper() { thread_sync_.Wait(); }
static StaticAtomicSequenceNumber g_order;
@@ -103,9 +94,9 @@ class MessageLoopProxyTest : public testing::Test {
base::WaitableEvent thread_sync_;
};
-StaticAtomicSequenceNumber MessageLoopProxyTest::g_order;
+StaticAtomicSequenceNumber MessageLoopTaskRunnerTest::g_order;
-TEST_F(MessageLoopProxyTest, PostTaskAndReply_Basic) {
+TEST_F(MessageLoopTaskRunnerTest, PostTaskAndReply_Basic) {
MessageLoop* task_run_on = NULL;
MessageLoop* task_deleted_on = NULL;
int task_delete_order = -1;
@@ -118,9 +109,8 @@ TEST_F(MessageLoopProxyTest, PostTaskAndReply_Basic) {
scoped_refptr<LoopRecorder> 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),
+ ASSERT_TRUE(task_thread_.task_runner()->PostTaskAndReply(
+ FROM_HERE, Bind(&RecordLoop, task_recoder),
Bind(&RecordLoopAndQuit, reply_recoder)));
// Die if base::Bind doesn't retain a reference to the recorders.
@@ -139,7 +129,7 @@ TEST_F(MessageLoopProxyTest, PostTaskAndReply_Basic) {
EXPECT_LT(task_delete_order, reply_delete_order);
}
-TEST_F(MessageLoopProxyTest, PostTaskAndReplyOnDeletedThreadDoesNotLeak) {
+TEST_F(MessageLoopTaskRunnerTest, PostTaskAndReplyOnDeletedThreadDoesNotLeak) {
MessageLoop* task_run_on = NULL;
MessageLoop* task_deleted_on = NULL;
int task_delete_order = -1;
@@ -152,16 +142,15 @@ TEST_F(MessageLoopProxyTest, PostTaskAndReplyOnDeletedThreadDoesNotLeak) {
scoped_refptr<LoopRecorder> reply_recoder =
new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order);
- // Grab a MessageLoopProxy to a dead MessageLoop.
- scoped_refptr<MessageLoopProxy> task_loop_proxy =
- task_thread_.message_loop_proxy();
+ // Grab a task runner to a dead MessageLoop.
+ scoped_refptr<SingleThreadTaskRunner> task_runner =
+ task_thread_.task_runner();
UnblockTaskThread();
task_thread_.Stop();
- ASSERT_FALSE(task_loop_proxy->PostTaskAndReply(
- FROM_HERE,
- Bind(&RecordLoop, task_recoder),
- Bind(&RecordLoopAndQuit, reply_recoder)));
+ ASSERT_FALSE(
+ task_runner->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.
@@ -174,7 +163,7 @@ TEST_F(MessageLoopProxyTest, PostTaskAndReplyOnDeletedThreadDoesNotLeak) {
EXPECT_FALSE(reply_run_on);
}
-TEST_F(MessageLoopProxyTest, PostTaskAndReply_SameLoop) {
+TEST_F(MessageLoopTaskRunnerTest, PostTaskAndReply_SameLoop) {
MessageLoop* task_run_on = NULL;
MessageLoop* task_deleted_on = NULL;
int task_delete_order = -1;
@@ -188,9 +177,8 @@ TEST_F(MessageLoopProxyTest, PostTaskAndReply_SameLoop) {
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),
+ ASSERT_TRUE(current_loop_->task_runner()->PostTaskAndReply(
+ FROM_HERE, Bind(&RecordLoop, task_recoder),
Bind(&RecordLoopAndQuit, reply_recoder)));
// Die if base::Bind doesn't retain a reference to the recorders.
@@ -208,7 +196,7 @@ TEST_F(MessageLoopProxyTest, PostTaskAndReply_SameLoop) {
EXPECT_LT(task_delete_order, reply_delete_order);
}
-TEST_F(MessageLoopProxyTest, PostTaskAndReply_DeadReplyLoopDoesNotDelete) {
+TEST_F(MessageLoopTaskRunnerTest, PostTaskAndReply_DeadReplyLoopDoesNotDelete) {
MessageLoop* task_run_on = NULL;
MessageLoop* task_deleted_on = NULL;
int task_delete_order = -1;
@@ -222,9 +210,8 @@ TEST_F(MessageLoopProxyTest, PostTaskAndReply_DeadReplyLoopDoesNotDelete) {
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),
+ task_thread_.task_runner()->PostTaskAndReply(
+ FROM_HERE, Bind(&RecordLoop, task_recoder),
Bind(&RecordLoopAndQuit, reply_recoder));
// Die if base::Bind doesn't retain a reference to the recorders.
@@ -254,10 +241,115 @@ TEST_F(MessageLoopProxyTest, PostTaskAndReply_DeadReplyLoopDoesNotDelete) {
// 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
+ // already been deleted in order to perform this test. See
// http://crbug.com/86301.
}
-} // namespace
+class MessageLoopTaskRunnerThreadingTest : 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_->task_runner()->BelongsToCurrentThread());
+ ASSERT_EQ(io_thread_->task_runner(), ThreadTaskRunnerHandle::Get());
+ }
+
+ void AssertOnFileThread() const {
+ ASSERT_TRUE(file_thread_->task_runner()->BelongsToCurrentThread());
+ ASSERT_EQ(file_thread_->task_runner(), ThreadTaskRunnerHandle::Get());
+ }
+
+ protected:
+ void SetUp() override {
+ io_thread_.reset(new Thread("MessageLoopTaskRunnerThreadingTest_IO"));
+ file_thread_.reset(new Thread("MessageLoopTaskRunnerThreadingTest_File"));
+ io_thread_->Start();
+ file_thread_->Start();
+ }
+
+ void TearDown() override {
+ io_thread_->Stop();
+ file_thread_->Stop();
+ }
+
+ static void BasicFunction(MessageLoopTaskRunnerThreadingTest* test) {
+ test->AssertOnFileThread();
+ test->Quit();
+ }
+
+ static void AssertNotRun() { FAIL() << "Callback Should not get executed."; }
+
+ class DeletedOnFile {
+ public:
+ explicit DeletedOnFile(MessageLoopTaskRunnerThreadingTest* test)
+ : test_(test) {}
+
+ ~DeletedOnFile() {
+ test_->AssertOnFileThread();
+ test_->Quit();
+ }
+
+ private:
+ MessageLoopTaskRunnerThreadingTest* test_;
+ };
+
+ scoped_ptr<Thread> io_thread_;
+ scoped_ptr<Thread> file_thread_;
+
+ private:
+ mutable MessageLoop loop_;
+};
+
+TEST_F(MessageLoopTaskRunnerThreadingTest, Release) {
+ EXPECT_TRUE(io_thread_->task_runner()->ReleaseSoon(FROM_HERE, this));
+ MessageLoop::current()->Run();
+}
+
+TEST_F(MessageLoopTaskRunnerThreadingTest, Delete) {
+ DeletedOnFile* deleted_on_file = new DeletedOnFile(this);
+ EXPECT_TRUE(
+ file_thread_->task_runner()->DeleteSoon(FROM_HERE, deleted_on_file));
+ MessageLoop::current()->Run();
+}
+
+TEST_F(MessageLoopTaskRunnerThreadingTest, PostTask) {
+ EXPECT_TRUE(file_thread_->task_runner()->PostTask(
+ FROM_HERE, Bind(&MessageLoopTaskRunnerThreadingTest::BasicFunction,
+ Unretained(this))));
+ MessageLoop::current()->Run();
+}
+
+TEST_F(MessageLoopTaskRunnerThreadingTest, PostTaskAfterThreadExits) {
+ scoped_ptr<Thread> test_thread(
+ new Thread("MessageLoopTaskRunnerThreadingTest_Dummy"));
+ test_thread->Start();
+ scoped_refptr<SingleThreadTaskRunner> task_runner =
+ test_thread->task_runner();
+ test_thread->Stop();
+
+ bool ret = task_runner->PostTask(
+ FROM_HERE, Bind(&MessageLoopTaskRunnerThreadingTest::AssertNotRun));
+ EXPECT_FALSE(ret);
+}
+
+TEST_F(MessageLoopTaskRunnerThreadingTest, PostTaskAfterThreadIsDeleted) {
+ scoped_refptr<SingleThreadTaskRunner> task_runner;
+ {
+ scoped_ptr<Thread> test_thread(
+ new Thread("MessageLoopTaskRunnerThreadingTest_Dummy"));
+ test_thread->Start();
+ task_runner = test_thread->task_runner();
+ }
+ bool ret = task_runner->PostTask(
+ FROM_HERE, Bind(&MessageLoopTaskRunnerThreadingTest::AssertNotRun));
+ EXPECT_FALSE(ret);
+}
} // namespace base
diff --git a/base/message_loop/message_loop_test.cc b/base/message_loop/message_loop_test.cc
index eca6c8f245..ac50d64848 100644
--- a/base/message_loop/message_loop_test.cc
+++ b/base/message_loop/message_loop_test.cc
@@ -4,7 +4,12 @@
#include "base/message_loop/message_loop_test.h"
+#include <stddef.h>
+
+#include <utility>
+
#include "base/bind.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/run_loop.h"
#include "base/synchronization/waitable_event.h"
@@ -87,7 +92,7 @@ void RecordRunTimeFunc(Time* run_time, int* quit_counter) {
void RunTest_PostTask(MessagePumpFactory factory) {
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
// Add tests to message loop
scoped_refptr<Foo> foo(new Foo());
std::string a("a"), b("b"), c("c"), d("d");
@@ -104,8 +109,9 @@ void RunTest_PostTask(MessagePumpFactory factory) {
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())));
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ Bind(&MessageLoop::QuitWhenIdle, Unretained(MessageLoop::current())));
// Now kick things off
MessageLoop::current()->Run();
@@ -116,7 +122,7 @@ void RunTest_PostTask(MessagePumpFactory factory) {
void RunTest_PostDelayedTask_Basic(MessagePumpFactory factory) {
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
// Test that PostDelayedTask results in a delayed task.
@@ -139,7 +145,7 @@ void RunTest_PostDelayedTask_Basic(MessagePumpFactory factory) {
void RunTest_PostDelayedTask_InDelayOrder(MessagePumpFactory factory) {
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
// Test that two tasks with different delays run in the right order.
int num_tasks = 2;
@@ -164,7 +170,7 @@ void RunTest_PostDelayedTask_InDelayOrder(MessagePumpFactory factory) {
void RunTest_PostDelayedTask_InPostOrder(MessagePumpFactory factory) {
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
// Test that two tasks with the same delay run in the order in which they
// were posted.
@@ -194,7 +200,7 @@ void RunTest_PostDelayedTask_InPostOrder(MessagePumpFactory factory) {
void RunTest_PostDelayedTask_InPostOrder_2(MessagePumpFactory factory) {
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
// Test that a delayed task still runs after a normal tasks even if the
// normal tasks take a long time to run.
@@ -221,7 +227,7 @@ void RunTest_PostDelayedTask_InPostOrder_2(MessagePumpFactory factory) {
void RunTest_PostDelayedTask_InPostOrder_3(MessagePumpFactory factory) {
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
// 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
@@ -249,7 +255,7 @@ void RunTest_PostDelayedTask_InPostOrder_3(MessagePumpFactory factory) {
void RunTest_PostDelayedTask_SharedTimer(MessagePumpFactory factory) {
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
// 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.
@@ -316,7 +322,7 @@ void RunTest_EnsureDeletion(MessagePumpFactory factory) {
bool b_was_deleted = false;
{
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
loop.PostTask(
FROM_HERE, Bind(&RecordDeletionProbe::Run,
new RecordDeletionProbe(NULL, &a_was_deleted)));
@@ -336,7 +342,7 @@ void RunTest_EnsureDeletion_Chain(MessagePumpFactory factory) {
bool c_was_deleted = false;
{
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
// 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);
@@ -363,7 +369,7 @@ void NestingFunc(int* depth) {
void RunTest_Nesting(MessagePumpFactory factory) {
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
int depth = 100;
MessageLoop::current()->PostTask(FROM_HERE,
@@ -471,7 +477,7 @@ void QuitFunc(TaskList* order, int cookie) {
}
void RunTest_RecursiveDenial1(MessagePumpFactory factory) {
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
EXPECT_TRUE(MessageLoop::current()->NestableTasksAllowed());
TaskList order;
@@ -518,7 +524,7 @@ void OrderedFunc(TaskList* order, int cookie) {
void RunTest_RecursiveDenial3(MessagePumpFactory factory) {
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
EXPECT_TRUE(MessageLoop::current()->NestableTasksAllowed());
TaskList order;
@@ -559,7 +565,7 @@ void RunTest_RecursiveDenial3(MessagePumpFactory factory) {
void RunTest_RecursiveSupport1(MessagePumpFactory factory) {
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
TaskList order;
MessageLoop::current()->PostTask(
@@ -592,7 +598,7 @@ void RunTest_RecursiveSupport1(MessagePumpFactory factory) {
// Tests that non nestable tasks run in FIFO if there are no nested loops.
void RunTest_NonNestableWithNoNesting(MessagePumpFactory factory) {
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
TaskList order;
@@ -634,7 +640,7 @@ void SleepFunc(TaskList* order, int cookie, TimeDelta delay) {
void RunTest_NonNestableInNestedLoop(MessagePumpFactory factory,
bool use_delayed) {
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
TaskList order;
@@ -702,7 +708,7 @@ void FuncThatQuitsNow() {
// Tests RunLoopQuit only quits the corresponding MessageLoop::Run.
void RunTest_QuitNow(MessagePumpFactory factory) {
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
TaskList order;
@@ -737,7 +743,7 @@ void RunTest_QuitNow(MessagePumpFactory factory) {
// Tests RunLoopQuit only quits the corresponding MessageLoop::Run.
void RunTest_RunLoopQuitTop(MessagePumpFactory factory) {
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
TaskList order;
@@ -767,7 +773,7 @@ void RunTest_RunLoopQuitTop(MessagePumpFactory factory) {
// Tests RunLoopQuit only quits the corresponding MessageLoop::Run.
void RunTest_RunLoopQuitNested(MessagePumpFactory factory) {
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
TaskList order;
@@ -797,7 +803,7 @@ void RunTest_RunLoopQuitNested(MessagePumpFactory factory) {
// Tests RunLoopQuit only quits the corresponding MessageLoop::Run.
void RunTest_RunLoopQuitBogus(MessagePumpFactory factory) {
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
TaskList order;
@@ -830,7 +836,7 @@ void RunTest_RunLoopQuitBogus(MessagePumpFactory factory) {
// Tests RunLoopQuit only quits the corresponding MessageLoop::Run.
void RunTest_RunLoopQuitDeep(MessagePumpFactory factory) {
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
TaskList order;
@@ -899,7 +905,7 @@ void RunTest_RunLoopQuitDeep(MessagePumpFactory factory) {
// Tests RunLoopQuit works before RunWithID.
void RunTest_RunLoopQuitOrderBefore(MessagePumpFactory factory) {
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
TaskList order;
@@ -920,7 +926,7 @@ void RunTest_RunLoopQuitOrderBefore(MessagePumpFactory factory) {
// Tests RunLoopQuit works during RunWithID.
void RunTest_RunLoopQuitOrderDuring(MessagePumpFactory factory) {
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
TaskList order;
@@ -947,7 +953,7 @@ void RunTest_RunLoopQuitOrderDuring(MessagePumpFactory factory) {
// Tests RunLoopQuit works after RunWithID.
void RunTest_RunLoopQuitOrderAfter(MessagePumpFactory factory) {
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
TaskList order;
@@ -1005,7 +1011,7 @@ void PostNTasksThenQuit(int posts_remaining) {
void RunTest_RecursivePosts(MessagePumpFactory factory) {
const int kNumTimes = 1 << 17;
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
loop.PostTask(FROM_HERE, Bind(&PostNTasksThenQuit, kNumTimes));
loop.Run();
}
diff --git a/base/message_loop/message_loop_unittest.cc b/base/message_loop/message_loop_unittest.cc
index ddde6bb170..1a3a925700 100644
--- a/base/message_loop/message_loop_unittest.cc
+++ b/base/message_loop/message_loop_unittest.cc
@@ -2,23 +2,28 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stddef.h>
+#include <stdint.h>
+
#include <vector>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/compiler_specific.h"
#include "base/logging.h"
+#include "base/macros.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/message_loop/message_loop_test.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/test/test_simple_task_runner.h"
#include "base/thread_task_runner_handle.h"
#include "base/threading/platform_thread.h"
#include "base/threading/thread.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#if defined(OS_WIN)
@@ -119,7 +124,7 @@ void RunTest_PostDelayedTask_SharedTimer_SubPump() {
Bind(&RecordRunTimeFunc, &run_time, &num_tasks),
TimeDelta::FromSeconds(1000));
- // This slightly delayed task should run from within SubPumpFunc).
+ // This slightly delayed task should run from within SubPumpFunc.
loop.PostDelayedTask(
FROM_HERE,
Bind(&PostQuitMessage, 0),
@@ -336,7 +341,7 @@ void RunTest_RecursiveDenial2(MessageLoop::Type message_loop_type) {
WaitForSingleObject(event.Get(), INFINITE);
MessageLoop::current()->Run();
- ASSERT_EQ(order.Size(), 17);
+ ASSERT_EQ(17u, 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(MESSAGEBOX, 2, true));
@@ -380,7 +385,7 @@ void RunTest_RecursiveSupport2(MessageLoop::Type message_loop_type) {
WaitForSingleObject(event.Get(), INFINITE);
MessageLoop::current()->Run();
- ASSERT_EQ(order.Size(), 18);
+ ASSERT_EQ(18u, 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(MESSAGEBOX, 2, true));
@@ -522,7 +527,7 @@ void TestIOHandler::Init() {
DWORD read;
EXPECT_FALSE(ReadFile(file_.Get(), buffer_, size(), &read, context()));
- EXPECT_EQ(ERROR_IO_PENDING, GetLastError());
+ EXPECT_EQ(static_cast<DWORD>(ERROR_IO_PENDING), GetLastError());
if (wait_)
WaitForIO();
}
@@ -600,7 +605,7 @@ void RunTest_WaitForIO() {
TestIOHandler handler2(kPipeName2, callback2_called.Get(), true);
thread_loop->PostTask(FROM_HERE, Bind(&TestIOHandler::Init,
Unretained(&handler1)));
- // TODO(ajwong): Do we really need such long Sleeps in ths function?
+ // TODO(ajwong): Do we really need such long Sleeps in this function?
// Make sure the thread runs and sleeps for lack of work.
TimeDelta delay = TimeDelta::FromMilliseconds(100);
PlatformThread::Sleep(delay);
@@ -615,8 +620,9 @@ void RunTest_WaitForIO() {
DWORD written;
EXPECT_TRUE(WriteFile(server1.Get(), buffer, sizeof(buffer), &written, NULL));
PlatformThread::Sleep(2 * delay);
- EXPECT_EQ(WAIT_TIMEOUT, WaitForSingleObject(callback1_called.Get(), 0)) <<
- "handler1 has not been called";
+ EXPECT_EQ(static_cast<DWORD>(WAIT_TIMEOUT),
+ WaitForSingleObject(callback1_called.Get(), 0))
+ << "handler1 has not been called";
EXPECT_TRUE(WriteFile(server2.Get(), buffer, sizeof(buffer), &written, NULL));
@@ -645,7 +651,7 @@ TEST(MessageLoopTest, PostDelayedTask_SharedTimer_SubPump) {
RunTest_PostDelayedTask_SharedTimer_SubPump();
}
-// This test occasionally hangs http://crbug.com/44567
+// This test occasionally hangs. See http://crbug.com/44567.
TEST(MessageLoopTest, DISABLED_RecursiveDenial2) {
RunTest_RecursiveDenial2(MessageLoop::TYPE_DEFAULT);
RunTest_RecursiveDenial2(MessageLoop::TYPE_UI);
@@ -653,7 +659,7 @@ TEST(MessageLoopTest, DISABLED_RecursiveDenial2) {
}
TEST(MessageLoopTest, RecursiveSupport2) {
- // This test requires a UI loop
+ // This test requires a UI loop.
RunTest_RecursiveSupport2(MessageLoop::TYPE_UI);
}
#endif // defined(OS_WIN)
@@ -907,8 +913,9 @@ TEST(MessageLoopTest, ThreadMainTaskRunner) {
&Foo::Test1ConstRef, foo.get(), a));
// Post quit task;
- MessageLoop::current()->PostTask(FROM_HERE, Bind(
- &MessageLoop::Quit, Unretained(MessageLoop::current())));
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ Bind(&MessageLoop::QuitWhenIdle, Unretained(MessageLoop::current())));
// Now kick things off
MessageLoop::current()->Run();
@@ -983,7 +990,7 @@ LRESULT CALLBACK TestWndProcThunk(HWND hwnd, UINT message,
break;
}
EXPECT_TRUE(did_run);
- MessageLoop::current()->Quit();
+ MessageLoop::current()->QuitWhenIdle();
break;
}
return 0;
@@ -1012,4 +1019,37 @@ TEST(MessageLoopTest, AlwaysHaveUserMessageWhenNesting) {
}
#endif // defined(OS_WIN)
+TEST(MessageLoopTest, SetTaskRunner) {
+ MessageLoop loop;
+ scoped_refptr<SingleThreadTaskRunner> new_runner(new TestSimpleTaskRunner());
+
+ loop.SetTaskRunner(new_runner);
+ EXPECT_EQ(new_runner, loop.task_runner());
+ EXPECT_EQ(new_runner, ThreadTaskRunnerHandle::Get());
+}
+
+TEST(MessageLoopTest, OriginalRunnerWorks) {
+ MessageLoop loop;
+ scoped_refptr<SingleThreadTaskRunner> new_runner(new TestSimpleTaskRunner());
+ scoped_refptr<SingleThreadTaskRunner> original_runner(loop.task_runner());
+ loop.SetTaskRunner(new_runner);
+
+ scoped_refptr<Foo> foo(new Foo());
+ original_runner->PostTask(FROM_HERE,
+ Bind(&Foo::Test1ConstRef, foo.get(), "a"));
+ loop.RunUntilIdle();
+ EXPECT_EQ(1, foo->test_count());
+}
+
+TEST(MessageLoopTest, DeleteUnboundLoop) {
+ // It should be possible to delete an unbound message loop on a thread which
+ // already has another active loop. This happens when thread creation fails.
+ MessageLoop loop;
+ scoped_ptr<MessageLoop> unbound_loop(MessageLoop::CreateUnbound(
+ MessageLoop::TYPE_DEFAULT, MessageLoop::MessagePumpFactoryCallback()));
+ unbound_loop.reset();
+ EXPECT_EQ(&loop, MessageLoop::current());
+ EXPECT_EQ(loop.task_runner(), ThreadTaskRunnerHandle::Get());
+}
+
} // namespace base
diff --git a/base/message_loop/message_pump.h b/base/message_loop/message_pump.h
index 77a49cee49..c53be80410 100644
--- a/base/message_loop/message_pump.h
+++ b/base/message_loop/message_pump.h
@@ -6,7 +6,6 @@
#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_H_
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/message_loop/timer_slack.h"
#include "base/threading/non_thread_safe.h"
@@ -42,9 +41,6 @@ class BASE_EXPORT MessagePump : public NonThreadSafe {
// Returns true to indicate that idle work was done. Returning false means
// the pump will now wait.
virtual bool DoIdleWork() = 0;
-
- // Returns the delay for the newly added task.
- virtual TimeTicks GetNewlyAddedTaskDelay() = 0;
};
MessagePump();
diff --git a/base/message_loop/message_pump_default.cc b/base/message_loop/message_pump_default.cc
index daa80d8532..ed15395d56 100644
--- a/base/message_loop/message_pump_default.cc
+++ b/base/message_loop/message_pump_default.cc
@@ -4,10 +4,9 @@
#include "base/message_loop/message_pump_default.h"
-#include <algorithm>
-
#include "base/logging.h"
#include "base/threading/thread_restrictions.h"
+#include "build/build_config.h"
#if defined(OS_MACOSX)
#include "base/mac/scoped_nsautorelease_pool.h"
@@ -54,13 +53,6 @@ void MessagePumpDefault::Run(Delegate* delegate) {
event_.Wait();
} else {
TimeDelta delay = delayed_work_time_ - TimeTicks::Now();
-#if defined(OS_WIN)
- // If the delay is greater than zero and under 1 ms we need to round up to
- // 1 ms or else we will end up spinning until it counts down to zero
- // because sub-ms waits aren't supported on Windows.
- if (delay > TimeDelta())
- delay = std::max(delay, TimeDelta::FromMilliseconds(1));
-#endif
if (delay > TimeDelta()) {
event_.TimedWait(delay);
} else {
diff --git a/base/message_loop/message_pump_default.h b/base/message_loop/message_pump_default.h
index 8aeaa62fcd..4cd7cd17d5 100644
--- a/base/message_loop/message_pump_default.h
+++ b/base/message_loop/message_pump_default.h
@@ -6,6 +6,7 @@
#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_DEFAULT_H_
#include "base/base_export.h"
+#include "base/macros.h"
#include "base/message_loop/message_pump.h"
#include "base/synchronization/waitable_event.h"
#include "base/time/time.h"
diff --git a/base/message_loop/message_pump_libevent.cc b/base/message_loop/message_pump_libevent.cc
index cb703cee0e..1df9819720 100644
--- a/base/message_loop/message_pump_libevent.cc
+++ b/base/message_loop/message_pump_libevent.cc
@@ -5,24 +5,26 @@
#include "base/message_loop/message_pump_libevent.h"
#include <errno.h>
-#include <fcntl.h>
#include <unistd.h>
#include "base/auto_reset.h"
#include "base/compiler_specific.h"
+#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/observer_list.h"
#include "base/posix/eintr_wrapper.h"
+#if !defined(__ANDROID__) && !defined(__ANDROID_HOST__)
+#include "base/third_party/libevent/event.h"
+#endif
#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
+#include "build/build_config.h"
#if defined(__ANDROID__) || defined(__ANDROID_HOST__)
#include <event2/event.h>
#include <event2/event_compat.h>
#include <event2/event_struct.h>
-#else
-#include "third_party/libevent/event.h"
#endif
#if defined(OS_MACOSX)
@@ -49,26 +51,21 @@
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) {
+ was_destroyed_(NULL) {
}
MessagePumpLibevent::FileDescriptorWatcher::~FileDescriptorWatcher() {
if (event_) {
StopWatchingFileDescriptor();
}
+ if (was_destroyed_) {
+ DCHECK(!*was_destroyed_);
+ *was_destroyed_ = true;
+ }
}
bool MessagePumpLibevent::FileDescriptorWatcher::StopWatchingFileDescriptor() {
@@ -325,11 +322,11 @@ bool MessagePumpLibevent::Init() {
DLOG(ERROR) << "pipe() failed, errno: " << errno;
return false;
}
- if (SetNonBlocking(fds[0])) {
+ if (!SetNonBlocking(fds[0])) {
DLOG(ERROR) << "SetNonBlocking for pipe fd[0] failed, errno: " << errno;
return false;
}
- if (SetNonBlocking(fds[1])) {
+ if (!SetNonBlocking(fds[1])) {
DLOG(ERROR) << "SetNonBlocking for pipe fd[1] failed, errno: " << errno;
return false;
}
@@ -347,23 +344,31 @@ bool MessagePumpLibevent::Init() {
}
// static
-void MessagePumpLibevent::OnLibeventNotification(int fd, short flags,
+void MessagePumpLibevent::OnLibeventNotification(int fd,
+ short flags,
void* context) {
- WeakPtr<FileDescriptorWatcher> controller =
- static_cast<FileDescriptorWatcher*>(context)->weak_factory_.GetWeakPtr();
- DCHECK(controller.get());
+ FileDescriptorWatcher* controller =
+ static_cast<FileDescriptorWatcher*>(context);
+ DCHECK(controller);
TRACE_EVENT1("toplevel", "MessagePumpLibevent::OnLibeventNotification",
"fd", fd);
MessagePumpLibevent* pump = controller->pump();
pump->processed_io_events_ = true;
- if (flags & EV_WRITE) {
+ if ((flags & (EV_READ | EV_WRITE)) == (EV_READ | EV_WRITE)) {
+ // Both callbacks will be called. It is necessary to check that |controller|
+ // is not destroyed.
+ bool controller_was_destroyed = false;
+ controller->was_destroyed_ = &controller_was_destroyed;
controller->OnFileCanWriteWithoutBlocking(fd, pump);
- }
- // Check |controller| in case it's been deleted in
- // controller->OnFileCanWriteWithoutBlocking().
- if (controller.get() && flags & EV_READ) {
+ if (!controller_was_destroyed)
+ controller->OnFileCanReadWithoutBlocking(fd, pump);
+ if (!controller_was_destroyed)
+ controller->was_destroyed_ = nullptr;
+ } else if (flags & EV_WRITE) {
+ controller->OnFileCanWriteWithoutBlocking(fd, pump);
+ } else if (flags & EV_READ) {
controller->OnFileCanReadWithoutBlocking(fd, pump);
}
}
diff --git a/base/message_loop/message_pump_libevent.h b/base/message_loop/message_pump_libevent.h
index 3f5ad51dae..4d2f4f7037 100644
--- a/base/message_loop/message_pump_libevent.h
+++ b/base/message_loop/message_pump_libevent.h
@@ -5,9 +5,8 @@
#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/macros.h"
#include "base/message_loop/message_pump.h"
#include "base/observer_list.h"
#include "base/threading/thread_checker.h"
@@ -86,7 +85,9 @@ class BASE_EXPORT MessagePumpLibevent : public MessagePump {
event* event_;
MessagePumpLibevent* pump_;
Watcher* watcher_;
- WeakPtrFactory<FileDescriptorWatcher> weak_factory_;
+ // If this pointer is non-NULL, the pointee is set to true in the
+ // destructor.
+ bool* was_destroyed_;
DISALLOW_COPY_AND_ASSIGN(FileDescriptorWatcher);
};
diff --git a/base/message_loop/message_pump_mac.h b/base/message_loop/message_pump_mac.h
index c853202084..14b8377b90 100644
--- a/base/message_loop/message_pump_mac.h
+++ b/base/message_loop/message_pump_mac.h
@@ -22,7 +22,7 @@
//
// 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.
+// any other thread, one of the other concrete subclasses is preferable.
// MessagePumpMac::Create is defined, which returns a new NSApplication-based
// or NSRunLoop-based MessagePump subclass depending on which thread it is
// called on.
@@ -32,12 +32,13 @@
#include "base/message_loop/message_pump.h"
-#include "base/basictypes.h"
#include <CoreFoundation/CoreFoundation.h>
+#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop/timer_slack.h"
+#include "build/build_config.h"
#if defined(__OBJC__)
#if defined(OS_IOS)
diff --git a/base/message_loop/message_pump_mac.mm b/base/message_loop/message_pump_mac.mm
index 95d1c5f1fc..9f2f675379 100644
--- a/base/message_loop/message_pump_mac.mm
+++ b/base/message_loop/message_pump_mac.mm
@@ -10,10 +10,13 @@
#include <limits>
#include "base/logging.h"
+#include "base/mac/call_with_eh_frame.h"
#include "base/mac/scoped_cftyperef.h"
+#include "base/macros.h"
#include "base/message_loop/timer_slack.h"
#include "base/run_loop.h"
#include "base/time/time.h"
+#include "build/build_config.h"
#if !defined(OS_IOS)
#import <AppKit/AppKit.h>
@@ -301,7 +304,9 @@ void MessagePumpCFRunLoopBase::RunDelayedWorkTimer(
// static
void MessagePumpCFRunLoopBase::RunWorkSource(void* info) {
MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
- self->RunWork();
+ base::mac::CallWithEHFrame(^{
+ self->RunWork();
+ });
}
// Called by MessagePumpCFRunLoopBase::RunWorkSource.
@@ -360,7 +365,9 @@ bool MessagePumpCFRunLoopBase::RunWork() {
// static
void MessagePumpCFRunLoopBase::RunIdleWorkSource(void* info) {
MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
- self->RunIdleWork();
+ base::mac::CallWithEHFrame(^{
+ self->RunIdleWork();
+ });
}
// Called by MessagePumpCFRunLoopBase::RunIdleWorkSource.
@@ -394,7 +401,9 @@ bool MessagePumpCFRunLoopBase::RunIdleWork() {
// static
void MessagePumpCFRunLoopBase::RunNestingDeferredWorkSource(void* info) {
MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
- self->RunNestingDeferredWork();
+ base::mac::CallWithEHFrame(^{
+ self->RunNestingDeferredWork();
+ });
}
// Called by MessagePumpCFRunLoopBase::RunNestingDeferredWorkSource.
@@ -442,15 +451,16 @@ void MessagePumpCFRunLoopBase::PreWaitObserver(
CFRunLoopActivity /* activity */,
void* info) {
MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(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();
+ base::mac::CallWithEHFrame(^{
+ // 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.
@@ -466,7 +476,9 @@ void MessagePumpCFRunLoopBase::PreSourceObserver(
// 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();
+ base::mac::CallWithEHFrame(^{
+ self->MaybeScheduleNestingDeferredWork();
+ });
}
// Called from the run loop.
@@ -502,7 +514,9 @@ void MessagePumpCFRunLoopBase::EnterExitObserver(
// 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();
+ base::mac::CallWithEHFrame(^{
+ self->MaybeScheduleNestingDeferredWork();
+ });
--self->nesting_level_;
break;
@@ -510,7 +524,9 @@ void MessagePumpCFRunLoopBase::EnterExitObserver(
break;
}
- self->EnterExitRunLoop(activity);
+ base::mac::CallWithEHFrame(^{
+ self->EnterExitRunLoop(activity);
+ });
}
// Called by MessagePumpCFRunLoopBase::EnterExitRunLoop. The default
diff --git a/base/metrics/BUILD.gn b/base/metrics/BUILD.gn
deleted file mode 100644
index 845ac4f79c..0000000000
--- a/base/metrics/BUILD.gn
+++ /dev/null
@@ -1,49 +0,0 @@
-# Copyright (c) 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-source_set("metrics") {
- sources = [
- "bucket_ranges.cc",
- "bucket_ranges.h",
- "field_trial.cc",
- "field_trial.h",
- "histogram.cc",
- "histogram.h",
- "histogram_base.cc",
- "histogram_base.h",
- "histogram_delta_serialization.cc",
- "histogram_delta_serialization.h",
- "histogram_flattener.h",
- "histogram_macros.h",
- "histogram_samples.cc",
- "histogram_samples.h",
- "histogram_snapshot_manager.cc",
- "histogram_snapshot_manager.h",
- "sample_map.cc",
- "sample_map.h",
- "sample_vector.cc",
- "sample_vector.h",
- "sparse_histogram.cc",
- "sparse_histogram.h",
- "statistics_recorder.cc",
- "statistics_recorder.h",
- "user_metrics.cc",
- "user_metrics.h",
- "user_metrics_action.h",
- ]
-
- if (is_nacl) {
- sources -= [ "field_trial.cc" ]
- }
-
- configs += [ "//base:base_implementation" ]
-
- deps = [
- "//base/debug",
- "//base/json",
- "//base/memory",
- ]
-
- visibility = [ "//base/*" ]
-}
diff --git a/base/metrics/bucket_ranges.cc b/base/metrics/bucket_ranges.cc
index 949c813e46..084cdd3293 100644
--- a/base/metrics/bucket_ranges.cc
+++ b/base/metrics/bucket_ranges.cc
@@ -11,62 +11,70 @@
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,
+const uint32_t 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) {
+// to keep the quotient in a uint32_t. 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_t Crc32(uint32_t sum, HistogramBase::Sample value) {
// TODO(jar): Switch to false and watch stats.
const bool kUseRealCrc = true;
@@ -84,12 +92,12 @@ static uint32 Crc32(uint32 sum, HistogramBase::Sample value) {
// 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];
+ uint16_t 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<uint32>(converter.ints[1]) << 11);
+ sum = (sum << 16) ^ sum ^ (static_cast<uint32_t>(converter.ints[1]) << 11);
sum += sum >> 11;
}
return sum;
@@ -107,9 +115,9 @@ void BucketRanges::set_range(size_t i, HistogramBase::Sample value) {
ranges_[i] = value;
}
-uint32 BucketRanges::CalculateChecksum() const {
+uint32_t BucketRanges::CalculateChecksum() const {
// Seed checksum.
- uint32 checksum = static_cast<uint32>(ranges_.size());
+ uint32_t checksum = static_cast<uint32_t>(ranges_.size());
for (size_t index = 0; index < ranges_.size(); ++index)
checksum = Crc32(checksum, ranges_[index]);
diff --git a/base/metrics/bucket_ranges.h b/base/metrics/bucket_ranges.h
index fe1152f5db..c356195ba7 100644
--- a/base/metrics/bucket_ranges.h
+++ b/base/metrics/bucket_ranges.h
@@ -17,11 +17,15 @@
#ifndef BASE_METRICS_BUCKET_RANGES_H_
#define BASE_METRICS_BUCKET_RANGES_H_
+#include <stddef.h>
+#include <stdint.h>
+
#include <vector>
+#include <limits.h>
+
#include "base/base_export.h"
-#include "base/basictypes.h"
-#include "base/gtest_prod_util.h"
+#include "base/macros.h"
#include "base/metrics/histogram_base.h"
namespace base {
@@ -36,8 +40,8 @@ class BASE_EXPORT 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; }
+ uint32_t checksum() const { return checksum_; }
+ void set_checksum(uint32_t 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
@@ -47,7 +51,7 @@ class BASE_EXPORT BucketRanges {
// Checksum methods to verify whether the ranges are corrupted (e.g. bad
// memory access).
- uint32 CalculateChecksum() const;
+ uint32_t CalculateChecksum() const;
bool HasValidChecksum() const;
void ResetChecksum();
@@ -63,16 +67,16 @@ class BASE_EXPORT BucketRanges {
// 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
+ // TODO(kaiwang): Consider change this to uint64_t. Because we see a lot of
// noise on UMA dashboard.
- uint32 checksum_;
+ uint32_t checksum_;
DISALLOW_COPY_AND_ASSIGN(BucketRanges);
};
//////////////////////////////////////////////////////////////////////////////
// Expose only for test.
-BASE_EXPORT_PRIVATE extern const uint32 kCrcTable[256];
+BASE_EXPORT extern const uint32_t kCrcTable[256];
} // namespace base
diff --git a/base/metrics/bucket_ranges_unittest.cc b/base/metrics/bucket_ranges_unittest.cc
index fc0699c733..481054c5d2 100644
--- a/base/metrics/bucket_ranges_unittest.cc
+++ b/base/metrics/bucket_ranges_unittest.cc
@@ -4,6 +4,8 @@
#include "base/metrics/bucket_ranges.h"
+#include <stdint.h>
+
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
@@ -76,9 +78,9 @@ TEST(BucketRangesTest, Checksum) {
// http://www.w3.org/TR/PNG/#D-CRCAppendix.
TEST(BucketRangesTest, Crc32TableTest) {
for (int i = 0; i < 256; ++i) {
- uint32 checksum = i;
+ uint32_t checksum = i;
for (int j = 0; j < 8; ++j) {
- const uint32 kReversedPolynomial = 0xedb88320L;
+ const uint32_t kReversedPolynomial = 0xedb88320L;
if (checksum & 1)
checksum = kReversedPolynomial ^ (checksum >> 1);
else
diff --git a/base/metrics/field_trial.cc b/base/metrics/field_trial.cc
index 639f6d38e2..b417b056d2 100644
--- a/base/metrics/field_trial.cc
+++ b/base/metrics/field_trial.cc
@@ -9,16 +9,23 @@
#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 {
+// 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).
+const char kPersistentStringSeparator = '/'; // Currently a slash.
+
+// Define a marker character to be used as a prefix to a trial name on the
+// command line which forces its activation.
+const char kActivationMarker = '*';
+
// 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);
@@ -59,6 +66,45 @@ FieldTrial::Probability GetGroupBoundaryValue(
return std::min(result, divisor - 1);
}
+// Parses the --force-fieldtrials string |trials_string| into |entries|.
+// Returns true if the string was parsed correctly. On failure, the |entries|
+// array may end up being partially filled.
+bool ParseFieldTrialsString(const std::string& trials_string,
+ std::vector<FieldTrial::State>* entries) {
+ const StringPiece trials_string_piece(trials_string);
+
+ 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 (name_end + 1 == group_name_end)
+ return false;
+ if (group_name_end == trials_string.npos)
+ group_name_end = trials_string.length();
+
+ FieldTrial::State entry;
+ // Verify if the trial should be activated or not.
+ if (trials_string[next_item] == kActivationMarker) {
+ // Name cannot be only the indicator.
+ if (name_end - next_item == 1)
+ return false;
+ next_item++;
+ entry.activated = true;
+ }
+ entry.trial_name =
+ trials_string_piece.substr(next_item, name_end - next_item);
+ entry.group_name =
+ trials_string_piece.substr(name_end + 1, group_name_end - name_end - 1);
+ next_item = group_name_end + 1;
+
+ entries->push_back(entry);
+ }
+ return true;
+}
+
} // namespace
// statics
@@ -66,8 +112,6 @@ const int FieldTrial::kNotFinalized = -1;
const int FieldTrial::kDefaultGroupNumber = 0;
bool FieldTrial::enable_benchmarking_ = false;
-const char FieldTrialList::kPersistentStringSeparator('/');
-const char FieldTrialList::kActivationMarker('*');
int FieldTrialList::kNoExpirationYear = 0;
//------------------------------------------------------------------------------
@@ -76,6 +120,10 @@ int FieldTrialList::kNoExpirationYear = 0;
FieldTrial::EntropyProvider::~EntropyProvider() {
}
+FieldTrial::State::State() : activated(false) {}
+
+FieldTrial::State::~State() {}
+
void FieldTrial::Disable() {
DCHECK(!group_reported_);
enable_field_trial_ = false;
@@ -140,6 +188,11 @@ const std::string& FieldTrial::group_name() {
return group_name_;
}
+const std::string& FieldTrial::GetGroupNameWithoutActivation() {
+ FinalizeGroupChoice();
+ return group_name_;
+}
+
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.
@@ -223,16 +276,12 @@ bool FieldTrial::GetActiveGroup(ActiveGroup* active_group) const {
return true;
}
-bool FieldTrial::GetState(FieldTrialState* field_trial_state) const {
+bool FieldTrial::GetState(State* field_trial_state) {
if (!enable_field_trial_)
return false;
+ FinalizeGroupChoice();
field_trial_state->trial_name = trial_name_;
- // If the group name is empty (hasn't been finalized yet), use the default
- // group name instead.
- if (!group_name_.empty())
- field_trial_state->group_name = group_name_;
- else
- field_trial_state->group_name = default_group_name_;
+ field_trial_state->group_name = group_name_;
field_trial_state->activated = group_reported_;
return true;
}
@@ -299,7 +348,7 @@ FieldTrial* FieldTrialList::FactoryGetFieldTrialWithRandomizationSeed(
const int month,
const int day_of_month,
FieldTrial::RandomizationType randomization_type,
- uint32 randomization_seed,
+ uint32_t randomization_seed,
int* default_group_number) {
if (default_group_number)
*default_group_number = FieldTrial::kDefaultGroupNumber;
@@ -321,12 +370,11 @@ FieldTrial* FieldTrialList::FactoryGetFieldTrialWithRandomizationSeed(
// group number, so that it does not conflict with the |AppendGroup()|
// result for the chosen group.
const int kNonConflictingGroupNumber = -2;
- COMPILE_ASSERT(
+ static_assert(
kNonConflictingGroupNumber != FieldTrial::kDefaultGroupNumber,
- conflicting_default_group_number);
- COMPILE_ASSERT(
- kNonConflictingGroupNumber != FieldTrial::kNotFinalized,
- conflicting_default_group_number);
+ "The 'non-conflicting' group number conflicts");
+ static_assert(kNonConflictingGroupNumber != FieldTrial::kNotFinalized,
+ "The 'non-conflicting' group number conflicts");
*default_group_number = kNonConflictingGroupNumber;
}
}
@@ -355,32 +403,39 @@ FieldTrial* FieldTrialList::FactoryGetFieldTrialWithRandomizationSeed(
}
// static
-FieldTrial* FieldTrialList::Find(const std::string& name) {
+FieldTrial* FieldTrialList::Find(const std::string& trial_name) {
if (!global_)
return NULL;
AutoLock auto_lock(global_->lock_);
- return global_->PreLockedFind(name);
+ return global_->PreLockedFind(trial_name);
}
// static
-int FieldTrialList::FindValue(const std::string& name) {
- FieldTrial* field_trial = Find(name);
+int FieldTrialList::FindValue(const std::string& trial_name) {
+ FieldTrial* field_trial = Find(trial_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);
+std::string FieldTrialList::FindFullName(const std::string& trial_name) {
+ FieldTrial* field_trial = Find(trial_name);
if (field_trial)
return field_trial->group_name();
return std::string();
}
// static
-bool FieldTrialList::TrialExists(const std::string& name) {
- return Find(name) != NULL;
+bool FieldTrialList::TrialExists(const std::string& trial_name) {
+ return Find(trial_name) != NULL;
+}
+
+// static
+bool FieldTrialList::IsTrialActive(const std::string& trial_name) {
+ FieldTrial* field_trial = Find(trial_name);
+ FieldTrial::ActiveGroup active_group;
+ return field_trial && field_trial->GetActiveGroup(&active_group);
}
// static
@@ -407,7 +462,7 @@ void FieldTrialList::AllStatesToString(std::string* output) {
AutoLock auto_lock(global_->lock_);
for (const auto& registered : global_->registered_) {
- FieldTrial::FieldTrialState trial;
+ FieldTrial::State trial;
if (!registered.second->GetState(&trial))
continue;
DCHECK_EQ(std::string::npos,
@@ -416,9 +471,9 @@ void FieldTrialList::AllStatesToString(std::string* output) {
trial.group_name.find(kPersistentStringSeparator));
if (trial.activated)
output->append(1, kActivationMarker);
- output->append(trial.trial_name);
+ trial.trial_name.AppendToString(output);
output->append(1, kPersistentStringSeparator);
- output->append(trial.group_name);
+ trial.group_name.AppendToString(output);
output->append(1, kPersistentStringSeparator);
}
}
@@ -440,6 +495,24 @@ void FieldTrialList::GetActiveFieldTrialGroups(
}
// static
+void FieldTrialList::GetActiveFieldTrialGroupsFromString(
+ const std::string& trials_string,
+ FieldTrial::ActiveGroups* active_groups) {
+ std::vector<FieldTrial::State> entries;
+ if (!ParseFieldTrialsString(trials_string, &entries))
+ return;
+
+ for (const auto& entry : entries) {
+ if (entry.activated) {
+ FieldTrial::ActiveGroup group;
+ group.trial_name = entry.trial_name.as_string();
+ group.group_name = entry.group_name.as_string();
+ active_groups->push_back(group);
+ }
+ }
+}
+
+// static
bool FieldTrialList::CreateTrialsFromString(
const std::string& trials_string,
FieldTrialActivationMode mode,
@@ -448,40 +521,21 @@ bool FieldTrialList::CreateTrialsFromString(
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 (name_end + 1 == group_name_end)
- return false;
- if (group_name_end == trials_string.npos)
- group_name_end = trials_string.length();
+ std::vector<FieldTrial::State> entries;
+ if (!ParseFieldTrialsString(trials_string, &entries))
+ return false;
- // Verify if the trial should be activated or not.
- std::string name;
- bool force_activation = false;
- if (trials_string[next_item] == kActivationMarker) {
- // Name cannot be only the indicator.
- if (name_end - next_item == 1)
- return false;
- next_item++;
- force_activation = true;
- }
- name.append(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;
+ for (const auto& entry : entries) {
+ const std::string trial_name = entry.trial_name.as_string();
+ const std::string group_name = entry.group_name.as_string();
- if (ignored_trial_names.find(name) != ignored_trial_names.end())
+ if (ContainsKey(ignored_trial_names, trial_name))
continue;
- FieldTrial* trial = CreateFieldTrial(name, group_name);
+ FieldTrial* trial = CreateFieldTrial(trial_name, group_name);
if (!trial)
return false;
- if (mode == ACTIVATE_TRIALS || force_activation) {
+ if (mode == ACTIVATE_TRIALS || entry.activated) {
// 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.
diff --git a/base/metrics/field_trial.h b/base/metrics/field_trial.h
index 26257ab4a8..7bfc1deef1 100644
--- a/base/metrics/field_trial.h
+++ b/base/metrics/field_trial.h
@@ -54,6 +54,9 @@
#ifndef BASE_METRICS_FIELD_TRIAL_H_
#define BASE_METRICS_FIELD_TRIAL_H_
+#include <stddef.h>
+#include <stdint.h>
+
#include <map>
#include <set>
#include <string>
@@ -61,8 +64,10 @@
#include "base/base_export.h"
#include "base/gtest_prod_util.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/observer_list_threadsafe.h"
+#include "base/strings/string_piece.h"
#include "base/synchronization/lock.h"
#include "base/time/time.h"
@@ -97,7 +102,7 @@ class BASE_EXPORT FieldTrial : public RefCounted<FieldTrial> {
// 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;
+ uint32_t randomization_seed) const = 0;
};
// A pair representing a Field Trial and its selected group.
@@ -108,10 +113,13 @@ class BASE_EXPORT FieldTrial : public RefCounted<FieldTrial> {
// A triplet representing a FieldTrial, its selected group and whether it's
// active.
- struct FieldTrialState {
- std::string trial_name;
- std::string group_name;
+ struct BASE_EXPORT State {
+ StringPiece trial_name;
+ StringPiece group_name;
bool activated;
+
+ State();
+ ~State();
};
typedef std::vector<ActiveGroup> ActiveGroups;
@@ -149,6 +157,11 @@ class BASE_EXPORT FieldTrial : public RefCounted<FieldTrial> {
// is used as the group name. This causes a winner to be chosen if none was.
const std::string& group_name();
+ // Finalizes the group choice and returns the chosen group, but does not mark
+ // the trial as active - so its state will not be reported until group_name()
+ // or similar is called.
+ const std::string& GetGroupNameWithoutActivation();
+
// 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
@@ -245,7 +258,7 @@ class BASE_EXPORT FieldTrial : public RefCounted<FieldTrial> {
// been disabled. In that case, true is returned and |field_trial_state| is
// filled in; otherwise, the result is false and |field_trial_state| is left
// untouched.
- bool GetState(FieldTrialState* field_trial_state) const;
+ bool GetState(State* field_trial_state);
// Returns the group_name. A winner need not have been chosen.
std::string group_name_internal() const { return group_name_; }
@@ -315,15 +328,6 @@ class BASE_EXPORT FieldTrialList {
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.
-
- // Define a marker character to be used as a prefix to a trial name on the
- // command line which forces its activation.
- static const char kActivationMarker; // Currently an asterisk.
-
// 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;
@@ -393,23 +397,28 @@ class BASE_EXPORT FieldTrialList {
const int month,
const int day_of_month,
FieldTrial::RandomizationType randomization_type,
- uint32 randomization_seed,
+ uint32_t randomization_seed,
int* default_group_number);
- // The Find() method can be used to test to see if a named Trial was already
+ // 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);
+ static FieldTrial* Find(const std::string& trial_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);
+ static int FindValue(const std::string& trial_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 the group name chosen for the named trial, or the empty string if
+ // the trial does not exist. The first call of this function on a given field
+ // trial will mark it as active, so that its state will be reported with usage
+ // metrics, crashes, etc.
+ static std::string FindFullName(const std::string& trial_name);
// Returns true if the named trial has been registered.
- static bool TrialExists(const std::string& name);
+ static bool TrialExists(const std::string& trial_name);
+
+ // Returns true if the named trial exists and has been activated.
+ static bool IsTrialActive(const std::string& trial_name);
// Creates a persistent representation of active FieldTrial instances for
// resurrection in another process. This allows randomization to be done in
@@ -438,6 +447,11 @@ class BASE_EXPORT FieldTrialList {
static void GetActiveFieldTrialGroups(
FieldTrial::ActiveGroups* active_groups);
+ // Returns the field trials that are marked active in |trials_string|.
+ static void GetActiveFieldTrialGroupsFromString(
+ const std::string& trials_string,
+ 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
@@ -447,9 +461,9 @@ class BASE_EXPORT FieldTrialList {
// trials are all marked as "used" for the purposes of active trial reporting
// if |mode| is ACTIVATE_TRIALS, otherwise each trial will be marked as "used"
// if it is prefixed with |kActivationMarker|. Trial names in
- // |ignored_trial_names| are ignored when parsing |prior_trials|.
+ // |ignored_trial_names| are ignored when parsing |trials_string|.
static bool CreateTrialsFromString(
- const std::string& prior_trials,
+ const std::string& trials_string,
FieldTrialActivationMode mode,
const std::set<std::string>& ignored_trial_names);
diff --git a/base/metrics/field_trial_unittest.cc b/base/metrics/field_trial_unittest.cc
index f1a1042585..555d7fa60c 100644
--- a/base/metrics/field_trial_unittest.cc
+++ b/base/metrics/field_trial_unittest.cc
@@ -4,7 +4,10 @@
#include "base/metrics/field_trial.h"
+#include <stddef.h>
+
#include "base/build_time.h"
+#include "base/macros.h"
#include "base/message_loop/message_loop.h"
#include "base/rand_util.h"
#include "base/run_loop.h"
@@ -72,6 +75,8 @@ class FieldTrialTest : public testing::Test {
private:
MessageLoop message_loop_;
FieldTrialList trial_list_;
+
+ DISALLOW_COPY_AND_ASSIGN(FieldTrialTest);
};
// Test registration, and also check that destructors are called for trials
@@ -311,8 +316,19 @@ TEST_F(FieldTrialTest, ActiveGroups) {
}
}
+TEST_F(FieldTrialTest, GetActiveFieldTrialGroupsFromString) {
+ FieldTrial::ActiveGroups active_groups;
+ FieldTrialList::GetActiveFieldTrialGroupsFromString("*A/X/B/Y/*C/Z",
+ &active_groups);
+ ASSERT_EQ(2U, active_groups.size());
+ EXPECT_EQ("A", active_groups[0].trial_name);
+ EXPECT_EQ("X", active_groups[0].group_name);
+ EXPECT_EQ("C", active_groups[1].trial_name);
+ EXPECT_EQ("Z", active_groups[1].group_name);
+}
+
TEST_F(FieldTrialTest, AllGroups) {
- FieldTrial::FieldTrialState field_trial_state;
+ FieldTrial::State field_trial_state;
std::string one_winner("One Winner");
scoped_refptr<FieldTrial> trial =
CreateFieldTrial(one_winner, 10, "Default", NULL);
@@ -376,6 +392,28 @@ TEST_F(FieldTrialTest, ActiveGroupsNotFinalized) {
EXPECT_EQ(active_group.group_name, active_groups[0].group_name);
}
+TEST_F(FieldTrialTest, GetGroupNameWithoutActivation) {
+ const char kTrialName[] = "TestTrial";
+ const char kSecondaryGroupName[] = "SecondaryGroup";
+
+ int default_group = -1;
+ scoped_refptr<FieldTrial> trial =
+ CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group);
+ trial->AppendGroup(kSecondaryGroupName, 50);
+
+ // The trial should start inactive.
+ EXPECT_FALSE(FieldTrialList::IsTrialActive(kTrialName));
+
+ // Calling |GetGroupNameWithoutActivation()| should not activate the trial.
+ std::string group_name = trial->GetGroupNameWithoutActivation();
+ EXPECT_FALSE(group_name.empty());
+ EXPECT_FALSE(FieldTrialList::IsTrialActive(kTrialName));
+
+ // Calling |group_name()| should activate it and return the same group name.
+ EXPECT_EQ(group_name, trial->group_name());
+ EXPECT_TRUE(FieldTrialList::IsTrialActive(kTrialName));
+}
+
TEST_F(FieldTrialTest, Save) {
std::string save_string;
@@ -422,30 +460,34 @@ TEST_F(FieldTrialTest, SaveAll) {
std::string save_string;
scoped_refptr<FieldTrial> trial =
- CreateFieldTrial("Some name", 10, "Default some name", NULL);
+ CreateFieldTrial("Some name", 10, "Default some name", nullptr);
EXPECT_EQ("", trial->group_name_internal());
FieldTrialList::AllStatesToString(&save_string);
EXPECT_EQ("Some name/Default some name/", save_string);
+ // Getting all states should have finalized the trial.
+ EXPECT_EQ("Default some name", trial->group_name_internal());
save_string.clear();
// Create a winning group.
+ trial = CreateFieldTrial("trial2", 10, "Default some name", nullptr);
trial->AppendGroup("Winner", 10);
// Finalize the group selection by accessing the selected group.
trial->group();
FieldTrialList::AllStatesToString(&save_string);
- EXPECT_EQ("*Some name/Winner/", save_string);
+ EXPECT_EQ("Some name/Default some name/*trial2/Winner/", save_string);
save_string.clear();
// Create a second trial and winning group.
scoped_refptr<FieldTrial> trial2 =
- CreateFieldTrial("xxx", 10, "Default xxx", NULL);
+ CreateFieldTrial("xxx", 10, "Default xxx", nullptr);
trial2->AppendGroup("yyyy", 10);
// Finalize the group selection by accessing the selected group.
trial2->group();
FieldTrialList::AllStatesToString(&save_string);
// We assume names are alphabetized... though this is not critical.
- EXPECT_EQ("*Some name/Winner/*xxx/yyyy/", save_string);
+ EXPECT_EQ("Some name/Default some name/*trial2/Winner/*xxx/yyyy/",
+ save_string);
save_string.clear();
// Create a third trial with only the default group.
@@ -453,7 +495,8 @@ TEST_F(FieldTrialTest, SaveAll) {
CreateFieldTrial("zzz", 10, "default", NULL);
FieldTrialList::AllStatesToString(&save_string);
- EXPECT_EQ("*Some name/Winner/*xxx/yyyy/zzz/default/", save_string);
+ EXPECT_EQ("Some name/Default some name/*trial2/Winner/*xxx/yyyy/zzz/default/",
+ save_string);
}
TEST_F(FieldTrialTest, Restore) {
@@ -1021,9 +1064,9 @@ TEST_F(FieldTrialTest, FloatBoundariesGiveEqualGroupSizes) {
scoped_refptr<base::FieldTrial> trial(
new base::FieldTrial("test", kBucketCount, "default", entropy));
for (int j = 0; j < kBucketCount; ++j)
- trial->AppendGroup(base::StringPrintf("%d", j), 1);
+ trial->AppendGroup(base::IntToString(j), 1);
- EXPECT_EQ(base::StringPrintf("%d", i), trial->group_name());
+ EXPECT_EQ(base::IntToString(i), trial->group_name());
}
}
diff --git a/base/metrics/histogram.cc b/base/metrics/histogram.cc
index 6198cffbeb..9b9f99da28 100644
--- a/base/metrics/histogram.cc
+++ b/base/metrics/histogram.cc
@@ -9,6 +9,7 @@
#include "base/metrics/histogram.h"
+#include <limits.h>
#include <math.h>
#include <algorithm>
@@ -17,6 +18,8 @@
#include "base/compiler_specific.h"
#include "base/debug/alias.h"
#include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/metrics/metrics_hashes.h"
#include "base/metrics/sample_vector.h"
#include "base/metrics/statistics_recorder.h"
#include "base/pickle.h"
@@ -35,7 +38,7 @@ bool ReadHistogramArguments(PickleIterator* iter,
int* declared_min,
int* declared_max,
size_t* bucket_count,
- uint32* range_checksum) {
+ uint32_t* range_checksum) {
if (!iter->ReadString(histogram_name) ||
!iter->ReadInt(flags) ||
!iter->ReadInt(declared_min) ||
@@ -66,7 +69,7 @@ bool ReadHistogramArguments(PickleIterator* iter,
}
bool ValidateRangeChecksum(const HistogramBase& histogram,
- uint32 range_checksum) {
+ uint32_t range_checksum) {
const Histogram& casted_histogram =
static_cast<const Histogram&>(histogram);
@@ -85,7 +88,7 @@ HistogramBase* Histogram::FactoryGet(const std::string& name,
Sample minimum,
Sample maximum,
size_t bucket_count,
- int32 flags) {
+ int32_t flags) {
bool valid_arguments =
InspectConstructionArguments(name, &minimum, &maximum, &bucket_count);
DCHECK(valid_arguments);
@@ -124,12 +127,29 @@ HistogramBase* Histogram::FactoryTimeGet(const std::string& name,
TimeDelta minimum,
TimeDelta maximum,
size_t bucket_count,
- int32 flags) {
+ int32_t flags) {
return FactoryGet(name, static_cast<Sample>(minimum.InMilliseconds()),
static_cast<Sample>(maximum.InMilliseconds()), bucket_count,
flags);
}
+HistogramBase* Histogram::FactoryGet(const char* name,
+ Sample minimum,
+ Sample maximum,
+ size_t bucket_count,
+ int32_t flags) {
+ return FactoryGet(std::string(name), minimum, maximum, bucket_count, flags);
+}
+
+HistogramBase* Histogram::FactoryTimeGet(const char* name,
+ TimeDelta minimum,
+ TimeDelta maximum,
+ size_t bucket_count,
+ int32_t flags) {
+ return FactoryTimeGet(std::string(name), minimum, maximum, bucket_count,
+ flags);
+}
+
// 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
@@ -185,7 +205,7 @@ int Histogram::FindCorruption(const HistogramSamples& samples) const {
if (!bucket_ranges()->HasValidChecksum())
inconsistencies |= RANGE_CHECKSUM_ERROR;
- int64 delta64 = samples.redundant_count() - samples.TotalCount();
+ int64_t delta64 = samples.redundant_count() - samples.TotalCount();
if (delta64 != 0) {
int delta = static_cast<int>(delta64);
if (delta != delta64)
@@ -241,6 +261,10 @@ bool Histogram::InspectConstructionArguments(const std::string& name,
return true;
}
+uint64_t Histogram::name_hash() const {
+ return samples_->id();
+}
+
HistogramType Histogram::GetHistogramType() const {
return HISTOGRAM;
}
@@ -254,6 +278,10 @@ bool Histogram::HasConstructionArguments(Sample expected_minimum,
}
void Histogram::Add(int value) {
+ AddCount(value, 1);
+}
+
+void Histogram::AddCount(int value, int count) {
DCHECK_EQ(0, ranges(0));
DCHECK_EQ(kSampleType_MAX, ranges(bucket_count()));
@@ -261,11 +289,17 @@ void Histogram::Add(int value) {
value = kSampleType_MAX - 1;
if (value < 0)
value = 0;
- samples_->Accumulate(value, 1);
+ if (count <= 0) {
+ NOTREACHED();
+ return;
+ }
+ samples_->Accumulate(value, count);
+
+ FindAndRunCallback(value);
}
scoped_ptr<HistogramSamples> Histogram::SnapshotSamples() const {
- return SnapshotSampleVector().Pass();
+ return SnapshotSampleVector();
}
void Histogram::AddSamples(const HistogramSamples& samples) {
@@ -307,7 +341,7 @@ Histogram::Histogram(const std::string& name,
declared_min_(minimum),
declared_max_(maximum) {
if (ranges)
- samples_.reset(new SampleVector(ranges));
+ samples_.reset(new SampleVector(HashMetricName(name), ranges));
}
Histogram::~Histogram() {
@@ -345,7 +379,7 @@ HistogramBase* Histogram::DeserializeInfoImpl(PickleIterator* iter) {
int declared_min;
int declared_max;
size_t bucket_count;
- uint32 range_checksum;
+ uint32_t range_checksum;
if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
&declared_max, &bucket_count, &range_checksum)) {
@@ -364,9 +398,10 @@ HistogramBase* Histogram::DeserializeInfoImpl(PickleIterator* iter) {
}
scoped_ptr<SampleVector> Histogram::SnapshotSampleVector() const {
- scoped_ptr<SampleVector> samples(new SampleVector(bucket_ranges()));
+ scoped_ptr<SampleVector> samples(
+ new SampleVector(samples_->id(), bucket_ranges()));
samples->Add(*samples_);
- return samples.Pass();
+ return samples;
}
void Histogram::WriteAsciiImpl(bool graph_it,
@@ -404,8 +439,8 @@ void Histogram::WriteAsciiImpl(bool graph_it,
}
}
- int64 remaining = sample_count;
- int64 past = 0;
+ int64_t remaining = sample_count;
+ int64_t past = 0;
// Output the actual histogram graph.
for (size_t i = 0; i < bucket_count(); ++i) {
Count current = snapshot->GetCountAtIndex(i);
@@ -464,9 +499,9 @@ void Histogram::WriteAsciiHeader(const SampleVector& samples,
StringAppendF(output, " (flags = 0x%x)", flags() & ~kHexRangePrintingFlag);
}
-void Histogram::WriteAsciiBucketContext(const int64 past,
+void Histogram::WriteAsciiBucketContext(const int64_t past,
const Count current,
- const int64 remaining,
+ const int64_t remaining,
const size_t i,
std::string* output) const {
double scaled_sum = (past + current + remaining) / 100.0;
@@ -485,7 +520,7 @@ void Histogram::GetParameters(DictionaryValue* params) const {
}
void Histogram::GetCountAndBucketData(Count* count,
- int64* sum,
+ int64_t* sum,
ListValue* buckets) const {
scoped_ptr<SampleVector> snapshot = SnapshotSampleVector();
*count = snapshot->TotalCount();
@@ -516,7 +551,7 @@ HistogramBase* LinearHistogram::FactoryGet(const std::string& name,
Sample minimum,
Sample maximum,
size_t bucket_count,
- int32 flags) {
+ int32_t flags) {
return FactoryGetWithRangeDescription(
name, minimum, maximum, bucket_count, flags, NULL);
}
@@ -525,19 +560,36 @@ HistogramBase* LinearHistogram::FactoryTimeGet(const std::string& name,
TimeDelta minimum,
TimeDelta maximum,
size_t bucket_count,
- int32 flags) {
+ int32_t flags) {
return FactoryGet(name, static_cast<Sample>(minimum.InMilliseconds()),
static_cast<Sample>(maximum.InMilliseconds()), bucket_count,
flags);
}
+HistogramBase* LinearHistogram::FactoryGet(const char* name,
+ Sample minimum,
+ Sample maximum,
+ size_t bucket_count,
+ int32_t flags) {
+ return FactoryGet(std::string(name), minimum, maximum, bucket_count, flags);
+}
+
+HistogramBase* LinearHistogram::FactoryTimeGet(const char* name,
+ TimeDelta minimum,
+ TimeDelta maximum,
+ size_t bucket_count,
+ int32_t flags) {
+ return FactoryTimeGet(std::string(name), minimum, maximum, bucket_count,
+ flags);
+}
+
HistogramBase* LinearHistogram::FactoryGetWithRangeDescription(
- const std::string& name,
- Sample minimum,
- Sample maximum,
- size_t bucket_count,
- int32 flags,
- const DescriptionPair descriptions[]) {
+ const std::string& name,
+ Sample minimum,
+ Sample maximum,
+ size_t bucket_count,
+ int32_t flags,
+ const DescriptionPair descriptions[]) {
bool valid_arguments = Histogram::InspectConstructionArguments(
name, &minimum, &maximum, &bucket_count);
DCHECK(valid_arguments);
@@ -634,7 +686,7 @@ HistogramBase* LinearHistogram::DeserializeInfoImpl(PickleIterator* iter) {
int declared_min;
int declared_max;
size_t bucket_count;
- uint32 range_checksum;
+ uint32_t range_checksum;
if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
&declared_max, &bucket_count, &range_checksum)) {
@@ -655,7 +707,7 @@ HistogramBase* LinearHistogram::DeserializeInfoImpl(PickleIterator* iter) {
//------------------------------------------------------------------------------
HistogramBase* BooleanHistogram::FactoryGet(const std::string& name,
- int32 flags) {
+ int32_t flags) {
HistogramBase* histogram = StatisticsRecorder::FindHistogram(name);
if (!histogram) {
// To avoid racy destruction at shutdown, the following will be leaked.
@@ -676,6 +728,10 @@ HistogramBase* BooleanHistogram::FactoryGet(const std::string& name,
return histogram;
}
+HistogramBase* BooleanHistogram::FactoryGet(const char* name, int32_t flags) {
+ return FactoryGet(std::string(name), flags);
+}
+
HistogramType BooleanHistogram::GetHistogramType() const {
return BOOLEAN_HISTOGRAM;
}
@@ -690,7 +746,7 @@ HistogramBase* BooleanHistogram::DeserializeInfoImpl(PickleIterator* iter) {
int declared_min;
int declared_max;
size_t bucket_count;
- uint32 range_checksum;
+ uint32_t range_checksum;
if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
&declared_max, &bucket_count, &range_checksum)) {
@@ -713,7 +769,7 @@ HistogramBase* BooleanHistogram::DeserializeInfoImpl(PickleIterator* iter) {
HistogramBase* CustomHistogram::FactoryGet(
const std::string& name,
const std::vector<Sample>& custom_ranges,
- int32 flags) {
+ int32_t flags) {
CHECK(ValidateCustomRanges(custom_ranges));
HistogramBase* histogram = StatisticsRecorder::FindHistogram(name);
@@ -736,6 +792,13 @@ HistogramBase* CustomHistogram::FactoryGet(
return histogram;
}
+HistogramBase* CustomHistogram::FactoryGet(
+ const char* name,
+ const std::vector<Sample>& custom_ranges,
+ int32_t flags) {
+ return FactoryGet(std::string(name), custom_ranges, flags);
+}
+
HistogramType CustomHistogram::GetHistogramType() const {
return CUSTOM_HISTOGRAM;
}
@@ -787,7 +850,7 @@ HistogramBase* CustomHistogram::DeserializeInfoImpl(PickleIterator* iter) {
int declared_min;
int declared_max;
size_t bucket_count;
- uint32 range_checksum;
+ uint32_t range_checksum;
if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
&declared_max, &bucket_count, &range_checksum)) {
diff --git a/base/metrics/histogram.h b/base/metrics/histogram.h
index c13f05e179..28bb29b6e3 100644
--- a/base/metrics/histogram.h
+++ b/base/metrics/histogram.h
@@ -66,15 +66,18 @@
#ifndef BASE_METRICS_HISTOGRAM_H_
#define BASE_METRICS_HISTOGRAM_H_
+#include <stddef.h>
+#include <stdint.h>
+
#include <map>
#include <string>
#include <vector>
#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/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/metrics/bucket_ranges.h"
#include "base/metrics/histogram_base.h"
@@ -114,12 +117,26 @@ class BASE_EXPORT Histogram : public HistogramBase {
Sample minimum,
Sample maximum,
size_t bucket_count,
- int32 flags);
+ int32_t flags);
static HistogramBase* FactoryTimeGet(const std::string& name,
base::TimeDelta minimum,
base::TimeDelta maximum,
size_t bucket_count,
- int32 flags);
+ int32_t flags);
+
+ // Overloads of the above two functions that take a const char* |name| param,
+ // to avoid code bloat from the std::string constructor being inlined into
+ // call sites.
+ static HistogramBase* FactoryGet(const char* name,
+ Sample minimum,
+ Sample maximum,
+ size_t bucket_count,
+ int32_t flags);
+ static HistogramBase* FactoryTimeGet(const char* name,
+ base::TimeDelta minimum,
+ base::TimeDelta maximum,
+ size_t bucket_count,
+ int32_t flags);
static void InitializeBucketRanges(Sample minimum,
Sample maximum,
@@ -162,11 +179,13 @@ class BASE_EXPORT Histogram : public HistogramBase {
size_t* bucket_count);
// HistogramBase implementation:
+ uint64_t name_hash() const override;
HistogramType GetHistogramType() const override;
bool HasConstructionArguments(Sample expected_minimum,
Sample expected_maximum,
size_t expected_bucket_count) const override;
void Add(Sample value) override;
+ void AddCount(Sample value, int count) override;
scoped_ptr<HistogramSamples> SnapshotSamples() const override;
void AddSamples(const HistogramSamples& samples) override;
bool AddSamplesFromPickle(base::PickleIterator* iter) override;
@@ -204,11 +223,12 @@ class BASE_EXPORT Histogram : public HistogramBase {
FRIEND_TEST_ALL_PREFIXES(HistogramTest, CorruptBucketBounds);
FRIEND_TEST_ALL_PREFIXES(HistogramTest, CorruptSampleCounts);
FRIEND_TEST_ALL_PREFIXES(HistogramTest, NameMatchTest);
+ FRIEND_TEST_ALL_PREFIXES(HistogramTest, AddCountTest);
friend class StatisticsRecorder; // To allow it to delete duplicates.
friend class StatisticsRecorderTest;
- friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
+ friend BASE_EXPORT HistogramBase* DeserializeHistogramInfo(
base::PickleIterator* iter);
static HistogramBase* DeserializeInfoImpl(base::PickleIterator* iter);
@@ -232,15 +252,17 @@ class BASE_EXPORT Histogram : public HistogramBase {
// 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,
+ void WriteAsciiBucketContext(const int64_t past,
+ const Count current,
+ const int64_t remaining,
+ const size_t i,
std::string* output) const;
// WriteJSON calls these.
void GetParameters(DictionaryValue* params) const override;
void GetCountAndBucketData(Count* count,
- int64* sum,
+ int64_t* sum,
ListValue* buckets) const override;
// Does not own this object. Should get from StatisticsRecorder.
@@ -270,12 +292,26 @@ class BASE_EXPORT LinearHistogram : public Histogram {
Sample minimum,
Sample maximum,
size_t bucket_count,
- int32 flags);
+ int32_t flags);
static HistogramBase* FactoryTimeGet(const std::string& name,
TimeDelta minimum,
TimeDelta maximum,
size_t bucket_count,
- int32 flags);
+ int32_t flags);
+
+ // Overloads of the above two functions that take a const char* |name| param,
+ // to avoid code bloat from the std::string constructor being inlined into
+ // call sites.
+ static HistogramBase* FactoryGet(const char* name,
+ Sample minimum,
+ Sample maximum,
+ size_t bucket_count,
+ int32_t flags);
+ static HistogramBase* FactoryTimeGet(const char* name,
+ TimeDelta minimum,
+ TimeDelta maximum,
+ size_t bucket_count,
+ int32_t flags);
struct DescriptionPair {
Sample sample;
@@ -292,7 +328,7 @@ class BASE_EXPORT LinearHistogram : public Histogram {
Sample minimum,
Sample maximum,
size_t bucket_count,
- int32 flags,
+ int32_t flags,
const DescriptionPair descriptions[]);
static void InitializeBucketRanges(Sample minimum,
@@ -319,7 +355,7 @@ class BASE_EXPORT LinearHistogram : public Histogram {
bool PrintEmptyBucket(size_t index) const override;
private:
- friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
+ friend BASE_EXPORT HistogramBase* DeserializeHistogramInfo(
base::PickleIterator* iter);
static HistogramBase* DeserializeInfoImpl(base::PickleIterator* iter);
@@ -337,14 +373,19 @@ class BASE_EXPORT LinearHistogram : public Histogram {
// BooleanHistogram is a histogram for booleans.
class BASE_EXPORT BooleanHistogram : public LinearHistogram {
public:
- static HistogramBase* FactoryGet(const std::string& name, int32 flags);
+ static HistogramBase* FactoryGet(const std::string& name, int32_t flags);
+
+ // Overload of the above function that takes a const char* |name| param,
+ // to avoid code bloat from the std::string constructor being inlined into
+ // call sites.
+ static HistogramBase* FactoryGet(const char* name, int32_t flags);
HistogramType GetHistogramType() const override;
private:
BooleanHistogram(const std::string& name, const BucketRanges* ranges);
- friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
+ friend BASE_EXPORT HistogramBase* DeserializeHistogramInfo(
base::PickleIterator* iter);
static HistogramBase* DeserializeInfoImpl(base::PickleIterator* iter);
@@ -362,7 +403,14 @@ class BASE_EXPORT CustomHistogram : public Histogram {
// client should not depend on this.
static HistogramBase* FactoryGet(const std::string& name,
const std::vector<Sample>& custom_ranges,
- int32 flags);
+ int32_t flags);
+
+ // Overload of the above function that takes a const char* |name| param,
+ // to avoid code bloat from the std::string constructor being inlined into
+ // call sites.
+ static HistogramBase* FactoryGet(const char* name,
+ const std::vector<Sample>& custom_ranges,
+ int32_t flags);
// Overridden from Histogram:
HistogramType GetHistogramType() const override;
@@ -385,7 +433,7 @@ class BASE_EXPORT CustomHistogram : public Histogram {
double GetBucketSize(Count current, size_t i) const override;
private:
- friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
+ friend BASE_EXPORT HistogramBase* DeserializeHistogramInfo(
base::PickleIterator* iter);
static HistogramBase* DeserializeInfoImpl(base::PickleIterator* iter);
diff --git a/base/metrics/histogram_base.cc b/base/metrics/histogram_base.cc
index c4306fd9bb..d8aefb12ac 100644
--- a/base/metrics/histogram_base.cc
+++ b/base/metrics/histogram_base.cc
@@ -4,7 +4,9 @@
#include "base/metrics/histogram_base.h"
-#include <climits>
+#include <limits.h>
+
+#include <utility>
#include "base/json/json_string_value_serializer.h"
#include "base/logging.h"
@@ -12,6 +14,7 @@
#include "base/metrics/histogram.h"
#include "base/metrics/histogram_samples.h"
#include "base/metrics/sparse_histogram.h"
+#include "base/metrics/statistics_recorder.h"
#include "base/pickle.h"
#include "base/process/process_handle.h"
#include "base/strings/stringprintf.h"
@@ -70,12 +73,14 @@ void HistogramBase::CheckName(const StringPiece& name) const {
DCHECK_EQ(histogram_name(), name);
}
-void HistogramBase::SetFlags(int32 flags) {
- flags_ |= flags;
+void HistogramBase::SetFlags(int32_t flags) {
+ HistogramBase::Count old_flags = subtle::NoBarrier_Load(&flags_);
+ subtle::NoBarrier_Store(&flags_, old_flags | flags);
}
-void HistogramBase::ClearFlags(int32 flags) {
- flags_ &= ~flags;
+void HistogramBase::ClearFlags(int32_t flags) {
+ HistogramBase::Count old_flags = subtle::NoBarrier_Load(&flags_);
+ subtle::NoBarrier_Store(&flags_, old_flags & ~flags);
}
void HistogramBase::AddTime(const TimeDelta& time) {
@@ -99,7 +104,7 @@ int HistogramBase::FindCorruption(const HistogramSamples& /* samples */) const {
void HistogramBase::WriteJSON(std::string* output) const {
Count count;
- int64 sum;
+ int64_t sum;
scoped_ptr<ListValue> buckets(new ListValue());
GetCountAndBucketData(&count, &sum, buckets.get());
scoped_ptr<DictionaryValue> parameters(new DictionaryValue());
@@ -111,12 +116,22 @@ void HistogramBase::WriteJSON(std::string* output) const {
root.SetInteger("count", count);
root.SetDouble("sum", static_cast<double>(sum));
root.SetInteger("flags", flags());
- root.Set("params", parameters.Pass());
- root.Set("buckets", buckets.Pass());
+ root.Set("params", std::move(parameters));
+ root.Set("buckets", std::move(buckets));
root.SetInteger("pid", GetCurrentProcId());
serializer.Serialize(root);
}
+void HistogramBase::FindAndRunCallback(HistogramBase::Sample sample) const {
+ if ((flags() & kCallbackExists) == 0)
+ return;
+
+ StatisticsRecorder::OnSampleCallback cb =
+ StatisticsRecorder::FindCallback(histogram_name());
+ if (!cb.is_null())
+ cb.Run(sample);
+}
+
void HistogramBase::WriteAsciiBucketGraph(double current_size,
double max_size,
std::string* output) const {
diff --git a/base/metrics/histogram_base.h b/base/metrics/histogram_base.h
index 006395b1f2..4fa07c64ef 100644
--- a/base/metrics/histogram_base.h
+++ b/base/metrics/histogram_base.h
@@ -5,6 +5,8 @@
#ifndef BASE_METRICS_HISTOGRAM_BASE_H_
#define BASE_METRICS_HISTOGRAM_BASE_H_
+#include <limits.h>
+#include <stddef.h>
#include <stdint.h>
#include <string>
@@ -12,7 +14,7 @@
#include "base/atomicops.h"
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/string_piece.h"
#include "base/time/time.h"
@@ -31,7 +33,7 @@ class PickleIterator;
// processes into the browser. If you create another class that inherits from
// HistogramBase, add new histogram types and names below.
-enum BASE_EXPORT HistogramType {
+enum HistogramType {
HISTOGRAM,
LINEAR_HISTOGRAM,
BOOLEAN_HISTOGRAM,
@@ -43,8 +45,7 @@ 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(
- base::PickleIterator* iter);
+BASE_EXPORT HistogramBase* DeserializeHistogramInfo(base::PickleIterator* iter);
////////////////////////////////////////////////////////////////////////////////
@@ -74,6 +75,12 @@ class BASE_EXPORT HistogramBase {
// the source histogram!).
kIPCSerializationSourceFlag = 0x10,
+ // Indicates that a callback exists for when a new sample is recorded on
+ // this histogram. We store this as a flag with the histogram since
+ // histograms can be in performance critical code, and this allows us
+ // to shortcut looking up the callback if it doesn't exist.
+ kCallbackExists = 0x20,
+
// Only for Histogram and its sub classes: fancy bucket-naming support.
kHexRangePrintingFlag = 0x8000,
};
@@ -92,15 +99,18 @@ class BASE_EXPORT HistogramBase {
explicit HistogramBase(const std::string& name);
virtual ~HistogramBase();
- std::string histogram_name() const { return histogram_name_; }
+ const std::string& histogram_name() const { return histogram_name_; }
// Comapres |name| to the histogram name and triggers a DCHECK if they do not
// match. This is a helper function used by histogram macros, which results in
// in more compact machine code being generated by the macros.
void CheckName(const StringPiece& name) const;
+ // Get a unique ID for this histogram's samples.
+ virtual uint64_t name_hash() const = 0;
+
// Operations with Flags enum.
- int32_t flags() const { return flags_; }
+ int32_t flags() const { return subtle::NoBarrier_Load(&flags_); }
void SetFlags(int32_t flags);
void ClearFlags(int32_t flags);
@@ -115,6 +125,12 @@ class BASE_EXPORT HistogramBase {
virtual void Add(Sample value) = 0;
+ // In Add function the |value| bucket is increased by one, but in some use
+ // cases we need to increase this value by an arbitrary integer. AddCount
+ // function increases the |value| bucket by |count|. |count| should be greater
+ // than or equal to 1.
+ virtual void AddCount(Sample value, int count) = 0;
+
// 2 convenient functions that call Add(Sample).
void AddTime(const TimeDelta& time);
void AddBoolean(bool value);
@@ -155,7 +171,7 @@ class BASE_EXPORT HistogramBase {
// counts to |buckets|, the total sample count to |count| and the total sum
// to |sum|.
virtual void GetCountAndBucketData(Count* count,
- int64* sum,
+ int64_t* sum,
ListValue* buckets) const = 0;
//// Produce actual graph (set of blank vs non blank char's) for a bucket.
@@ -172,9 +188,13 @@ class BASE_EXPORT HistogramBase {
double scaled_sum,
std::string* output) const;
+ // Retrieves the callback for this histogram, if one exists, and runs it
+ // passing |sample| as the parameter.
+ void FindAndRunCallback(Sample sample) const;
+
private:
const std::string histogram_name_;
- int32_t flags_;
+ AtomicCount flags_;
DISALLOW_COPY_AND_ASSIGN(HistogramBase);
};
diff --git a/base/metrics/histogram_delta_serialization.h b/base/metrics/histogram_delta_serialization.h
index a379914c0d..0a3983f8ea 100644
--- a/base/metrics/histogram_delta_serialization.h
+++ b/base/metrics/histogram_delta_serialization.h
@@ -9,10 +9,11 @@
#include <vector>
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/metrics/histogram_flattener.h"
#include "base/metrics/histogram_snapshot_manager.h"
+#include "base/threading/thread_checker.h"
namespace base {
@@ -45,6 +46,8 @@ class BASE_EXPORT HistogramDeltaSerialization : public HistogramFlattener {
HistogramBase::Inconsistency problem) override;
void InconsistencyDetectedInLoggedCount(int amount) override;
+ ThreadChecker thread_checker_;
+
// Calculates deltas in histogram counters.
HistogramSnapshotManager histogram_snapshot_manager_;
diff --git a/base/metrics/histogram_flattener.h b/base/metrics/histogram_flattener.h
index ca05a4f421..b5fe976656 100644
--- a/base/metrics/histogram_flattener.h
+++ b/base/metrics/histogram_flattener.h
@@ -8,7 +8,7 @@
#include <map>
#include <string>
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/metrics/histogram.h"
namespace base {
diff --git a/base/metrics/histogram_macros.h b/base/metrics/histogram_macros.h
index 2aee1a5de4..0492f0c913 100644
--- a/base/metrics/histogram_macros.h
+++ b/base/metrics/histogram_macros.h
@@ -6,7 +6,6 @@
#define BASE_METRICS_HISTOGRAM_MACROS_H_
#include "base/atomicops.h"
-#include "base/basictypes.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "base/time/time.h"
@@ -189,6 +188,9 @@
#define UMA_HISTOGRAM_COUNTS_100(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
name, sample, 1, 100, 50)
+#define UMA_HISTOGRAM_COUNTS_1000(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
+ name, sample, 1, 1000, 50)
+
#define UMA_HISTOGRAM_COUNTS_10000(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
name, sample, 1, 10000, 50)
@@ -203,6 +205,9 @@
#define UMA_HISTOGRAM_MEMORY_MB(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
name, sample, 1, 1000, 50)
+#define UMA_HISTOGRAM_MEMORY_LARGE_MB(name, sample) \
+ UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, 1, 64000, 100)
+
#define UMA_HISTOGRAM_PERCENTAGE(name, under_one_hundred) \
UMA_HISTOGRAM_ENUMERATION(name, under_one_hundred, 101)
diff --git a/base/metrics/histogram_samples.cc b/base/metrics/histogram_samples.cc
index 5a9ceab211..61efd23f2e 100644
--- a/base/metrics/histogram_samples.cc
+++ b/base/metrics/histogram_samples.cc
@@ -59,30 +59,58 @@ void SampleCountPickleIterator::Get(HistogramBase::Sample* min,
} // namespace
-HistogramSamples::HistogramSamples() : sum_(0), redundant_count_(0) {}
+// Don't try to delegate behavior to the constructor below that accepts a
+// Matadata pointer by passing &local_meta_. Such cannot be reliably passed
+// because it has not yet been constructed -- no member variables have; the
+// class itself is in the middle of being constructed. Using it to
+// initialize meta_ is okay because the object now exists and local_meta_
+// is before meta_ in the construction order.
+HistogramSamples::HistogramSamples(uint64_t id)
+ : meta_(&local_meta_) {
+ meta_->id = id;
+}
+
+HistogramSamples::HistogramSamples(uint64_t id, Metadata* meta)
+ : meta_(meta) {
+ DCHECK(meta_->id == 0 || meta_->id == id);
+ meta_->id = id;
+}
HistogramSamples::~HistogramSamples() {}
+// Despite using atomic operations, the increment/add actions below are *not*
+// atomic! Race conditions may cause loss of samples or even completely corrupt
+// the 64-bit sum on 32-bit machines. This is done intentionally to reduce the
+// cost of these operations that could be executed in performance-significant
+// points of the code.
+//
+// TODO(bcwhite): Gather quantitative information as to the cost of using
+// proper atomic increments and improve either globally or for those histograms
+// that really need it.
+
void HistogramSamples::Add(const HistogramSamples& other) {
- sum_ += other.sum();
+ meta_->sum += other.sum();
+
HistogramBase::Count old_redundant_count =
- subtle::NoBarrier_Load(&redundant_count_);
- subtle::NoBarrier_Store(&redundant_count_,
+ subtle::NoBarrier_Load(&meta_->redundant_count);
+ subtle::NoBarrier_Store(&meta_->redundant_count,
old_redundant_count + other.redundant_count());
bool success = AddSubtractImpl(other.Iterator().get(), ADD);
DCHECK(success);
}
bool HistogramSamples::AddFromPickle(PickleIterator* iter) {
- int64 sum;
+ int64_t sum;
HistogramBase::Count redundant_count;
if (!iter->ReadInt64(&sum) || !iter->ReadInt(&redundant_count))
return false;
- sum_ += sum;
+
+ meta_->sum += sum;
+
HistogramBase::Count old_redundant_count =
- subtle::NoBarrier_Load(&redundant_count_);
- subtle::NoBarrier_Store(&redundant_count_,
+ subtle::NoBarrier_Load(&meta_->redundant_count);
+ subtle::NoBarrier_Store(&meta_->redundant_count,
old_redundant_count + redundant_count);
SampleCountPickleIterator pickle_iter(iter);
@@ -90,18 +118,20 @@ bool HistogramSamples::AddFromPickle(PickleIterator* iter) {
}
void HistogramSamples::Subtract(const HistogramSamples& other) {
- sum_ -= other.sum();
+ meta_->sum -= other.sum();
+
HistogramBase::Count old_redundant_count =
- subtle::NoBarrier_Load(&redundant_count_);
- subtle::NoBarrier_Store(&redundant_count_,
+ subtle::NoBarrier_Load(&meta_->redundant_count);
+ subtle::NoBarrier_Store(&meta_->redundant_count,
old_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(subtle::NoBarrier_Load(&redundant_count_)))
+ if (!pickle->WriteInt64(meta_->sum))
+ return false;
+ if (!pickle->WriteInt(subtle::NoBarrier_Load(&meta_->redundant_count)))
return false;
HistogramBase::Sample min;
@@ -119,13 +149,13 @@ bool HistogramSamples::Serialize(Pickle* pickle) const {
return true;
}
-void HistogramSamples::IncreaseSum(int64 diff) {
- sum_ += diff;
+void HistogramSamples::IncreaseSum(int64_t diff) {
+ meta_->sum += diff;
}
void HistogramSamples::IncreaseRedundantCount(HistogramBase::Count diff) {
- subtle::NoBarrier_Store(&redundant_count_,
- subtle::NoBarrier_Load(&redundant_count_) + diff);
+ subtle::NoBarrier_Store(&meta_->redundant_count,
+ subtle::NoBarrier_Load(&meta_->redundant_count) + diff);
}
SampleCountIterator::~SampleCountIterator() {}
diff --git a/base/metrics/histogram_samples.h b/base/metrics/histogram_samples.h
index 54185cf383..3da3e2d829 100644
--- a/base/metrics/histogram_samples.h
+++ b/base/metrics/histogram_samples.h
@@ -5,9 +5,13 @@
#ifndef BASE_METRICS_HISTOGRAM_SAMPLES_H_
#define BASE_METRICS_HISTOGRAM_SAMPLES_H_
-#include "base/basictypes.h"
-#include "base/metrics/histogram_base.h"
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/atomicops.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
+#include "base/metrics/histogram_base.h"
namespace base {
@@ -18,7 +22,35 @@ class SampleCountIterator;
// HistogramSamples is a container storing all samples of a histogram.
class BASE_EXPORT HistogramSamples {
public:
- HistogramSamples();
+ struct Metadata {
+ // Initialized when the sample-set is first created with a value provided
+ // by the caller. It is generally used to identify the sample-set across
+ // threads and processes, though not necessarily uniquely as it is possible
+ // to have multiple sample-sets representing subsets of the data.
+ uint64_t id;
+
+ // The sum of all the entries, effectivly the sum(sample * count) for
+ // all samples. Despite being atomic, no guarantees are made on the
+ // accuracy of this value; there may be races during histogram
+ // accumulation and snapshotting that we choose to accept. It should
+ // be treated as approximate.
+ // TODO(bcwhite): Change this to std::atomic<int64_t>.
+ int64_t sum;
+
+ // A "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::AtomicCount redundant_count;
+
+ Metadata() : id(0), sum(0), redundant_count(0) {}
+ };
+
+ explicit HistogramSamples(uint64_t id);
+ HistogramSamples(uint64_t id, Metadata* meta);
virtual ~HistogramSamples();
virtual void Accumulate(HistogramBase::Sample value,
@@ -37,9 +69,10 @@ class BASE_EXPORT HistogramSamples {
virtual bool Serialize(Pickle* pickle) const;
// Accessor fuctions.
- int64 sum() const { return sum_; }
+ uint64_t id() const { return meta_->id; }
+ int64_t sum() const { return meta_->sum; }
HistogramBase::Count redundant_count() const {
- return subtle::NoBarrier_Load(&redundant_count_);
+ return subtle::NoBarrier_Load(&meta_->redundant_count);
}
protected:
@@ -47,20 +80,17 @@ class BASE_EXPORT HistogramSamples {
enum Operator { ADD, SUBTRACT };
virtual bool AddSubtractImpl(SampleCountIterator* iter, Operator op) = 0;
- void IncreaseSum(int64 diff);
+ void IncreaseSum(int64_t 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::AtomicCount redundant_count_;
+ // In order to support histograms shared through an external memory segment,
+ // meta values may be the local storage or external storage depending on the
+ // wishes of the derived class.
+ Metadata local_meta_;
+ Metadata* meta_;
+
+ DISALLOW_COPY_AND_ASSIGN(HistogramSamples);
};
class BASE_EXPORT SampleCountIterator {
diff --git a/base/metrics/histogram_snapshot_manager.cc b/base/metrics/histogram_snapshot_manager.cc
index a7605aa141..02f87f0105 100644
--- a/base/metrics/histogram_snapshot_manager.cc
+++ b/base/metrics/histogram_snapshot_manager.cc
@@ -41,13 +41,11 @@ void HistogramSnapshotManager::PrepareDelta(const HistogramBase& histogram) {
// Get up-to-date snapshot of sample stats.
scoped_ptr<HistogramSamples> 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.
+ int corruption = histogram.FindCorruption(*snapshot);
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);
@@ -59,29 +57,29 @@ void HistogramSnapshotManager::PrepareDelta(const HistogramBase& histogram) {
// 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.
+ const uint64_t histogram_hash = histogram.name_hash();
if (corruption) {
- DLOG(ERROR) << "Histogram: " << histogram_name
+ DLOG(ERROR) << "Histogram: " << histogram.histogram_name()
<< " has data corruption: " << corruption;
histogram_flattener_->InconsistencyDetected(
static_cast<HistogramBase::Inconsistency>(corruption));
// Don't record corrupt data to metrics services.
- int old_corruption = inconsistencies_[histogram_name];
+ int old_corruption = inconsistencies_[histogram_hash];
if (old_corruption == (corruption | old_corruption))
return; // We've already seen this corruption for this histogram.
- inconsistencies_[histogram_name] |= corruption;
+ inconsistencies_[histogram_hash] |= corruption;
histogram_flattener_->UniqueInconsistencyDetected(
static_cast<HistogramBase::Inconsistency>(corruption));
return;
}
HistogramSamples* to_log;
- std::map<std::string, HistogramSamples*>::iterator it =
- logged_samples_.find(histogram_name);
+ auto it = logged_samples_.find(histogram_hash);
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;
+ logged_samples_[histogram_hash] = to_log;
} else {
HistogramSamples* already_logged = it->second;
InspectLoggedSamplesInconsistency(*snapshot, already_logged);
diff --git a/base/metrics/histogram_snapshot_manager.h b/base/metrics/histogram_snapshot_manager.h
index 5a5f2e93e5..bad4668067 100644
--- a/base/metrics/histogram_snapshot_manager.h
+++ b/base/metrics/histogram_snapshot_manager.h
@@ -5,10 +5,12 @@
#ifndef BASE_METRICS_HISTOGRAM_SNAPSHOT_MANAGER_H_
#define BASE_METRICS_HISTOGRAM_SNAPSHOT_MANAGER_H_
+#include <stdint.h>
+
#include <map>
#include <string>
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/metrics/histogram_base.h"
namespace base {
@@ -48,10 +50,12 @@ class BASE_EXPORT HistogramSnapshotManager {
// 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<std::string, HistogramSamples*> logged_samples_;
+ // The information is indexed by the hash of the histogram name.
+ std::map<uint64_t, HistogramSamples*> logged_samples_;
- // List of histograms found to be corrupt, and their problems.
- std::map<std::string, int> inconsistencies_;
+ // Set of histograms found to be corrupt and their problems, indexed
+ // by the hash of the histogram name.
+ std::map<uint64_t, int> inconsistencies_;
// |histogram_flattener_| handles the logistics of recording the histogram
// deltas.
diff --git a/base/metrics/histogram_snapshot_manager_unittest.cc b/base/metrics/histogram_snapshot_manager_unittest.cc
index 3a1fd4044b..b6a367af2b 100644
--- a/base/metrics/histogram_snapshot_manager_unittest.cc
+++ b/base/metrics/histogram_snapshot_manager_unittest.cc
@@ -7,8 +7,9 @@
#include <string>
#include <vector>
-#include "base/metrics/histogram.h"
+#include "base/macros.h"
#include "base/metrics/histogram_delta_serialization.h"
+#include "base/metrics/histogram_macros.h"
#include "base/metrics/statistics_recorder.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/base/metrics/histogram_unittest.cc b/base/metrics/histogram_unittest.cc
index 2e3a1ee013..2fadc30441 100644
--- a/base/metrics/histogram_unittest.cc
+++ b/base/metrics/histogram_unittest.cc
@@ -4,13 +4,18 @@
#include "base/metrics/histogram.h"
-#include <climits>
+#include <limits.h>
+#include <stddef.h>
+#include <stdint.h>
+
#include <algorithm>
+#include <climits>
#include <vector>
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/metrics/bucket_ranges.h"
+#include "base/metrics/histogram_macros.h"
#include "base/metrics/sample_vector.h"
#include "base/metrics/statistics_recorder.h"
#include "base/pickle.h"
@@ -80,7 +85,7 @@ TEST_F(HistogramTest, NameMatchTest) {
}
TEST_F(HistogramTest, ExponentialRangesTest) {
- // Check that we got a nice exponential when there was enough rooom.
+ // Check that we got a nice exponential when there was enough room.
BucketRanges ranges(9);
Histogram::InitializeBucketRanges(1, 64, &ranges);
EXPECT_EQ(0, ranges.range(0));
@@ -230,6 +235,30 @@ TEST_F(HistogramTest, CustomHistogramWithOnly2Buckets) {
EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges->range(2));
}
+// Test the AddCount function.
+TEST_F(HistogramTest, AddCountTest) {
+ const size_t kBucketCount = 50;
+ Histogram* histogram = static_cast<Histogram*>(
+ Histogram::FactoryGet("AddCountHistogram", 10, 100, kBucketCount,
+ HistogramBase::kNoFlags));
+
+ histogram->AddCount(20, 15);
+ histogram->AddCount(30, 14);
+
+ scoped_ptr<SampleVector> samples = histogram->SnapshotSampleVector();
+ EXPECT_EQ(29, samples->TotalCount());
+ EXPECT_EQ(15, samples->GetCount(20));
+ EXPECT_EQ(14, samples->GetCount(30));
+
+ histogram->AddCount(20, 25);
+ histogram->AddCount(30, 24);
+
+ scoped_ptr<SampleVector> samples2 = histogram->SnapshotSampleVector();
+ EXPECT_EQ(78, samples2->TotalCount());
+ EXPECT_EQ(40, samples2->GetCount(20));
+ EXPECT_EQ(38, samples2->GetCount(30));
+}
+
// Make sure histogram handles out-of-bounds data gracefully.
TEST_F(HistogramTest, BoundsTest) {
const size_t kBucketCount = 50;
@@ -389,11 +418,11 @@ TEST_F(HistogramTest, HistogramSerializeInfo) {
EXPECT_TRUE(iter.ReadInt(&max));
EXPECT_EQ(64, max);
- int64 bucket_count;
+ int64_t bucket_count;
EXPECT_TRUE(iter.ReadInt64(&bucket_count));
EXPECT_EQ(8, bucket_count);
- uint32 checksum;
+ uint32_t checksum;
EXPECT_TRUE(iter.ReadUInt32(&checksum));
EXPECT_EQ(histogram->bucket_ranges()->checksum(), checksum);
@@ -418,8 +447,8 @@ TEST_F(HistogramTest, CustomHistogramSerializeInfo) {
int i;
std::string s;
- int64 bucket_count;
- uint32 ui32;
+ int64_t bucket_count;
+ uint32_t 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));
diff --git a/base/metrics/metrics_hashes.cc b/base/metrics/metrics_hashes.cc
new file mode 100644
index 0000000000..73bce2e00b
--- /dev/null
+++ b/base/metrics/metrics_hashes.cc
@@ -0,0 +1,31 @@
+// Copyright 2014 The Chromium Authors. All 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/metrics_hashes.h"
+
+#include "base/logging.h"
+#include "base/md5.h"
+#include "base/sys_byteorder.h"
+
+namespace base {
+
+namespace {
+
+// Converts the 8-byte prefix of an MD5 hash into a uint64_t value.
+inline uint64_t DigestToUInt64(const base::MD5Digest& digest) {
+ uint64_t value;
+ DCHECK_GE(sizeof(digest.a), sizeof(value));
+ memcpy(&value, digest.a, sizeof(value));
+ return base::NetToHost64(value);
+}
+
+} // namespace
+
+uint64_t HashMetricName(const std::string& name) {
+ base::MD5Digest digest;
+ base::MD5Sum(name.c_str(), name.size(), &digest);
+ return DigestToUInt64(digest);
+}
+
+} // namespace metrics
diff --git a/base/metrics/metrics_hashes.h b/base/metrics/metrics_hashes.h
new file mode 100644
index 0000000000..bd040173fb
--- /dev/null
+++ b/base/metrics/metrics_hashes.h
@@ -0,0 +1,21 @@
+// Copyright 2014 The Chromium Authors. All 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_METRICS_HASHES_H_
+#define BASE_METRICS_METRICS_HASHES_H_
+
+#include <stdint.h>
+#include <string>
+
+#include "base/base_export.h"
+
+namespace base {
+
+// Computes a uint64_t hash of a given string based on its MD5 hash. Suitable
+// for metric names.
+BASE_EXPORT uint64_t HashMetricName(const std::string& name);
+
+} // namespace metrics
+
+#endif // BASE_METRICS_METRICS_HASHES_H_
diff --git a/base/metrics/metrics_hashes_unittest.cc b/base/metrics/metrics_hashes_unittest.cc
new file mode 100644
index 0000000000..aea254ef49
--- /dev/null
+++ b/base/metrics/metrics_hashes_unittest.cc
@@ -0,0 +1,35 @@
+// Copyright 2014 The Chromium Authors. All 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/metrics_hashes.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/format_macros.h"
+#include "base/macros.h"
+#include "base/strings/stringprintf.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+// Make sure our ID hashes are the same as what we see on the server side.
+TEST(MetricsUtilTest, HashMetricName) {
+ static const struct {
+ std::string input;
+ std::string output;
+ } cases[] = {
+ {"Back", "0x0557fa923dcee4d0"},
+ {"Forward", "0x67d2f6740a8eaebf"},
+ {"NewTab", "0x290eb683f96572f1"},
+ };
+
+ for (size_t i = 0; i < arraysize(cases); ++i) {
+ uint64_t hash = HashMetricName(cases[i].input);
+ std::string hash_hex = base::StringPrintf("0x%016" PRIx64, hash);
+ EXPECT_EQ(cases[i].output, hash_hex);
+ }
+}
+
+} // namespace metrics
diff --git a/base/metrics/sample_map.cc b/base/metrics/sample_map.cc
index f2540a4d00..a691243f34 100644
--- a/base/metrics/sample_map.cc
+++ b/base/metrics/sample_map.cc
@@ -11,7 +11,9 @@ namespace base {
typedef HistogramBase::Count Count;
typedef HistogramBase::Sample Sample;
-SampleMap::SampleMap() {}
+SampleMap::SampleMap() : SampleMap(0) {}
+
+SampleMap::SampleMap(uint64_t id) : HistogramSamples(id) {}
SampleMap::~SampleMap() {}
diff --git a/base/metrics/sample_map.h b/base/metrics/sample_map.h
index 952d34a1c4..da536e31e6 100644
--- a/base/metrics/sample_map.h
+++ b/base/metrics/sample_map.h
@@ -8,18 +8,22 @@
#ifndef BASE_METRICS_SAMPLE_MAP_H_
#define BASE_METRICS_SAMPLE_MAP_H_
+#include <stdint.h>
+
#include <map>
#include "base/compiler_specific.h"
+#include "base/macros.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 {
+class BASE_EXPORT SampleMap : public HistogramSamples {
public:
SampleMap();
+ explicit SampleMap(uint64_t id);
~SampleMap() override;
// HistogramSamples implementation:
@@ -40,7 +44,7 @@ class BASE_EXPORT_PRIVATE SampleMap : public HistogramSamples {
DISALLOW_COPY_AND_ASSIGN(SampleMap);
};
-class BASE_EXPORT_PRIVATE SampleMapIterator : public SampleCountIterator {
+class BASE_EXPORT SampleMapIterator : public SampleCountIterator {
public:
typedef std::map<HistogramBase::Sample, HistogramBase::Count>
SampleToCountMap;
diff --git a/base/metrics/sample_map_unittest.cc b/base/metrics/sample_map_unittest.cc
index 22ce8e1c8e..c941d65f06 100644
--- a/base/metrics/sample_map_unittest.cc
+++ b/base/metrics/sample_map_unittest.cc
@@ -11,7 +11,7 @@ namespace base {
namespace {
TEST(SampleMapTest, AccumulateTest) {
- SampleMap samples;
+ SampleMap samples(1);
samples.Accumulate(1, 100);
samples.Accumulate(2, 200);
@@ -25,8 +25,8 @@ TEST(SampleMapTest, AccumulateTest) {
}
TEST(SampleMapTest, AddSubtractTest) {
- SampleMap samples1;
- SampleMap samples2;
+ SampleMap samples1(1);
+ SampleMap samples2(2);
samples1.Accumulate(1, 100);
samples1.Accumulate(2, 100);
@@ -56,7 +56,7 @@ TEST(SampleMapTest, AddSubtractTest) {
}
TEST(SampleMapIteratorTest, IterateTest) {
- SampleMap samples;
+ SampleMap samples(1);
samples.Accumulate(1, 100);
samples.Accumulate(2, 200);
samples.Accumulate(4, -300);
@@ -91,14 +91,14 @@ TEST(SampleMapIteratorTest, IterateTest) {
}
TEST(SampleMapIteratorTest, SkipEmptyRanges) {
- SampleMap samples;
+ SampleMap samples(1);
samples.Accumulate(5, 1);
samples.Accumulate(10, 2);
samples.Accumulate(15, 3);
samples.Accumulate(20, 4);
samples.Accumulate(25, 5);
- SampleMap samples2;
+ SampleMap samples2(2);
samples2.Accumulate(5, 1);
samples2.Accumulate(20, 4);
samples2.Accumulate(25, 5);
@@ -132,7 +132,7 @@ TEST(SampleMapIteratorTest, SkipEmptyRanges) {
#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && GTEST_HAS_DEATH_TEST
TEST(SampleMapIteratorDeathTest, IterateDoneTest) {
- SampleMap samples;
+ SampleMap samples(1);
scoped_ptr<SampleCountIterator> it = samples.Iterator();
diff --git a/base/metrics/sample_vector.cc b/base/metrics/sample_vector.cc
index 1202527545..6120c50ba9 100644
--- a/base/metrics/sample_vector.cc
+++ b/base/metrics/sample_vector.cc
@@ -13,8 +13,27 @@ typedef HistogramBase::Count Count;
typedef HistogramBase::Sample Sample;
SampleVector::SampleVector(const BucketRanges* bucket_ranges)
- : counts_(bucket_ranges->bucket_count()),
+ : SampleVector(0, bucket_ranges) {}
+
+SampleVector::SampleVector(uint64_t id, const BucketRanges* bucket_ranges)
+ : HistogramSamples(id),
+ local_counts_(bucket_ranges->bucket_count()),
+ counts_(&local_counts_[0]),
+ counts_size_(local_counts_.size()),
+ bucket_ranges_(bucket_ranges) {
+ CHECK_GE(bucket_ranges_->bucket_count(), 1u);
+}
+
+SampleVector::SampleVector(uint64_t id,
+ HistogramBase::AtomicCount* counts,
+ size_t /* counts_size */,
+ Metadata* meta,
+ const BucketRanges* bucket_ranges)
+ : HistogramSamples(id, meta),
+ counts_(counts),
+ counts_size_(bucket_ranges->bucket_count()),
bucket_ranges_(bucket_ranges) {
+ CHECK_LE(bucket_ranges_->bucket_count(), counts_size_);
CHECK_GE(bucket_ranges_->bucket_count(), 1u);
}
@@ -35,20 +54,20 @@ Count SampleVector::GetCount(Sample value) const {
Count SampleVector::TotalCount() const {
Count count = 0;
- for (size_t i = 0; i < counts_.size(); i++) {
+ for (size_t i = 0; i < counts_size_; i++) {
count += subtle::NoBarrier_Load(&counts_[i]);
}
return count;
}
Count SampleVector::GetCountAtIndex(size_t bucket_index) const {
- DCHECK(bucket_index < counts_.size());
+ DCHECK(bucket_index < counts_size_);
return subtle::NoBarrier_Load(&counts_[bucket_index]);
}
scoped_ptr<SampleCountIterator> SampleVector::Iterator() const {
return scoped_ptr<SampleCountIterator>(
- new SampleVectorIterator(&counts_, bucket_ranges_));
+ new SampleVectorIterator(counts_, counts_size_, bucket_ranges_));
}
bool SampleVector::AddSubtractImpl(SampleCountIterator* iter,
@@ -59,7 +78,7 @@ bool SampleVector::AddSubtractImpl(SampleCountIterator* iter,
// Go through the iterator and add the counts into correct bucket.
size_t index = 0;
- while (index < counts_.size() && !iter->Done()) {
+ while (index < counts_size_ && !iter->Done()) {
iter->Get(&min, &max, &count);
if (min == bucket_ranges_->range(index) &&
max == bucket_ranges_->range(index + 1)) {
@@ -109,19 +128,33 @@ size_t SampleVector::GetBucketIndex(Sample value) const {
return mid;
}
-SampleVectorIterator::SampleVectorIterator(const std::vector<Count>* counts,
- const BucketRanges* bucket_ranges)
+SampleVectorIterator::SampleVectorIterator(
+ const std::vector<HistogramBase::AtomicCount>* counts,
+ const BucketRanges* bucket_ranges)
+ : counts_(&(*counts)[0]),
+ counts_size_(counts->size()),
+ bucket_ranges_(bucket_ranges),
+ index_(0) {
+ CHECK_GE(bucket_ranges_->bucket_count(), counts_size_);
+ SkipEmptyBuckets();
+}
+
+SampleVectorIterator::SampleVectorIterator(
+ const HistogramBase::AtomicCount* counts,
+ size_t counts_size,
+ const BucketRanges* bucket_ranges)
: counts_(counts),
+ counts_size_(counts_size),
bucket_ranges_(bucket_ranges),
index_(0) {
- CHECK_GE(bucket_ranges_->bucket_count(), counts_->size());
+ CHECK_GE(bucket_ranges_->bucket_count(), counts_size_);
SkipEmptyBuckets();
}
SampleVectorIterator::~SampleVectorIterator() {}
bool SampleVectorIterator::Done() const {
- return index_ >= counts_->size();
+ return index_ >= counts_size_;
}
void SampleVectorIterator::Next() {
@@ -139,7 +172,7 @@ void SampleVectorIterator::Get(HistogramBase::Sample* min,
if (max != NULL)
*max = bucket_ranges_->range(index_ + 1);
if (count != NULL)
- *count = subtle::NoBarrier_Load(&(*counts_)[index_]);
+ *count = subtle::NoBarrier_Load(&counts_[index_]);
}
bool SampleVectorIterator::GetBucketIndex(size_t* index) const {
@@ -153,8 +186,8 @@ void SampleVectorIterator::SkipEmptyBuckets() {
if (Done())
return;
- while (index_ < counts_->size()) {
- if (subtle::NoBarrier_Load(&(*counts_)[index_]) != 0)
+ while (index_ < counts_size_) {
+ if (subtle::NoBarrier_Load(&counts_[index_]) != 0)
return;
index_++;
}
diff --git a/base/metrics/sample_vector.h b/base/metrics/sample_vector.h
index 55f9b965cc..0317869f95 100644
--- a/base/metrics/sample_vector.h
+++ b/base/metrics/sample_vector.h
@@ -8,10 +8,14 @@
#ifndef BASE_METRICS_SAMPLE_VECTOR_H_
#define BASE_METRICS_SAMPLE_VECTOR_H_
+#include <stddef.h>
+#include <stdint.h>
+
#include <vector>
#include "base/compiler_specific.h"
#include "base/gtest_prod_util.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/metrics/histogram_base.h"
#include "base/metrics/histogram_samples.h"
@@ -20,9 +24,15 @@ namespace base {
class BucketRanges;
-class BASE_EXPORT_PRIVATE SampleVector : public HistogramSamples {
+class BASE_EXPORT SampleVector : public HistogramSamples {
public:
explicit SampleVector(const BucketRanges* bucket_ranges);
+ SampleVector(uint64_t id, const BucketRanges* bucket_ranges);
+ SampleVector(uint64_t id,
+ HistogramBase::AtomicCount* counts,
+ size_t counts_size,
+ Metadata* meta,
+ const BucketRanges* bucket_ranges);
~SampleVector() override;
// HistogramSamples implementation:
@@ -45,7 +55,14 @@ class BASE_EXPORT_PRIVATE SampleVector : public HistogramSamples {
private:
FRIEND_TEST_ALL_PREFIXES(HistogramTest, CorruptSampleCounts);
- std::vector<HistogramBase::AtomicCount> counts_;
+ // In the case where this class manages the memory, here it is.
+ std::vector<HistogramBase::AtomicCount> local_counts_;
+
+ // These are raw pointers rather than objects for flexibility. The actual
+ // memory is either managed by local_counts_ above or by an external object
+ // and passed in directly.
+ HistogramBase::AtomicCount* counts_;
+ size_t counts_size_;
// Shares the same BucketRanges with Histogram object.
const BucketRanges* const bucket_ranges_;
@@ -53,10 +70,13 @@ class BASE_EXPORT_PRIVATE SampleVector : public HistogramSamples {
DISALLOW_COPY_AND_ASSIGN(SampleVector);
};
-class BASE_EXPORT_PRIVATE SampleVectorIterator : public SampleCountIterator {
+class BASE_EXPORT SampleVectorIterator : public SampleCountIterator {
public:
SampleVectorIterator(const std::vector<HistogramBase::AtomicCount>* counts,
const BucketRanges* bucket_ranges);
+ SampleVectorIterator(const HistogramBase::AtomicCount* counts,
+ size_t counts_size,
+ const BucketRanges* bucket_ranges);
~SampleVectorIterator() override;
// SampleCountIterator implementation:
@@ -72,7 +92,8 @@ class BASE_EXPORT_PRIVATE SampleVectorIterator : public SampleCountIterator {
private:
void SkipEmptyBuckets();
- const std::vector<HistogramBase::AtomicCount>* counts_;
+ const HistogramBase::AtomicCount* counts_;
+ size_t counts_size_;
const BucketRanges* bucket_ranges_;
size_t index_;
diff --git a/base/metrics/sample_vector_unittest.cc b/base/metrics/sample_vector_unittest.cc
index fd42376669..744cbfaba0 100644
--- a/base/metrics/sample_vector_unittest.cc
+++ b/base/metrics/sample_vector_unittest.cc
@@ -4,6 +4,9 @@
#include "base/metrics/sample_vector.h"
+#include <limits.h>
+#include <stddef.h>
+
#include <vector>
#include "base/memory/scoped_ptr.h"
@@ -20,7 +23,7 @@ TEST(SampleVectorTest, AccumulateTest) {
ranges.set_range(0, 1);
ranges.set_range(1, 5);
ranges.set_range(2, 10);
- SampleVector samples(&ranges);
+ SampleVector samples(1, &ranges);
samples.Accumulate(1, 200);
samples.Accumulate(2, -300);
@@ -50,7 +53,7 @@ TEST(SampleVectorTest, AddSubtractTest) {
ranges.set_range(3, 3);
ranges.set_range(4, INT_MAX);
- SampleVector samples1(&ranges);
+ SampleVector samples1(1, &ranges);
samples1.Accumulate(0, 100);
samples1.Accumulate(2, 100);
samples1.Accumulate(4, 100);
@@ -58,7 +61,7 @@ TEST(SampleVectorTest, AddSubtractTest) {
EXPECT_EQ(300, samples1.TotalCount());
EXPECT_EQ(samples1.redundant_count(), samples1.TotalCount());
- SampleVector samples2(&ranges);
+ SampleVector samples2(2, &ranges);
samples2.Accumulate(1, 200);
samples2.Accumulate(2, 200);
samples2.Accumulate(4, 200);
@@ -91,7 +94,7 @@ TEST(SampleVectorDeathTest, BucketIndexTest) {
// [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);
+ SampleVector samples(1, &ranges);
// Normal case
samples.Accumulate(0, 1);
@@ -113,7 +116,7 @@ TEST(SampleVectorDeathTest, BucketIndexTest) {
ranges2.set_range(0, 1);
ranges2.set_range(1, 5);
ranges2.set_range(2, 10);
- SampleVector samples2(&ranges2);
+ SampleVector samples2(2, &ranges2);
// Normal case.
samples2.Accumulate(1, 1);
@@ -134,7 +137,7 @@ TEST(SampleVectorDeathTest, AddSubtractBucketNotMatchTest) {
ranges1.set_range(0, 1);
ranges1.set_range(1, 3);
ranges1.set_range(2, 5);
- SampleVector samples1(&ranges1);
+ SampleVector samples1(1, &ranges1);
// Custom buckets 2: [0, 1) [1, 3) [3, 6) [6, 7)
BucketRanges ranges2(5);
@@ -143,7 +146,7 @@ TEST(SampleVectorDeathTest, AddSubtractBucketNotMatchTest) {
ranges2.set_range(2, 3);
ranges2.set_range(3, 6);
ranges2.set_range(4, 7);
- SampleVector samples2(&ranges2);
+ SampleVector samples2(2, &ranges2);
samples2.Accumulate(1, 100);
samples1.Add(samples2);
@@ -209,7 +212,7 @@ TEST(SampleVectorIteratorTest, IterateTest) {
EXPECT_TRUE(it.Done());
// Create iterator from SampleVector.
- SampleVector samples(&ranges);
+ SampleVector samples(1, &ranges);
samples.Accumulate(0, 0);
samples.Accumulate(1, 1);
samples.Accumulate(2, 2);
@@ -239,7 +242,7 @@ TEST(SampleVectorIteratorDeathTest, IterateDoneTest) {
ranges.set_range(2, 2);
ranges.set_range(3, 3);
ranges.set_range(4, INT_MAX);
- SampleVector samples(&ranges);
+ SampleVector samples(1, &ranges);
scoped_ptr<SampleCountIterator> it = samples.Iterator();
diff --git a/base/metrics/sparse_histogram.cc b/base/metrics/sparse_histogram.cc
index d5fd4a32be..37ea5e76b5 100644
--- a/base/metrics/sparse_histogram.cc
+++ b/base/metrics/sparse_histogram.cc
@@ -4,6 +4,9 @@
#include "base/metrics/sparse_histogram.h"
+#include <utility>
+
+#include "base/metrics/metrics_hashes.h"
#include "base/metrics/sample_map.h"
#include "base/metrics/statistics_recorder.h"
#include "base/pickle.h"
@@ -17,7 +20,7 @@ typedef HistogramBase::Sample Sample;
// static
HistogramBase* SparseHistogram::FactoryGet(const std::string& name,
- int32 flags) {
+ int32_t flags) {
HistogramBase* histogram = StatisticsRecorder::FindHistogram(name);
if (!histogram) {
@@ -33,6 +36,10 @@ HistogramBase* SparseHistogram::FactoryGet(const std::string& name,
SparseHistogram::~SparseHistogram() {}
+uint64_t SparseHistogram::name_hash() const {
+ return samples_.id();
+}
+
HistogramType SparseHistogram::GetHistogramType() const {
return SPARSE_HISTOGRAM;
}
@@ -46,16 +53,28 @@ bool SparseHistogram::HasConstructionArguments(
}
void SparseHistogram::Add(Sample value) {
- base::AutoLock auto_lock(lock_);
- samples_.Accumulate(value, 1);
+ AddCount(value, 1);
+}
+
+void SparseHistogram::AddCount(Sample value, int count) {
+ if (count <= 0) {
+ NOTREACHED();
+ return;
+ }
+ {
+ base::AutoLock auto_lock(lock_);
+ samples_.Accumulate(value, count);
+ }
+
+ FindAndRunCallback(value);
}
scoped_ptr<HistogramSamples> SparseHistogram::SnapshotSamples() const {
- scoped_ptr<SampleMap> snapshot(new SampleMap());
+ scoped_ptr<SampleMap> snapshot(new SampleMap(name_hash()));
base::AutoLock auto_lock(lock_);
snapshot->Add(samples_);
- return snapshot.Pass();
+ return std::move(snapshot);
}
void SparseHistogram::AddSamples(const HistogramSamples& samples) {
@@ -83,7 +102,8 @@ bool SparseHistogram::SerializeInfoImpl(Pickle* pickle) const {
}
SparseHistogram::SparseHistogram(const std::string& name)
- : HistogramBase(name) {}
+ : HistogramBase(name),
+ samples_(HashMetricName(name)) {}
HistogramBase* SparseHistogram::DeserializeInfoImpl(PickleIterator* iter) {
std::string histogram_name;
@@ -104,7 +124,7 @@ void SparseHistogram::GetParameters(DictionaryValue* /* params */) const {
}
void SparseHistogram::GetCountAndBucketData(Count* /* count */,
- int64* /* sum */,
+ int64_t* /* sum */,
ListValue* /* buckets */) const {
// TODO(kaiwang): Implement. (See HistogramBase::WriteJSON.)
}
diff --git a/base/metrics/sparse_histogram.h b/base/metrics/sparse_histogram.h
index a02da592d6..a77c020d4c 100644
--- a/base/metrics/sparse_histogram.h
+++ b/base/metrics/sparse_histogram.h
@@ -5,13 +5,16 @@
#ifndef BASE_METRICS_SPARSE_HISTOGRAM_H_
#define BASE_METRICS_SPARSE_HISTOGRAM_H_
+#include <stddef.h>
+#include <stdint.h>
+
#include <map>
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/metrics/histogram_base.h"
#include "base/metrics/sample_map.h"
@@ -28,20 +31,22 @@ namespace base {
class HistogramSamples;
-class BASE_EXPORT_PRIVATE SparseHistogram : public HistogramBase {
+class BASE_EXPORT 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);
+ static HistogramBase* FactoryGet(const std::string& name, int32_t flags);
~SparseHistogram() override;
// HistogramBase implementation:
+ uint64_t name_hash() const override;
HistogramType GetHistogramType() const override;
bool HasConstructionArguments(Sample expected_minimum,
Sample expected_maximum,
size_t expected_bucket_count) const override;
void Add(Sample value) override;
+ void AddCount(Sample value, int count) override;
void AddSamples(const HistogramSamples& samples) override;
bool AddSamplesFromPickle(base::PickleIterator* iter) override;
scoped_ptr<HistogramSamples> SnapshotSamples() const override;
@@ -56,13 +61,13 @@ class BASE_EXPORT_PRIVATE SparseHistogram : public HistogramBase {
// Clients should always use FactoryGet to create SparseHistogram.
explicit SparseHistogram(const std::string& name);
- friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
+ friend BASE_EXPORT HistogramBase* DeserializeHistogramInfo(
base::PickleIterator* iter);
static HistogramBase* DeserializeInfoImpl(base::PickleIterator* iter);
void GetParameters(DictionaryValue* params) const override;
void GetCountAndBucketData(Count* count,
- int64* sum,
+ int64_t* sum,
ListValue* buckets) const override;
// Helpers for emitting Ascii graphic. Each method appends data to output.
diff --git a/base/metrics/sparse_histogram_unittest.cc b/base/metrics/sparse_histogram_unittest.cc
index fca4d59e50..83cf5d3724 100644
--- a/base/metrics/sparse_histogram_unittest.cc
+++ b/base/metrics/sparse_histogram_unittest.cc
@@ -62,6 +62,25 @@ TEST_F(SparseHistogramTest, BasicTest) {
EXPECT_EQ(1, snapshot2->GetCount(101));
}
+TEST_F(SparseHistogramTest, BasicTestAddCount) {
+ scoped_ptr<SparseHistogram> histogram(NewSparseHistogram("Sparse"));
+ scoped_ptr<HistogramSamples> snapshot(histogram->SnapshotSamples());
+ EXPECT_EQ(0, snapshot->TotalCount());
+ EXPECT_EQ(0, snapshot->sum());
+
+ histogram->AddCount(100, 15);
+ scoped_ptr<HistogramSamples> snapshot1(histogram->SnapshotSamples());
+ EXPECT_EQ(15, snapshot1->TotalCount());
+ EXPECT_EQ(15, snapshot1->GetCount(100));
+
+ histogram->AddCount(100, 15);
+ histogram->AddCount(101, 25);
+ scoped_ptr<HistogramSamples> snapshot2(histogram->SnapshotSamples());
+ EXPECT_EQ(55, snapshot2->TotalCount());
+ EXPECT_EQ(30, snapshot2->GetCount(100));
+ EXPECT_EQ(25, snapshot2->GetCount(101));
+}
+
TEST_F(SparseHistogramTest, MacroBasicTest) {
UMA_HISTOGRAM_SPARSE_SLOWLY("Sparse", 100);
UMA_HISTOGRAM_SPARSE_SLOWLY("Sparse", 200);
diff --git a/base/metrics/statistics_recorder.cc b/base/metrics/statistics_recorder.cc
index fc952bfbe0..f8257f4f0c 100644
--- a/base/metrics/statistics_recorder.cc
+++ b/base/metrics/statistics_recorder.cc
@@ -9,6 +9,8 @@
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/metrics/histogram.h"
+#include "base/metrics/metrics_hashes.h"
+#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
#include "base/synchronization/lock.h"
#include "base/values.h"
@@ -51,15 +53,27 @@ HistogramBase* StatisticsRecorder::RegisterOrDeleteDuplicate(
histogram_to_return = histogram;
} else {
const std::string& name = histogram->histogram_name();
- HistogramMap::iterator it = histograms_->find(name);
+ uint64_t name_hash = histogram->name_hash();
+ HistogramMap::iterator it = histograms_->find(name_hash);
if (histograms_->end() == it) {
- (*histograms_)[name] = histogram;
+ (*histograms_)[name_hash] = histogram;
+ // If there are callbacks for this histogram, we set the kCallbackExists
+ // flag.
+ auto callback_iterator = callbacks_->find(name);
+ if (callback_iterator != callbacks_->end()) {
+ if (!callback_iterator->second.is_null())
+ histogram->SetFlags(HistogramBase::kCallbackExists);
+ else
+ histogram->ClearFlags(HistogramBase::kCallbackExists);
+ }
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.
+ DCHECK_EQ(histogram->histogram_name(),
+ it->second->histogram_name()) << "hash collision";
histogram_to_return = it->second;
histogram_to_delete = histogram;
}
@@ -180,7 +194,7 @@ void StatisticsRecorder::GetHistograms(Histograms* output) {
return;
for (const auto& entry : *histograms_) {
- DCHECK_EQ(entry.first, entry.second->histogram_name());
+ DCHECK_EQ(entry.first, entry.second->name_hash());
output->push_back(entry.second);
}
}
@@ -209,12 +223,69 @@ HistogramBase* StatisticsRecorder::FindHistogram(const std::string& name) {
if (histograms_ == NULL)
return NULL;
- HistogramMap::iterator it = histograms_->find(name);
+ HistogramMap::iterator it = histograms_->find(HashMetricName(name));
if (histograms_->end() == it)
return NULL;
+ DCHECK_EQ(name, it->second->histogram_name()) << "hash collision";
return it->second;
}
+// static
+bool StatisticsRecorder::SetCallback(
+ const std::string& name,
+ const StatisticsRecorder::OnSampleCallback& cb) {
+ DCHECK(!cb.is_null());
+ if (lock_ == NULL)
+ return false;
+ base::AutoLock auto_lock(*lock_);
+ if (histograms_ == NULL)
+ return false;
+
+ if (ContainsKey(*callbacks_, name))
+ return false;
+ callbacks_->insert(std::make_pair(name, cb));
+
+ HistogramMap::iterator it = histograms_->find(HashMetricName(name));
+ if (it != histograms_->end()) {
+ DCHECK_EQ(name, it->second->histogram_name()) << "hash collision";
+ it->second->SetFlags(HistogramBase::kCallbackExists);
+ }
+
+ return true;
+}
+
+// static
+void StatisticsRecorder::ClearCallback(const std::string& name) {
+ if (lock_ == NULL)
+ return;
+ base::AutoLock auto_lock(*lock_);
+ if (histograms_ == NULL)
+ return;
+
+ callbacks_->erase(name);
+
+ // We also clear the flag from the histogram (if it exists).
+ HistogramMap::iterator it = histograms_->find(HashMetricName(name));
+ if (it != histograms_->end()) {
+ DCHECK_EQ(name, it->second->histogram_name()) << "hash collision";
+ it->second->ClearFlags(HistogramBase::kCallbackExists);
+ }
+}
+
+// static
+StatisticsRecorder::OnSampleCallback StatisticsRecorder::FindCallback(
+ const std::string& name) {
+ if (lock_ == NULL)
+ return OnSampleCallback();
+ base::AutoLock auto_lock(*lock_);
+ if (histograms_ == NULL)
+ return OnSampleCallback();
+
+ auto callback_iterator = callbacks_->find(name);
+ return callback_iterator != callbacks_->end() ? callback_iterator->second
+ : OnSampleCallback();
+}
+
// private static
void StatisticsRecorder::GetSnapshot(const std::string& query,
Histograms* snapshot) {
@@ -225,7 +296,7 @@ void StatisticsRecorder::GetSnapshot(const std::string& query,
return;
for (const auto& entry : *histograms_) {
- if (entry.first.find(query) != std::string::npos)
+ if (entry.second->histogram_name().find(query) != std::string::npos)
snapshot->push_back(entry.second);
}
}
@@ -246,6 +317,7 @@ StatisticsRecorder::StatisticsRecorder() {
}
base::AutoLock auto_lock(*lock_);
histograms_ = new HistogramMap;
+ callbacks_ = new CallbackMap;
ranges_ = new RangesMap;
if (VLOG_IS_ON(1))
@@ -264,14 +336,17 @@ StatisticsRecorder::~StatisticsRecorder() {
// Clean up.
scoped_ptr<HistogramMap> histograms_deleter;
+ scoped_ptr<CallbackMap> callbacks_deleter;
scoped_ptr<RangesMap> 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_);
+ callbacks_deleter.reset(callbacks_);
ranges_deleter.reset(ranges_);
histograms_ = NULL;
+ callbacks_ = NULL;
ranges_ = NULL;
}
// We are going to leak the histograms and the ranges.
@@ -281,6 +356,8 @@ StatisticsRecorder::~StatisticsRecorder() {
// static
StatisticsRecorder::HistogramMap* StatisticsRecorder::histograms_ = NULL;
// static
+StatisticsRecorder::CallbackMap* StatisticsRecorder::callbacks_ = NULL;
+// static
StatisticsRecorder::RangesMap* StatisticsRecorder::ranges_ = NULL;
// static
base::Lock* StatisticsRecorder::lock_ = NULL;
diff --git a/base/metrics/statistics_recorder.h b/base/metrics/statistics_recorder.h
index b523057596..b1d182e93e 100644
--- a/base/metrics/statistics_recorder.h
+++ b/base/metrics/statistics_recorder.h
@@ -10,20 +10,23 @@
#ifndef BASE_METRICS_STATISTICS_RECORDER_H_
#define BASE_METRICS_STATISTICS_RECORDER_H_
+#include <stdint.h>
+
#include <list>
#include <map>
#include <string>
#include <vector>
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/callback.h"
#include "base/gtest_prod_util.h"
#include "base/lazy_instance.h"
+#include "base/macros.h"
+#include "base/metrics/histogram_base.h"
namespace base {
class BucketRanges;
-class HistogramBase;
class Lock;
class BASE_EXPORT StatisticsRecorder {
@@ -75,14 +78,37 @@ class BASE_EXPORT StatisticsRecorder {
// histograms).
static void GetSnapshot(const std::string& query, Histograms* snapshot);
+ typedef base::Callback<void(HistogramBase::Sample)> OnSampleCallback;
+
+ // SetCallback sets the callback to notify when a new sample is recorded on
+ // the histogram referred to by |histogram_name|. The call to this method can
+ // be be done before or after the histogram is created. This method is thread
+ // safe. The return value is whether or not the callback was successfully set.
+ static bool SetCallback(const std::string& histogram_name,
+ const OnSampleCallback& callback);
+
+ // ClearCallback clears any callback set on the histogram referred to by
+ // |histogram_name|. This method is thread safe.
+ static void ClearCallback(const std::string& histogram_name);
+
+ // FindCallback retrieves the callback for the histogram referred to by
+ // |histogram_name|, or a null callback if no callback exists for this
+ // histogram. This method is thread safe.
+ static OnSampleCallback FindCallback(const std::string& histogram_name);
+
private:
- // We keep all registered histograms in a map, from name to histogram.
- typedef std::map<std::string, HistogramBase*> HistogramMap;
+ // We keep all registered histograms in a map, indexed by the hash of the
+ // name of the histogram.
+ typedef std::map<uint64_t, HistogramBase*> HistogramMap;
+
+ // We keep a map of callbacks to histograms, so that as histograms are
+ // created, we can set the callback properly.
+ typedef std::map<std::string, OnSampleCallback> CallbackMap;
// 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<uint32, std::list<const BucketRanges*>*> RangesMap;
+ typedef std::map<uint32_t, std::list<const BucketRanges*>*> RangesMap;
friend struct DefaultLazyInstanceTraits<StatisticsRecorder>;
friend class HistogramBaseTest;
@@ -103,6 +129,7 @@ class BASE_EXPORT StatisticsRecorder {
static void DumpHistogramsToVlog(void* instance);
static HistogramMap* histograms_;
+ static CallbackMap* callbacks_;
static RangesMap* ranges_;
// Lock protects access to above maps.
diff --git a/base/metrics/statistics_recorder_unittest.cc b/base/metrics/statistics_recorder_unittest.cc
index d26df6901b..af5c1e7bbc 100644
--- a/base/metrics/statistics_recorder_unittest.cc
+++ b/base/metrics/statistics_recorder_unittest.cc
@@ -2,11 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stddef.h>
+
#include <vector>
+#include "base/bind.h"
#include "base/json/json_reader.h"
#include "base/memory/scoped_ptr.h"
-#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/metrics/sparse_histogram.h"
#include "base/metrics/statistics_recorder.h"
#include "base/values.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -70,7 +74,7 @@ TEST_F(StatisticsRecorderTest, NotInitialized) {
DeleteHistogram(histogram);
// RegisterOrDeleteDuplicateRanges is a no-op.
- BucketRanges* ranges = new BucketRanges(3);;
+ BucketRanges* ranges = new BucketRanges(3);
ranges->ResetChecksum();
EXPECT_EQ(ranges,
StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges));
@@ -81,9 +85,9 @@ TEST_F(StatisticsRecorderTest, NotInitialized) {
TEST_F(StatisticsRecorderTest, RegisterBucketRanges) {
std::vector<const BucketRanges*> registered_ranges;
- BucketRanges* ranges1 = new BucketRanges(3);;
+ BucketRanges* ranges1 = new BucketRanges(3);
ranges1->ResetChecksum();
- BucketRanges* ranges2 = new BucketRanges(4);;
+ BucketRanges* ranges2 = new BucketRanges(4);
ranges2->ResetChecksum();
// Register new ranges.
@@ -107,7 +111,7 @@ TEST_F(StatisticsRecorderTest, RegisterBucketRanges) {
EXPECT_EQ(0, ranges1->range(2));
// Register ranges with same values.
- BucketRanges* ranges3 = new BucketRanges(3);;
+ BucketRanges* ranges3 = new BucketRanges(3);
ranges3->ResetChecksum();
EXPECT_EQ(ranges1, // returning ranges1
StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges3));
@@ -261,8 +265,7 @@ TEST_F(StatisticsRecorderTest, ToJSON) {
std::string json(StatisticsRecorder::ToJSON(std::string()));
// Check for valid JSON.
- scoped_ptr<Value> root;
- root.reset(JSONReader::DeprecatedRead(json));
+ scoped_ptr<Value> root = JSONReader::Read(json);
ASSERT_TRUE(root.get());
DictionaryValue* root_dict = NULL;
@@ -287,7 +290,7 @@ TEST_F(StatisticsRecorderTest, ToJSON) {
std::string query("TestHistogram2");
json = StatisticsRecorder::ToJSON(query);
- root.reset(JSONReader::DeprecatedRead(json));
+ root = JSONReader::Read(json);
ASSERT_TRUE(root.get());
ASSERT_TRUE(root->GetAsDictionary(&root_dict));
@@ -312,4 +315,178 @@ TEST_F(StatisticsRecorderTest, ToJSON) {
EXPECT_TRUE(json.empty());
}
+namespace {
+
+// CallbackCheckWrapper is simply a convenient way to check and store that
+// a callback was actually run.
+struct CallbackCheckWrapper {
+ CallbackCheckWrapper() : called(false), last_histogram_value(0) {}
+
+ void OnHistogramChanged(base::HistogramBase::Sample histogram_value) {
+ called = true;
+ last_histogram_value = histogram_value;
+ }
+
+ bool called;
+ base::HistogramBase::Sample last_histogram_value;
+};
+
+} // namespace
+
+// Check that you can't overwrite the callback with another.
+TEST_F(StatisticsRecorderTest, SetCallbackFailsWithoutHistogramTest) {
+ CallbackCheckWrapper callback_wrapper;
+
+ bool result = base::StatisticsRecorder::SetCallback(
+ "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
+ base::Unretained(&callback_wrapper)));
+ EXPECT_TRUE(result);
+
+ result = base::StatisticsRecorder::SetCallback(
+ "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
+ base::Unretained(&callback_wrapper)));
+ EXPECT_FALSE(result);
+}
+
+// Check that you can't overwrite the callback with another.
+TEST_F(StatisticsRecorderTest, SetCallbackFailsWithHistogramTest) {
+ HistogramBase* histogram = Histogram::FactoryGet("TestHistogram", 1, 1000, 10,
+ HistogramBase::kNoFlags);
+ EXPECT_TRUE(histogram);
+
+ CallbackCheckWrapper callback_wrapper;
+
+ bool result = base::StatisticsRecorder::SetCallback(
+ "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
+ base::Unretained(&callback_wrapper)));
+ EXPECT_TRUE(result);
+ EXPECT_EQ(histogram->flags() & base::HistogramBase::kCallbackExists,
+ base::HistogramBase::kCallbackExists);
+
+ result = base::StatisticsRecorder::SetCallback(
+ "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
+ base::Unretained(&callback_wrapper)));
+ EXPECT_FALSE(result);
+ EXPECT_EQ(histogram->flags() & base::HistogramBase::kCallbackExists,
+ base::HistogramBase::kCallbackExists);
+
+ histogram->Add(1);
+
+ EXPECT_TRUE(callback_wrapper.called);
+}
+
+// Check that you can't overwrite the callback with another.
+TEST_F(StatisticsRecorderTest, ClearCallbackSuceedsWithHistogramTest) {
+ HistogramBase* histogram = Histogram::FactoryGet("TestHistogram", 1, 1000, 10,
+ HistogramBase::kNoFlags);
+ EXPECT_TRUE(histogram);
+
+ CallbackCheckWrapper callback_wrapper;
+
+ bool result = base::StatisticsRecorder::SetCallback(
+ "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
+ base::Unretained(&callback_wrapper)));
+ EXPECT_TRUE(result);
+ EXPECT_EQ(histogram->flags() & base::HistogramBase::kCallbackExists,
+ base::HistogramBase::kCallbackExists);
+
+ base::StatisticsRecorder::ClearCallback("TestHistogram");
+ EXPECT_EQ(histogram->flags() & base::HistogramBase::kCallbackExists, 0);
+
+ histogram->Add(1);
+
+ EXPECT_FALSE(callback_wrapper.called);
+}
+
+// Check that callback is used.
+TEST_F(StatisticsRecorderTest, CallbackUsedTest) {
+ {
+ HistogramBase* histogram = Histogram::FactoryGet(
+ "TestHistogram", 1, 1000, 10, HistogramBase::kNoFlags);
+ EXPECT_TRUE(histogram);
+
+ CallbackCheckWrapper callback_wrapper;
+
+ base::StatisticsRecorder::SetCallback(
+ "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
+ base::Unretained(&callback_wrapper)));
+
+ histogram->Add(1);
+
+ EXPECT_TRUE(callback_wrapper.called);
+ EXPECT_EQ(callback_wrapper.last_histogram_value, 1);
+ }
+
+ {
+ HistogramBase* linear_histogram = LinearHistogram::FactoryGet(
+ "TestLinearHistogram", 1, 1000, 10, HistogramBase::kNoFlags);
+
+ CallbackCheckWrapper callback_wrapper;
+
+ base::StatisticsRecorder::SetCallback(
+ "TestLinearHistogram",
+ base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
+ base::Unretained(&callback_wrapper)));
+
+ linear_histogram->Add(1);
+
+ EXPECT_TRUE(callback_wrapper.called);
+ EXPECT_EQ(callback_wrapper.last_histogram_value, 1);
+ }
+
+ {
+ std::vector<int> custom_ranges;
+ custom_ranges.push_back(1);
+ custom_ranges.push_back(5);
+ HistogramBase* custom_histogram = CustomHistogram::FactoryGet(
+ "TestCustomHistogram", custom_ranges, HistogramBase::kNoFlags);
+
+ CallbackCheckWrapper callback_wrapper;
+
+ base::StatisticsRecorder::SetCallback(
+ "TestCustomHistogram",
+ base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
+ base::Unretained(&callback_wrapper)));
+
+ custom_histogram->Add(1);
+
+ EXPECT_TRUE(callback_wrapper.called);
+ EXPECT_EQ(callback_wrapper.last_histogram_value, 1);
+ }
+
+ {
+ HistogramBase* custom_histogram = SparseHistogram::FactoryGet(
+ "TestSparseHistogram", HistogramBase::kNoFlags);
+
+ CallbackCheckWrapper callback_wrapper;
+
+ base::StatisticsRecorder::SetCallback(
+ "TestSparseHistogram",
+ base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
+ base::Unretained(&callback_wrapper)));
+
+ custom_histogram->Add(1);
+
+ EXPECT_TRUE(callback_wrapper.called);
+ EXPECT_EQ(callback_wrapper.last_histogram_value, 1);
+ }
+}
+
+// Check that setting a callback before the histogram exists works.
+TEST_F(StatisticsRecorderTest, CallbackUsedBeforeHistogramCreatedTest) {
+ CallbackCheckWrapper callback_wrapper;
+
+ base::StatisticsRecorder::SetCallback(
+ "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
+ base::Unretained(&callback_wrapper)));
+
+ HistogramBase* histogram = Histogram::FactoryGet("TestHistogram", 1, 1000, 10,
+ HistogramBase::kNoFlags);
+ EXPECT_TRUE(histogram);
+ histogram->Add(1);
+
+ EXPECT_TRUE(callback_wrapper.called);
+ EXPECT_EQ(callback_wrapper.last_histogram_value, 1);
+}
+
} // namespace base
diff --git a/base/move.h b/base/move.h
index 87dc52d16c..24bf9d7545 100644
--- a/base/move.h
+++ b/base/move.h
@@ -5,230 +5,53 @@
#ifndef BASE_MOVE_H_
#define BASE_MOVE_H_
+#include <utility>
+
#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "build/build_config.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 <typename T>
-// 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<RValue*>(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.
-//
+// TODO(crbug.com/566182): DEPRECATED!
+// Use DISALLOW_COPY_AND_ASSIGN instead, or if your type will be used in
+// Callbacks, use DISALLOW_COPY_AND_ASSIGN_WITH_MOVE_FOR_BIND instead.
+#define MOVE_ONLY_TYPE_FOR_CPP_03(type) \
+ DISALLOW_COPY_AND_ASSIGN_WITH_MOVE_FOR_BIND(type)
+
+// A macro to disallow the copy constructor and copy assignment functions.
+// This should be used in the private: declarations for a class.
//
-// WHY HAVE typedef void MoveOnlyTypeForCPP03
+// Use this macro instead of DISALLOW_COPY_AND_ASSIGN if you want to pass
+// ownership of the type through a base::Callback without heap-allocating it
+// into a scoped_ptr. The class must define a move constructor and move
+// assignment operator to make this work.
//
-// Callback<>/Bind() needs to understand movable-but-not-copyable semantics
-// to call .Pass() appropriately when it is expected to transfer the value.
-// The cryptic typedef MoveOnlyTypeForCPP03 is added to make this check
-// easy and automatic in helper templates for Callback<>/Bind().
+// This version of the macro adds a Pass() function and a cryptic
+// MoveOnlyTypeForCPP03 typedef for the base::Callback implementation to use.
// See IsMoveOnlyType template and its usage in base/callback_internal.h
// for more details.
-//
-//
-// 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<Parent> p)" accept a
-// value of type scoped_ptr<Child> 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<Foo>& 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() WARN_UNUSED_RESULT { return type(rvalue_type(this)); } \
- typedef void MoveOnlyTypeForCPP03; \
+// TODO(crbug.com/566182): Remove this macro and use DISALLOW_COPY_AND_ASSIGN
+// everywhere instead.
+#if defined(OS_ANDROID) || defined(OS_LINUX)
+#define DISALLOW_COPY_AND_ASSIGN_WITH_MOVE_FOR_BIND(type) \
+ private: \
+ type(const type&) = delete; \
+ void operator=(const type&) = delete; \
+ \
+ public: \
+ typedef void MoveOnlyTypeForCPP03; \
+ \
private:
-
-#define MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(type) \
- private: \
- type(const type&); \
- void operator=(const type&); \
- public: \
- type&& Pass() WARN_UNUSED_RESULT { return static_cast<type&&>(*this); } \
- typedef void MoveOnlyTypeForCPP03; \
- private:
-
-#define TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(type) \
- public: \
- type&& Pass() WARN_UNUSED_RESULT { return static_cast<type&&>(*this); } \
+#else
+#define DISALLOW_COPY_AND_ASSIGN_WITH_MOVE_FOR_BIND(type) \
+ private: \
+ type(const type&) = delete; \
+ void operator=(const type&) = delete; \
+ \
+ public: \
+ type&& Pass() WARN_UNUSED_RESULT { return std::move(*this); } \
+ typedef void MoveOnlyTypeForCPP03; \
+ \
private:
+#endif
#endif // BASE_MOVE_H_
diff --git a/base/move_unittest.cc b/base/move_unittest.cc
deleted file mode 100644
index 1f4ce84cb6..0000000000
--- a/base/move_unittest.cc
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright (c) 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/move.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-
-class MoveOnly {
- MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(MoveOnly)
-
- public:
- MoveOnly() {}
-
- MoveOnly(MoveOnly&& other) {}
- MoveOnly& operator=(MoveOnly&& other) { return *this; }
-};
-
-class Container {
- public:
- Container() = default;
- Container(const Container& other) = default;
- Container& operator=(const Container& other) = default;
-
- Container(Container&& other) { value_ = other.value_.Pass(); }
-
- Container& operator=(Container&& other) {
- value_ = other.value_.Pass();
- return *this;
- }
-
- private:
- MoveOnly value_;
-};
-
-Container GetContainerRvalue() {
- Container x;
- return x;
-}
-
-TEST(MoveTest, CopyableContainerCanBeMoved) {
- // Container should be move-constructible and move-assignable.
- Container y = GetContainerRvalue();
- y = GetContainerRvalue();
-}
-
-} // namespace
diff --git a/base/numerics/safe_conversions.h b/base/numerics/safe_conversions.h
index 5dd5191959..baac188fd2 100644
--- a/base/numerics/safe_conversions.h
+++ b/base/numerics/safe_conversions.h
@@ -5,7 +5,10 @@
#ifndef BASE_NUMERICS_SAFE_CONVERSIONS_H_
#define BASE_NUMERICS_SAFE_CONVERSIONS_H_
+#include <stddef.h>
+
#include <limits>
+#include <type_traits>
#include "base/logging.h"
#include "base/numerics/safe_conversions_impl.h"
@@ -20,6 +23,24 @@ inline bool IsValueInRangeForNumericType(Src value) {
internal::RANGE_VALID;
}
+// Convenience function for determining if a numeric value is negative without
+// throwing compiler warnings on: unsigned(value) < 0.
+template <typename T>
+typename std::enable_if<std::numeric_limits<T>::is_signed, bool>::type
+IsValueNegative(T value) {
+ static_assert(std::numeric_limits<T>::is_specialized,
+ "Argument must be numeric.");
+ return value < 0;
+}
+
+template <typename T>
+typename std::enable_if<!std::numeric_limits<T>::is_signed, bool>::type
+ IsValueNegative(T) {
+ static_assert(std::numeric_limits<T>::is_specialized,
+ "Argument must be numeric.");
+ return false;
+}
+
// checked_cast<> is analogous to static_cast<> for numeric types,
// except that it CHECKs that the specified numeric conversion will not
// overflow or underflow. NaN source will always trigger a CHECK.
@@ -29,10 +50,30 @@ inline Dst checked_cast(Src value) {
return static_cast<Dst>(value);
}
+// HandleNaN will cause this class to CHECK(false).
+struct SaturatedCastNaNBehaviorCheck {
+ template <typename T>
+ static T HandleNaN() {
+ CHECK(false);
+ return T();
+ }
+};
+
+// HandleNaN will return 0 in this case.
+struct SaturatedCastNaNBehaviorReturnZero {
+ template <typename T>
+ static T HandleNaN() {
+ return T();
+ }
+};
+
// saturated_cast<> is analogous to static_cast<> for numeric types, except
// that the specified numeric conversion will saturate rather than overflow or
-// underflow. NaN assignment to an integral will trigger a CHECK condition.
-template <typename Dst, typename Src>
+// underflow. NaN assignment to an integral will defer the behavior to a
+// specified class. By default, it will return 0.
+template <typename Dst,
+ class NaNHandler = SaturatedCastNaNBehaviorReturnZero,
+ typename Src>
inline Dst saturated_cast(Src value) {
// Optimization for floating point values, which already saturate.
if (std::numeric_limits<Dst>::is_iec559)
@@ -50,8 +91,7 @@ inline Dst saturated_cast(Src value) {
// Should fail only on attempting to assign NaN to a saturated integer.
case internal::RANGE_INVALID:
- CHECK(false);
- return std::numeric_limits<Dst>::max();
+ return NaNHandler::template HandleNaN<Dst>();
}
NOTREACHED();
diff --git a/base/numerics/safe_conversions_impl.h b/base/numerics/safe_conversions_impl.h
index 3db045f568..181dd7e4f5 100644
--- a/base/numerics/safe_conversions_impl.h
+++ b/base/numerics/safe_conversions_impl.h
@@ -5,6 +5,9 @@
#ifndef BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
#define BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
+#include <limits.h>
+#include <stdint.h>
+
#include <limits>
#include "base/template_util.h"
@@ -108,6 +111,55 @@ inline RangeConstraint GetRangeConstraint(bool is_in_upper_bound,
(is_in_lower_bound ? 0 : RANGE_UNDERFLOW));
}
+// The following helper template addresses a corner case in range checks for
+// conversion from a floating-point type to an integral type of smaller range
+// but larger precision (e.g. float -> unsigned). The problem is as follows:
+// 1. Integral maximum is always one less than a power of two, so it must be
+// truncated to fit the mantissa of the floating point. The direction of
+// rounding is implementation defined, but by default it's always IEEE
+// floats, which round to nearest and thus result in a value of larger
+// magnitude than the integral value.
+// Example: float f = UINT_MAX; // f is 4294967296f but UINT_MAX
+// // is 4294967295u.
+// 2. If the floating point value is equal to the promoted integral maximum
+// value, a range check will erroneously pass.
+// Example: (4294967296f <= 4294967295u) // This is true due to a precision
+// // loss in rounding up to float.
+// 3. When the floating point value is then converted to an integral, the
+// resulting value is out of range for the target integral type and
+// thus is implementation defined.
+// Example: unsigned u = (float)INT_MAX; // u will typically overflow to 0.
+// To fix this bug we manually truncate the maximum value when the destination
+// type is an integral of larger precision than the source floating-point type,
+// such that the resulting maximum is represented exactly as a floating point.
+template <typename Dst, typename Src>
+struct NarrowingRange {
+ typedef typename std::numeric_limits<Src> SrcLimits;
+ typedef typename std::numeric_limits<Dst> DstLimits;
+
+ static Dst max() {
+ // The following logic avoids warnings where the max function is
+ // instantiated with invalid values for a bit shift (even though
+ // such a function can never be called).
+ static const int shift =
+ (MaxExponent<Src>::value > MaxExponent<Dst>::value &&
+ SrcLimits::digits < DstLimits::digits && SrcLimits::is_iec559 &&
+ DstLimits::is_integer)
+ ? (DstLimits::digits - SrcLimits::digits)
+ : 0;
+
+ // We use UINTMAX_C below to avoid compiler warnings about shifting floating
+ // points. Since it's a compile time calculation, it shouldn't have any
+ // performance impact.
+ return DstLimits::max() - static_cast<Dst>((UINTMAX_C(1) << shift) - 1);
+ }
+
+ static Dst min() {
+ return std::numeric_limits<Dst>::is_iec559 ? -DstLimits::max()
+ : DstLimits::min();
+ }
+};
+
template <
typename Dst,
typename Src,
@@ -147,11 +199,8 @@ struct DstRangeRelationToSrcRangeImpl<Dst,
INTEGER_REPRESENTATION_SIGNED,
NUMERIC_RANGE_NOT_CONTAINED> {
static RangeConstraint Check(Src value) {
- return std::numeric_limits<Dst>::is_iec559
- ? GetRangeConstraint((value < std::numeric_limits<Dst>::max()),
- (value > -std::numeric_limits<Dst>::max()))
- : GetRangeConstraint((value < std::numeric_limits<Dst>::max()),
- (value > std::numeric_limits<Dst>::min()));
+ return GetRangeConstraint((value <= NarrowingRange<Dst, Src>::max()),
+ (value >= NarrowingRange<Dst, Src>::min()));
}
};
@@ -163,7 +212,7 @@ struct DstRangeRelationToSrcRangeImpl<Dst,
INTEGER_REPRESENTATION_UNSIGNED,
NUMERIC_RANGE_NOT_CONTAINED> {
static RangeConstraint Check(Src value) {
- return GetRangeConstraint(value < std::numeric_limits<Dst>::max(), true);
+ return GetRangeConstraint(value <= NarrowingRange<Dst, Src>::max(), true);
}
};
@@ -178,7 +227,7 @@ struct DstRangeRelationToSrcRangeImpl<Dst,
return sizeof(Dst) > sizeof(Src)
? RANGE_VALID
: GetRangeConstraint(
- value < static_cast<Src>(std::numeric_limits<Dst>::max()),
+ value <= static_cast<Src>(NarrowingRange<Dst, Src>::max()),
true);
}
};
@@ -195,7 +244,7 @@ struct DstRangeRelationToSrcRangeImpl<Dst,
return (MaxExponent<Dst>::value >= MaxExponent<Src>::value)
? GetRangeConstraint(true, value >= static_cast<Src>(0))
: GetRangeConstraint(
- value < static_cast<Src>(std::numeric_limits<Dst>::max()),
+ value <= static_cast<Src>(NarrowingRange<Dst, Src>::max()),
value >= static_cast<Src>(0));
}
};
diff --git a/base/numerics/safe_math.h b/base/numerics/safe_math.h
index 1fab032af0..d169690a82 100644
--- a/base/numerics/safe_math.h
+++ b/base/numerics/safe_math.h
@@ -5,6 +5,8 @@
#ifndef BASE_NUMERICS_SAFE_MATH_H_
#define BASE_NUMERICS_SAFE_MATH_H_
+#include <stddef.h>
+
#include "base/numerics/safe_math_impl.h"
namespace base {
@@ -36,9 +38,8 @@ namespace internal {
// CheckedNumeric<int> checked_int = untrusted_input_value;
// int x = checked_int.ValueOrDefault(0) | kFlagValues;
// Comparison:
-// CheckedNumeric<size_t> checked_size;
-// CheckedNumeric<int> checked_size = untrusted_input_value;
-// checked_size = checked_size + HEADER LENGTH;
+// CheckedNumeric<size_t> checked_size = untrusted_input_value;
+// checked_size += HEADER LENGTH;
// if (checked_size.IsValid() && checked_size.ValueOrDie() < buffer_size)
// Do stuff...
template <typename T>
@@ -145,6 +146,14 @@ class CheckedNumeric {
return CheckedNumeric<T>(value, validity);
}
+ // This function is available only for integral types. It returns an unsigned
+ // integer of the same width as the source type, containing the absolute value
+ // of the source, and properly handling signed min.
+ CheckedNumeric<typename UnsignedOrFloatForSize<T>::type> UnsignedAbs() const {
+ return CheckedNumeric<typename UnsignedOrFloatForSize<T>::type>(
+ CheckedUnsignedAbs(state_.value()), state_.validity());
+ }
+
CheckedNumeric& operator++() {
*this += 1;
return *this;
@@ -173,21 +182,31 @@ class CheckedNumeric {
template <typename Src>
static CheckedNumeric<T> cast(
Src u,
- typename enable_if<std::numeric_limits<Src>::is_specialized, int>::type =
- 0) {
+ typename std::enable_if<std::numeric_limits<Src>::is_specialized,
+ int>::type = 0) {
return u;
}
template <typename Src>
static CheckedNumeric<T> cast(
const CheckedNumeric<Src>& u,
- typename enable_if<!is_same<Src, T>::value, int>::type = 0) {
+ typename std::enable_if<!is_same<Src, T>::value, int>::type = 0) {
return u;
}
static const CheckedNumeric<T>& cast(const CheckedNumeric<T>& u) { return u; }
private:
+ template <typename NumericType>
+ struct UnderlyingType {
+ using type = NumericType;
+ };
+
+ template <typename NumericType>
+ struct UnderlyingType<CheckedNumeric<NumericType>> {
+ using type = NumericType;
+ };
+
CheckedNumericState<T> state_;
};
@@ -224,7 +243,8 @@ class CheckedNumeric {
template <typename T> \
template <typename Src> \
CheckedNumeric<T>& CheckedNumeric<T>::operator COMPOUND_OP(Src rhs) { \
- *this = CheckedNumeric<T>::cast(*this) OP CheckedNumeric<Src>::cast(rhs); \
+ *this = CheckedNumeric<T>::cast(*this) \
+ OP CheckedNumeric<typename UnderlyingType<Src>::type>::cast(rhs); \
return *this; \
} \
/* Binary arithmetic operator for CheckedNumeric of different type. */ \
diff --git a/base/numerics/safe_math_impl.h b/base/numerics/safe_math_impl.h
index 2ed64ae472..f5ec2b8829 100644
--- a/base/numerics/safe_math_impl.h
+++ b/base/numerics/safe_math_impl.h
@@ -5,11 +5,13 @@
#ifndef BASE_NUMERICS_SAFE_MATH_IMPL_H_
#define BASE_NUMERICS_SAFE_MATH_IMPL_H_
+#include <stddef.h>
#include <stdint.h>
#include <cmath>
#include <cstdlib>
#include <limits>
+#include <type_traits>
#include "base/numerics/safe_conversions.h"
#include "base/template_util.h"
@@ -63,21 +65,21 @@ struct IntegerForSizeAndSign<8, false> {
template <typename Integer>
struct UnsignedIntegerForSize {
- typedef typename enable_if<
+ typedef typename std::enable_if<
std::numeric_limits<Integer>::is_integer,
typename IntegerForSizeAndSign<sizeof(Integer), false>::type>::type type;
};
template <typename Integer>
struct SignedIntegerForSize {
- typedef typename enable_if<
+ typedef typename std::enable_if<
std::numeric_limits<Integer>::is_integer,
typename IntegerForSizeAndSign<sizeof(Integer), true>::type>::type type;
};
template <typename Integer>
struct TwiceWiderInteger {
- typedef typename enable_if<
+ typedef typename std::enable_if<
std::numeric_limits<Integer>::is_integer,
typename IntegerForSizeAndSign<
sizeof(Integer) * 2,
@@ -86,8 +88,28 @@ struct TwiceWiderInteger {
template <typename Integer>
struct PositionOfSignBit {
- static const typename enable_if<std::numeric_limits<Integer>::is_integer,
- size_t>::type value = 8 * sizeof(Integer) - 1;
+ static const typename std::enable_if<std::numeric_limits<Integer>::is_integer,
+ size_t>::type value =
+ 8 * sizeof(Integer) - 1;
+};
+
+// This is used for UnsignedAbs, where we need to support floating-point
+// template instantiations even though we don't actually support the operations.
+// However, there is no corresponding implementation of e.g. CheckedUnsignedAbs,
+// so the float versions will not compile.
+template <typename Numeric,
+ bool IsInteger = std::numeric_limits<Numeric>::is_integer,
+ bool IsFloat = std::numeric_limits<Numeric>::is_iec559>
+struct UnsignedOrFloatForSize;
+
+template <typename Numeric>
+struct UnsignedOrFloatForSize<Numeric, true, false> {
+ typedef typename UnsignedIntegerForSize<Numeric>::type type;
+};
+
+template <typename Numeric>
+struct UnsignedOrFloatForSize<Numeric, false, true> {
+ typedef Numeric type;
};
// Helper templates for integer manipulations.
@@ -110,7 +132,7 @@ T BinaryComplement(T x) {
// way to coalesce things into the CheckedNumericState specializations below.
template <typename T>
-typename enable_if<std::numeric_limits<T>::is_integer, T>::type
+typename std::enable_if<std::numeric_limits<T>::is_integer, T>::type
CheckedAdd(T x, T y, RangeConstraint* validity) {
// Since the value of x+y is undefined if we have a signed type, we compute
// it using the unsigned type of the same size.
@@ -133,7 +155,7 @@ CheckedAdd(T x, T y, RangeConstraint* validity) {
}
template <typename T>
-typename enable_if<std::numeric_limits<T>::is_integer, T>::type
+typename std::enable_if<std::numeric_limits<T>::is_integer, T>::type
CheckedSub(T x, T y, RangeConstraint* validity) {
// Since the value of x+y is undefined if we have a signed type, we compute
// it using the unsigned type of the same size.
@@ -160,9 +182,9 @@ CheckedSub(T x, T y, RangeConstraint* validity) {
// slow case we need to manually check that the result won't be truncated by
// checking with division against the appropriate bound.
template <typename T>
-typename enable_if<
- std::numeric_limits<T>::is_integer && sizeof(T) * 2 <= sizeof(uintmax_t),
- T>::type
+typename std::enable_if<std::numeric_limits<T>::is_integer &&
+ sizeof(T) * 2 <= sizeof(uintmax_t),
+ T>::type
CheckedMul(T x, T y, RangeConstraint* validity) {
typedef typename TwiceWiderInteger<T>::type IntermediateType;
IntermediateType tmp =
@@ -172,9 +194,10 @@ CheckedMul(T x, T y, RangeConstraint* validity) {
}
template <typename T>
-typename enable_if<std::numeric_limits<T>::is_integer&& std::numeric_limits<
- T>::is_signed&&(sizeof(T) * 2 > sizeof(uintmax_t)),
- T>::type
+typename std::enable_if<std::numeric_limits<T>::is_integer &&
+ std::numeric_limits<T>::is_signed &&
+ (sizeof(T) * 2 > sizeof(uintmax_t)),
+ T>::type
CheckedMul(T x, T y, RangeConstraint* validity) {
// If either side is zero then the result will be zero.
if (!x || !y) {
@@ -201,10 +224,10 @@ CheckedMul(T x, T y, RangeConstraint* validity) {
}
template <typename T>
-typename enable_if<std::numeric_limits<T>::is_integer &&
- !std::numeric_limits<T>::is_signed &&
- (sizeof(T) * 2 > sizeof(uintmax_t)),
- T>::type
+typename std::enable_if<std::numeric_limits<T>::is_integer &&
+ !std::numeric_limits<T>::is_signed &&
+ (sizeof(T) * 2 > sizeof(uintmax_t)),
+ T>::type
CheckedMul(T x, T y, RangeConstraint* validity) {
*validity = (y == 0 || x <= std::numeric_limits<T>::max() / y)
? RANGE_VALID
@@ -214,11 +237,11 @@ CheckedMul(T x, T y, RangeConstraint* validity) {
// Division just requires a check for an invalid negation on signed min/-1.
template <typename T>
-T CheckedDiv(
- T x,
- T y,
- RangeConstraint* validity,
- typename enable_if<std::numeric_limits<T>::is_integer, int>::type = 0) {
+T CheckedDiv(T x,
+ T y,
+ RangeConstraint* validity,
+ typename std::enable_if<std::numeric_limits<T>::is_integer,
+ int>::type = 0) {
if (std::numeric_limits<T>::is_signed && x == std::numeric_limits<T>::min() &&
y == static_cast<T>(-1)) {
*validity = RANGE_OVERFLOW;
@@ -230,27 +253,27 @@ T CheckedDiv(
}
template <typename T>
-typename enable_if<
- std::numeric_limits<T>::is_integer&& std::numeric_limits<T>::is_signed,
- T>::type
+typename std::enable_if<std::numeric_limits<T>::is_integer &&
+ std::numeric_limits<T>::is_signed,
+ T>::type
CheckedMod(T x, T y, RangeConstraint* validity) {
*validity = y > 0 ? RANGE_VALID : RANGE_INVALID;
return x % y;
}
template <typename T>
-typename enable_if<
- std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed,
- T>::type
+typename std::enable_if<std::numeric_limits<T>::is_integer &&
+ !std::numeric_limits<T>::is_signed,
+ T>::type
CheckedMod(T x, T y, RangeConstraint* validity) {
*validity = RANGE_VALID;
return x % y;
}
template <typename T>
-typename enable_if<
- std::numeric_limits<T>::is_integer&& std::numeric_limits<T>::is_signed,
- T>::type
+typename std::enable_if<std::numeric_limits<T>::is_integer &&
+ std::numeric_limits<T>::is_signed,
+ T>::type
CheckedNeg(T value, RangeConstraint* validity) {
*validity =
value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW;
@@ -259,9 +282,9 @@ CheckedNeg(T value, RangeConstraint* validity) {
}
template <typename T>
-typename enable_if<
- std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed,
- T>::type
+typename std::enable_if<std::numeric_limits<T>::is_integer &&
+ !std::numeric_limits<T>::is_signed,
+ T>::type
CheckedNeg(T value, RangeConstraint* validity) {
// The only legal unsigned negation is zero.
*validity = value ? RANGE_UNDERFLOW : RANGE_VALID;
@@ -270,9 +293,9 @@ CheckedNeg(T value, RangeConstraint* validity) {
}
template <typename T>
-typename enable_if<
- std::numeric_limits<T>::is_integer&& std::numeric_limits<T>::is_signed,
- T>::type
+typename std::enable_if<std::numeric_limits<T>::is_integer &&
+ std::numeric_limits<T>::is_signed,
+ T>::type
CheckedAbs(T value, RangeConstraint* validity) {
*validity =
value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW;
@@ -280,23 +303,43 @@ CheckedAbs(T value, RangeConstraint* validity) {
}
template <typename T>
-typename enable_if<
- std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed,
- T>::type
+typename std::enable_if<std::numeric_limits<T>::is_integer &&
+ !std::numeric_limits<T>::is_signed,
+ T>::type
CheckedAbs(T value, RangeConstraint* validity) {
- // Absolute value of a positive is just its identiy.
+ // T is unsigned, so |value| must already be positive.
*validity = RANGE_VALID;
return value;
}
+template <typename T>
+typename std::enable_if<std::numeric_limits<T>::is_integer &&
+ std::numeric_limits<T>::is_signed,
+ typename UnsignedIntegerForSize<T>::type>::type
+CheckedUnsignedAbs(T value) {
+ typedef typename UnsignedIntegerForSize<T>::type UnsignedT;
+ return value == std::numeric_limits<T>::min()
+ ? static_cast<UnsignedT>(std::numeric_limits<T>::max()) + 1
+ : static_cast<UnsignedT>(std::abs(value));
+}
+
+template <typename T>
+typename std::enable_if<std::numeric_limits<T>::is_integer &&
+ !std::numeric_limits<T>::is_signed,
+ T>::type
+CheckedUnsignedAbs(T value) {
+ // T is unsigned, so |value| must already be positive.
+ return value;
+}
+
// These are the floating point stubs that the compiler needs to see. Only the
// negation operation is ever called.
-#define BASE_FLOAT_ARITHMETIC_STUBS(NAME) \
- template <typename T> \
- typename enable_if<std::numeric_limits<T>::is_iec559, T>::type \
- Checked##NAME(T, T, RangeConstraint*) { \
- NOTREACHED(); \
- return 0; \
+#define BASE_FLOAT_ARITHMETIC_STUBS(NAME) \
+ template <typename T> \
+ typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type \
+ Checked##NAME(T, T, RangeConstraint*) { \
+ NOTREACHED(); \
+ return 0; \
}
BASE_FLOAT_ARITHMETIC_STUBS(Add)
@@ -308,14 +351,14 @@ BASE_FLOAT_ARITHMETIC_STUBS(Mod)
#undef BASE_FLOAT_ARITHMETIC_STUBS
template <typename T>
-typename enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedNeg(
+typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedNeg(
T value,
RangeConstraint*) {
return -value;
}
template <typename T>
-typename enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedAbs(
+typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedAbs(
T value,
RangeConstraint*) {
return std::abs(value);
@@ -375,8 +418,8 @@ class CheckedNumericState<T, NUMERIC_INTEGER> {
template <typename Src>
explicit CheckedNumericState(
Src value,
- typename enable_if<std::numeric_limits<Src>::is_specialized, int>::type =
- 0)
+ typename std::enable_if<std::numeric_limits<Src>::is_specialized,
+ int>::type = 0)
: value_(static_cast<T>(value)),
validity_(DstRangeRelationToSrcRange<T>(value)) {}
@@ -400,7 +443,8 @@ class CheckedNumericState<T, NUMERIC_FLOATING> {
CheckedNumericState(
Src value,
RangeConstraint /* validity */,
- typename enable_if<std::numeric_limits<Src>::is_integer, int>::type = 0) {
+ typename std::enable_if<std::numeric_limits<Src>::is_integer, int>::type =
+ 0) {
switch (DstRangeRelationToSrcRange<T>(value)) {
case RANGE_VALID:
value_ = static_cast<T>(value);
@@ -426,8 +470,8 @@ class CheckedNumericState<T, NUMERIC_FLOATING> {
template <typename Src>
explicit CheckedNumericState(
Src value,
- typename enable_if<std::numeric_limits<Src>::is_specialized, int>::type =
- 0)
+ typename std::enable_if<std::numeric_limits<Src>::is_specialized,
+ int>::type = 0)
: value_(static_cast<T>(value)) {}
// Copy constructor.
diff --git a/base/numerics/safe_numerics_unittest.cc b/base/numerics/safe_numerics_unittest.cc
index 6f9a966c01..cb63ad0d08 100644
--- a/base/numerics/safe_numerics_unittest.cc
+++ b/base/numerics/safe_numerics_unittest.cc
@@ -2,22 +2,28 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#if defined(COMPILER_MSVC) && defined(ARCH_CPU_32_BITS)
-#include <mmintrin.h>
-#endif
+#include <stddef.h>
#include <stdint.h>
#include <limits>
+#include <type_traits>
#include "base/compiler_specific.h"
#include "base/numerics/safe_conversions.h"
#include "base/numerics/safe_math.h"
#include "base/template_util.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
+#if defined(COMPILER_MSVC) && defined(ARCH_CPU_32_BITS)
+#include <mmintrin.h>
+#endif
+
using std::numeric_limits;
using base::CheckedNumeric;
using base::checked_cast;
+using base::IsValueInRangeForNumericType;
+using base::IsValueNegative;
using base::SizeT;
using base::StrictNumeric;
using base::saturated_cast;
@@ -27,7 +33,7 @@ using base::internal::RANGE_VALID;
using base::internal::RANGE_INVALID;
using base::internal::RANGE_OVERFLOW;
using base::internal::RANGE_UNDERFLOW;
-using base::enable_if;
+using base::internal::SignedIntegerForSize;
// These tests deliberately cause arithmetic overflows. If the compiler is
// aggressive enough, it can const fold these overflows. Disable warnings about
@@ -36,6 +42,26 @@ using base::enable_if;
#pragma warning(disable:4756)
#endif
+// This is a helper function for finding the maximum value in Src that can be
+// wholy represented as the destination floating-point type.
+template <typename Dst, typename Src>
+Dst GetMaxConvertibleToFloat() {
+ typedef numeric_limits<Dst> DstLimits;
+ typedef numeric_limits<Src> SrcLimits;
+ static_assert(SrcLimits::is_specialized, "Source must be numeric.");
+ static_assert(DstLimits::is_specialized, "Destination must be numeric.");
+ CHECK(DstLimits::is_iec559);
+
+ if (SrcLimits::digits <= DstLimits::digits &&
+ MaxExponent<Src>::value <= MaxExponent<Dst>::value)
+ return SrcLimits::max();
+ Src max = SrcLimits::max() / 2 + (SrcLimits::is_integer ? 1 : 0);
+ while (max != static_cast<Src>(static_cast<Dst>(max))) {
+ max /= 2;
+ }
+ return static_cast<Dst>(max);
+}
+
// Helper macros to wrap displaying the conversion types and line numbers.
#define TEST_EXPECTED_VALIDITY(expected, actual) \
EXPECT_EQ(expected, CheckedNumeric<Dst>(actual).validity()) \
@@ -53,9 +79,9 @@ template <typename Dst>
static void TestSpecializedArithmetic(
const char* dst,
int line,
- typename enable_if<
- numeric_limits<Dst>::is_integer&& numeric_limits<Dst>::is_signed,
- int>::type = 0) {
+ typename std::enable_if<numeric_limits<Dst>::is_integer &&
+ numeric_limits<Dst>::is_signed,
+ int>::type = 0) {
typedef numeric_limits<Dst> DstLimits;
TEST_EXPECTED_VALIDITY(RANGE_OVERFLOW,
-CheckedNumeric<Dst>(DstLimits::min()));
@@ -109,9 +135,9 @@ template <typename Dst>
static void TestSpecializedArithmetic(
const char* dst,
int line,
- typename enable_if<
- numeric_limits<Dst>::is_integer && !numeric_limits<Dst>::is_signed,
- int>::type = 0) {
+ typename std::enable_if<numeric_limits<Dst>::is_integer &&
+ !numeric_limits<Dst>::is_signed,
+ int>::type = 0) {
typedef numeric_limits<Dst> DstLimits;
TEST_EXPECTED_VALIDITY(RANGE_VALID, -CheckedNumeric<Dst>(DstLimits::min()));
TEST_EXPECTED_VALIDITY(RANGE_VALID,
@@ -122,6 +148,13 @@ static void TestSpecializedArithmetic(
CheckedNumeric<Dst>(DstLimits::min()) - 1);
TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(DstLimits::min()) * 2);
TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) / 2);
+ TEST_EXPECTED_VALIDITY(RANGE_VALID,
+ CheckedNumeric<Dst>(DstLimits::min()).UnsignedAbs());
+ TEST_EXPECTED_VALIDITY(
+ RANGE_VALID,
+ CheckedNumeric<typename SignedIntegerForSize<Dst>::type>(
+ std::numeric_limits<typename SignedIntegerForSize<Dst>::type>::min())
+ .UnsignedAbs());
// Modulus is legal only for integers.
TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>() % 1);
@@ -142,7 +175,7 @@ template <typename Dst>
void TestSpecializedArithmetic(
const char* dst,
int line,
- typename enable_if<numeric_limits<Dst>::is_iec559, int>::type = 0) {
+ typename std::enable_if<numeric_limits<Dst>::is_iec559, int>::type = 0) {
typedef numeric_limits<Dst> DstLimits;
TEST_EXPECTED_VALIDITY(RANGE_VALID, -CheckedNumeric<Dst>(DstLimits::min()));
@@ -317,7 +350,6 @@ struct TestNumericConversion<Dst, Src, SIGN_PRESERVING_VALUE_PRESERVING> {
"Comparison must be sign preserving and value preserving");
const CheckedNumeric<Dst> checked_dst = SrcLimits::max();
- ;
TEST_EXPECTED_VALIDITY(RANGE_VALID, checked_dst);
if (MaxExponent<Dst>::value > MaxExponent<Src>::value) {
if (MaxExponent<Dst>::value >= MaxExponent<Src>::value * 2 - 1) {
@@ -370,6 +402,18 @@ struct TestNumericConversion<Dst, Src, SIGN_PRESERVING_NARROW> {
TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::infinity());
TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::infinity() * -1);
TEST_EXPECTED_RANGE(RANGE_INVALID, SrcLimits::quiet_NaN());
+ if (DstLimits::is_integer) {
+ if (SrcLimits::digits < DstLimits::digits) {
+ TEST_EXPECTED_RANGE(RANGE_OVERFLOW,
+ static_cast<Src>(DstLimits::max()));
+ } else {
+ TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(DstLimits::max()));
+ }
+ TEST_EXPECTED_RANGE(
+ RANGE_VALID,
+ static_cast<Src>(GetMaxConvertibleToFloat<Src, Dst>()));
+ TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(DstLimits::min()));
+ }
} else if (SrcLimits::is_signed) {
TEST_EXPECTED_VALUE(-1, checked_dst - static_cast<Src>(1));
TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::min());
@@ -428,6 +472,18 @@ struct TestNumericConversion<Dst, Src, SIGN_TO_UNSIGN_NARROW> {
TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::infinity());
TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::infinity() * -1);
TEST_EXPECTED_RANGE(RANGE_INVALID, SrcLimits::quiet_NaN());
+ if (DstLimits::is_integer) {
+ if (SrcLimits::digits < DstLimits::digits) {
+ TEST_EXPECTED_RANGE(RANGE_OVERFLOW,
+ static_cast<Src>(DstLimits::max()));
+ } else {
+ TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(DstLimits::max()));
+ }
+ TEST_EXPECTED_RANGE(
+ RANGE_VALID,
+ static_cast<Src>(GetMaxConvertibleToFloat<Src, Dst>()));
+ TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(DstLimits::min()));
+ }
} else {
TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::min());
}
@@ -578,6 +634,18 @@ TEST(SafeNumerics, CastTests) {
EXPECT_TRUE(CheckedNumeric<int>(StrictNumeric<unsigned>(1U)).IsValid());
EXPECT_FALSE(CheckedNumeric<unsigned>(StrictNumeric<int>(-1)).IsValid());
+ EXPECT_TRUE(IsValueNegative(-1));
+ EXPECT_TRUE(IsValueNegative(numeric_limits<int>::min()));
+ EXPECT_FALSE(IsValueNegative(numeric_limits<unsigned>::min()));
+ EXPECT_TRUE(IsValueNegative(-numeric_limits<double>::max()));
+ EXPECT_FALSE(IsValueNegative(0));
+ EXPECT_FALSE(IsValueNegative(1));
+ EXPECT_FALSE(IsValueNegative(0u));
+ EXPECT_FALSE(IsValueNegative(1u));
+ EXPECT_FALSE(IsValueNegative(numeric_limits<int>::max()));
+ EXPECT_FALSE(IsValueNegative(numeric_limits<unsigned>::max()));
+ EXPECT_FALSE(IsValueNegative(numeric_limits<double>::max()));
+
// These casts and coercions will fail to compile:
// EXPECT_EQ(0, strict_cast<int>(static_cast<size_t>(0)));
// EXPECT_EQ(0, strict_cast<size_t>(static_cast<int>(0)));
@@ -598,5 +666,120 @@ TEST(SafeNumerics, CastTests) {
EXPECT_EQ(saturated_cast<float>(-double_large), -double_infinity);
EXPECT_EQ(numeric_limits<int>::min(), saturated_cast<int>(double_small_int));
EXPECT_EQ(numeric_limits<int>::max(), saturated_cast<int>(double_large_int));
+
+ float not_a_number = std::numeric_limits<float>::infinity() -
+ std::numeric_limits<float>::infinity();
+ EXPECT_TRUE(std::isnan(not_a_number));
+ EXPECT_EQ(0, saturated_cast<int>(not_a_number));
}
+#if GTEST_HAS_DEATH_TEST
+
+TEST(SafeNumerics, SaturatedCastChecks) {
+ float not_a_number = std::numeric_limits<float>::infinity() -
+ std::numeric_limits<float>::infinity();
+ EXPECT_TRUE(std::isnan(not_a_number));
+ EXPECT_DEATH((saturated_cast<int, base::SaturatedCastNaNBehaviorCheck>(
+ not_a_number)), "");
+}
+
+#endif // GTEST_HAS_DEATH_TEST
+
+TEST(SafeNumerics, IsValueInRangeForNumericType) {
+ EXPECT_TRUE(IsValueInRangeForNumericType<uint32_t>(0));
+ EXPECT_TRUE(IsValueInRangeForNumericType<uint32_t>(1));
+ EXPECT_TRUE(IsValueInRangeForNumericType<uint32_t>(2));
+ EXPECT_FALSE(IsValueInRangeForNumericType<uint32_t>(-1));
+ EXPECT_TRUE(IsValueInRangeForNumericType<uint32_t>(0xffffffffu));
+ EXPECT_TRUE(IsValueInRangeForNumericType<uint32_t>(UINT64_C(0xffffffff)));
+ EXPECT_FALSE(IsValueInRangeForNumericType<uint32_t>(UINT64_C(0x100000000)));
+ EXPECT_FALSE(IsValueInRangeForNumericType<uint32_t>(UINT64_C(0x100000001)));
+ EXPECT_FALSE(IsValueInRangeForNumericType<uint32_t>(
+ std::numeric_limits<int32_t>::min()));
+ EXPECT_FALSE(IsValueInRangeForNumericType<uint32_t>(
+ std::numeric_limits<int64_t>::min()));
+
+ EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(0));
+ EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(1));
+ EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(2));
+ EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(-1));
+ EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(0x7fffffff));
+ EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(0x7fffffffu));
+ EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(0x80000000u));
+ EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(0xffffffffu));
+ EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(INT64_C(0x80000000)));
+ EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(INT64_C(0xffffffff)));
+ EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(INT64_C(0x100000000)));
+ EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(
+ std::numeric_limits<int32_t>::min()));
+ EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(
+ static_cast<int64_t>(std::numeric_limits<int32_t>::min())));
+ EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(
+ static_cast<int64_t>(std::numeric_limits<int32_t>::min()) - 1));
+ EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(
+ std::numeric_limits<int64_t>::min()));
+
+ EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(0));
+ EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(1));
+ EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(2));
+ EXPECT_FALSE(IsValueInRangeForNumericType<uint64_t>(-1));
+ EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(0xffffffffu));
+ EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(UINT64_C(0xffffffff)));
+ EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(UINT64_C(0x100000000)));
+ EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(UINT64_C(0x100000001)));
+ EXPECT_FALSE(IsValueInRangeForNumericType<uint64_t>(
+ std::numeric_limits<int32_t>::min()));
+ EXPECT_FALSE(IsValueInRangeForNumericType<uint64_t>(INT64_C(-1)));
+ EXPECT_FALSE(IsValueInRangeForNumericType<uint64_t>(
+ std::numeric_limits<int64_t>::min()));
+
+ EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(0));
+ EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(1));
+ EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(2));
+ EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(-1));
+ EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(0x7fffffff));
+ EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(0x7fffffffu));
+ EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(0x80000000u));
+ EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(0xffffffffu));
+ EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(INT64_C(0x80000000)));
+ EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(INT64_C(0xffffffff)));
+ EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(INT64_C(0x100000000)));
+ EXPECT_TRUE(
+ IsValueInRangeForNumericType<int64_t>(INT64_C(0x7fffffffffffffff)));
+ EXPECT_TRUE(
+ IsValueInRangeForNumericType<int64_t>(UINT64_C(0x7fffffffffffffff)));
+ EXPECT_FALSE(
+ IsValueInRangeForNumericType<int64_t>(UINT64_C(0x8000000000000000)));
+ EXPECT_FALSE(
+ IsValueInRangeForNumericType<int64_t>(UINT64_C(0xffffffffffffffff)));
+ EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(
+ std::numeric_limits<int32_t>::min()));
+ EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(
+ static_cast<int64_t>(std::numeric_limits<int32_t>::min())));
+ EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(
+ std::numeric_limits<int64_t>::min()));
+}
+
+TEST(SafeNumerics, CompoundNumericOperations) {
+ CheckedNumeric<int> a = 1;
+ CheckedNumeric<int> b = 2;
+ CheckedNumeric<int> c = 3;
+ CheckedNumeric<int> d = 4;
+ a += b;
+ EXPECT_EQ(3, a.ValueOrDie());
+ a -= c;
+ EXPECT_EQ(0, a.ValueOrDie());
+ d /= b;
+ EXPECT_EQ(2, d.ValueOrDie());
+ d *= d;
+ EXPECT_EQ(4, d.ValueOrDie());
+
+ CheckedNumeric<int> too_large = std::numeric_limits<int>::max();
+ EXPECT_TRUE(too_large.IsValid());
+ too_large += d;
+ EXPECT_FALSE(too_large.IsValid());
+ too_large -= d;
+ EXPECT_FALSE(too_large.IsValid());
+ too_large /= d;
+ EXPECT_FALSE(too_large.IsValid());
+}
diff --git a/base/observer_list.h b/base/observer_list.h
index a454430fc9..31564212e0 100644
--- a/base/observer_list.h
+++ b/base/observer_list.h
@@ -5,13 +5,16 @@
#ifndef BASE_OBSERVER_LIST_H_
#define BASE_OBSERVER_LIST_H_
+#include <stddef.h>
+
#include <algorithm>
#include <limits>
#include <vector>
-#include "base/basictypes.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/weak_ptr.h"
+#include "base/stl_util.h"
///////////////////////////////////////////////////////////////////////////////
//
@@ -157,8 +160,7 @@ ObserverType* ObserverListBase<ObserverType>::Iterator::GetNext() {
template <class ObserverType>
void ObserverListBase<ObserverType>::AddObserver(ObserverType* obs) {
DCHECK(obs);
- if (std::find(observers_.begin(), observers_.end(), obs)
- != observers_.end()) {
+ if (ContainsValue(observers_, obs)) {
NOTREACHED() << "Observers can only be added once!";
return;
}
diff --git a/base/observer_list_threadsafe.h b/base/observer_list_threadsafe.h
index b9b4a624ca..6154ae9b8d 100644
--- a/base/observer_list_threadsafe.h
+++ b/base/observer_list_threadsafe.h
@@ -8,10 +8,10 @@
#include <algorithm>
#include <map>
-#include "base/basictypes.h"
#include "base/bind.h"
#include "base/location.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
#include "base/observer_list.h"
@@ -67,9 +67,8 @@ template <class T, class Method, class Params>
class UnboundMethod {
public:
UnboundMethod(Method m, const Params& p) : m_(m), p_(p) {
- COMPILE_ASSERT(
- (internal::ParamsUseScopedRefptrCorrectly<Params>::value),
- badunboundmethodparams);
+ static_assert((internal::ParamsUseScopedRefptrCorrectly<Params>::value),
+ "bad unbound method params");
}
void Run(T* obj) const {
DispatchToMethod(obj, m_, p_);
diff --git a/base/pickle.cc b/base/pickle.cc
index cf4a865d35..d83391bb52 100644
--- a/base/pickle.cc
+++ b/base/pickle.cc
@@ -7,6 +7,11 @@
#include <stdlib.h>
#include <algorithm> // for max()
+#include <limits>
+
+#include "base/bits.h"
+#include "base/macros.h"
+#include "build/build_config.h"
namespace base {
@@ -26,7 +31,7 @@ inline bool PickleIterator::ReadBuiltinType(Type* result) {
const char* read_from = GetReadPointerAndAdvance<Type>();
if (!read_from)
return false;
- if (sizeof(Type) > sizeof(uint32))
+ if (sizeof(Type) > sizeof(uint32_t))
memcpy(result, read_from, sizeof(*result));
else
*result = *reinterpret_cast<const Type*>(read_from);
@@ -34,7 +39,7 @@ inline bool PickleIterator::ReadBuiltinType(Type* result) {
}
inline void PickleIterator::Advance(size_t size) {
- size_t aligned_size = AlignInt(size, sizeof(uint32_t));
+ size_t aligned_size = bits::Align(size, sizeof(uint32_t));
if (end_index_ - read_index_ < aligned_size) {
read_index_ = end_index_;
} else {
@@ -67,10 +72,10 @@ const char* PickleIterator::GetReadPointerAndAdvance(int num_bytes) {
inline const char* PickleIterator::GetReadPointerAndAdvance(
int num_elements,
size_t size_element) {
- // Check for int32 overflow.
- int64 num_bytes = static_cast<int64>(num_elements) * size_element;
+ // Check for int32_t overflow.
+ int64_t num_bytes = static_cast<int64_t>(num_elements) * size_element;
int num_bytes32 = static_cast<int>(num_bytes);
- if (num_bytes != static_cast<int64>(num_bytes32))
+ if (num_bytes != static_cast<int64_t>(num_bytes32))
return NULL;
return GetReadPointerAndAdvance(num_bytes32);
}
@@ -87,26 +92,26 @@ bool PickleIterator::ReadLong(long* result) {
return ReadBuiltinType(result);
}
-bool PickleIterator::ReadUInt16(uint16* result) {
+bool PickleIterator::ReadUInt16(uint16_t* result) {
return ReadBuiltinType(result);
}
-bool PickleIterator::ReadUInt32(uint32* result) {
+bool PickleIterator::ReadUInt32(uint32_t* result) {
return ReadBuiltinType(result);
}
-bool PickleIterator::ReadInt64(int64* result) {
+bool PickleIterator::ReadInt64(int64_t* result) {
return ReadBuiltinType(result);
}
-bool PickleIterator::ReadUInt64(uint64* result) {
+bool PickleIterator::ReadUInt64(uint64_t* result) {
return ReadBuiltinType(result);
}
bool PickleIterator::ReadSizeT(size_t* result) {
// Always read size_t as a 64-bit value to ensure compatibility between 32-bit
// and 64-bit processes.
- uint64 result_uint64 = 0;
+ uint64_t result_uint64 = 0;
bool success = ReadBuiltinType(&result_uint64);
*result = static_cast<size_t>(result_uint64);
// Fail if the cast above truncates the value.
@@ -203,20 +208,22 @@ bool PickleIterator::ReadBytes(const char** data, int length) {
return true;
}
-// Payload is uint32 aligned.
+// Payload is uint32_t aligned.
Pickle::Pickle()
: header_(NULL),
header_size_(sizeof(Header)),
capacity_after_header_(0),
write_offset_(0) {
+ static_assert((Pickle::kPayloadUnit & (Pickle::kPayloadUnit - 1)) == 0,
+ "Pickle::kPayloadUnit must be a power of two");
Resize(kPayloadUnit);
header_->payload_size = 0;
}
Pickle::Pickle(int header_size)
: header_(NULL),
- header_size_(AlignInt(header_size, sizeof(uint32))),
+ header_size_(bits::Align(header_size, sizeof(uint32_t))),
capacity_after_header_(0),
write_offset_(0) {
DCHECK_GE(static_cast<size_t>(header_size), sizeof(Header));
@@ -236,7 +243,7 @@ Pickle::Pickle(const char* data, int data_len)
if (header_size_ > static_cast<unsigned int>(data_len))
header_size_ = 0;
- if (header_size_ != AlignInt(header_size_, sizeof(uint32)))
+ if (header_size_ != bits::Align(header_size_, sizeof(uint32_t)))
header_size_ = 0;
// If there is anything wrong with the data, we're not going to use it.
@@ -249,9 +256,8 @@ Pickle::Pickle(const Pickle& other)
header_size_(other.header_size_),
capacity_after_header_(0),
write_offset_(other.write_offset_) {
- size_t payload_size = header_size_ + other.header_->payload_size;
- Resize(payload_size);
- memcpy(header_, other.header_, payload_size);
+ Resize(other.header_->payload_size);
+ memcpy(header_, other.header_, header_size_ + other.header_->payload_size);
}
Pickle::~Pickle() {
@@ -305,12 +311,12 @@ bool Pickle::WriteBytes(const void* data, int length) {
}
void Pickle::Reserve(size_t length) {
- size_t data_len = AlignInt(length, sizeof(uint32));
+ size_t data_len = bits::Align(length, sizeof(uint32_t));
DCHECK_GE(data_len, length);
#ifdef ARCH_CPU_64_BITS
- DCHECK_LE(data_len, kuint32max);
+ DCHECK_LE(data_len, std::numeric_limits<uint32_t>::max());
#endif
- DCHECK_LE(write_offset_, kuint32max - data_len);
+ DCHECK_LE(write_offset_, std::numeric_limits<uint32_t>::max() - data_len);
size_t new_size = write_offset_ + data_len;
if (new_size > capacity_after_header_)
Resize(capacity_after_header_ * 2 + new_size);
@@ -318,12 +324,19 @@ void Pickle::Reserve(size_t length) {
void Pickle::Resize(size_t new_capacity) {
CHECK_NE(capacity_after_header_, kCapacityReadOnly);
- capacity_after_header_ = AlignInt(new_capacity, kPayloadUnit);
+ capacity_after_header_ = bits::Align(new_capacity, kPayloadUnit);
void* p = realloc(header_, GetTotalAllocatedSize());
CHECK(p);
header_ = reinterpret_cast<Header*>(p);
}
+void* Pickle::ClaimBytes(size_t num_bytes) {
+ void* p = ClaimUninitializedBytesInternal(num_bytes);
+ CHECK(p);
+ memset(p, 0, num_bytes);
+ return p;
+}
+
size_t Pickle::GetTotalAllocatedSize() const {
if (capacity_after_header_ == kCapacityReadOnly)
return 0;
@@ -334,17 +347,41 @@ size_t Pickle::GetTotalAllocatedSize() const {
const char* Pickle::FindNext(size_t header_size,
const char* start,
const char* end) {
- DCHECK_EQ(header_size, AlignInt(header_size, sizeof(uint32)));
+ size_t pickle_size = 0;
+ if (!PeekNext(header_size, start, end, &pickle_size))
+ return NULL;
+
+ if (pickle_size > static_cast<size_t>(end - start))
+ return NULL;
+
+ return start + pickle_size;
+}
+
+// static
+bool Pickle::PeekNext(size_t header_size,
+ const char* start,
+ const char* end,
+ size_t* pickle_size) {
+ DCHECK_EQ(header_size, bits::Align(header_size, sizeof(uint32_t)));
+ DCHECK_GE(header_size, sizeof(Header));
DCHECK_LE(header_size, static_cast<size_t>(kPayloadUnit));
size_t length = static_cast<size_t>(end - start);
if (length < sizeof(Header))
- return NULL;
+ return false;
const Header* hdr = reinterpret_cast<const Header*>(start);
- if (length < header_size || length - header_size < hdr->payload_size)
- return NULL;
- return start + header_size + hdr->payload_size;
+ if (length < header_size)
+ return false;
+
+ if (hdr->payload_size > std::numeric_limits<size_t>::max() - header_size) {
+ // If payload_size causes an overflow, we return maximum possible
+ // pickle size to indicate that.
+ *pickle_size = std::numeric_limits<size_t>::max();
+ } else {
+ *pickle_size = header_size + hdr->payload_size;
+ }
+ return true;
}
template <size_t length> void Pickle::WriteBytesStatic(const void* data) {
@@ -355,26 +392,37 @@ template void Pickle::WriteBytesStatic<2>(const void* data);
template void Pickle::WriteBytesStatic<4>(const void* data);
template void Pickle::WriteBytesStatic<8>(const void* data);
-inline void Pickle::WriteBytesCommon(const void* data, size_t length) {
+inline void* Pickle::ClaimUninitializedBytesInternal(size_t length) {
DCHECK_NE(kCapacityReadOnly, capacity_after_header_)
<< "oops: pickle is readonly";
- MSAN_CHECK_MEM_IS_INITIALIZED(data, length);
- size_t data_len = AlignInt(length, sizeof(uint32));
+ size_t data_len = bits::Align(length, sizeof(uint32_t));
DCHECK_GE(data_len, length);
#ifdef ARCH_CPU_64_BITS
- DCHECK_LE(data_len, kuint32max);
+ DCHECK_LE(data_len, std::numeric_limits<uint32_t>::max());
#endif
- DCHECK_LE(write_offset_, kuint32max - data_len);
+ DCHECK_LE(write_offset_, std::numeric_limits<uint32_t>::max() - data_len);
size_t new_size = write_offset_ + data_len;
if (new_size > capacity_after_header_) {
- Resize(std::max(capacity_after_header_ * 2, new_size));
+ size_t new_capacity = capacity_after_header_ * 2;
+ const size_t kPickleHeapAlign = 4096;
+ if (new_capacity > kPickleHeapAlign)
+ new_capacity = bits::Align(new_capacity, kPickleHeapAlign) - kPayloadUnit;
+ Resize(std::max(new_capacity, new_size));
}
char* write = mutable_payload() + write_offset_;
- memcpy(write, data, length);
- memset(write + length, 0, data_len - length);
- header_->payload_size = static_cast<uint32>(new_size);
+ memset(write + length, 0, data_len - length); // Always initialize padding
+ header_->payload_size = static_cast<uint32_t>(new_size);
write_offset_ = new_size;
+ return write;
+}
+
+inline void Pickle::WriteBytesCommon(const void* data, size_t length) {
+ DCHECK_NE(kCapacityReadOnly, capacity_after_header_)
+ << "oops: pickle is readonly";
+ MSAN_CHECK_MEM_IS_INITIALIZED(data, length);
+ void* write = ClaimUninitializedBytesInternal(length);
+ memcpy(write, data, length);
}
} // namespace base
diff --git a/base/pickle.h b/base/pickle.h
index c9fef715a7..02bc432ad0 100644
--- a/base/pickle.h
+++ b/base/pickle.h
@@ -5,10 +5,12 @@
#ifndef BASE_PICKLE_H_
#define BASE_PICKLE_H_
+#include <stddef.h>
+#include <stdint.h>
+
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/gtest_prod_util.h"
#include "base/logging.h"
@@ -34,10 +36,10 @@ class BASE_EXPORT PickleIterator {
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 ReadUInt16(uint16_t* result) WARN_UNUSED_RESULT;
+ bool ReadUInt32(uint32_t* result) WARN_UNUSED_RESULT;
+ bool ReadInt64(int64_t* result) WARN_UNUSED_RESULT;
+ bool ReadUInt64(uint64_t* result) WARN_UNUSED_RESULT;
bool ReadSizeT(size_t* result) WARN_UNUSED_RESULT;
bool ReadFloat(float* result) WARN_UNUSED_RESULT;
bool ReadDouble(double* result) WARN_UNUSED_RESULT;
@@ -74,11 +76,6 @@ class BASE_EXPORT PickleIterator {
}
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 <typename Type>
bool ReadBuiltinType(Type* result);
@@ -184,22 +181,14 @@ class BASE_EXPORT Pickle {
bool WriteLongUsingDangerousNonPortableLessPersistableForm(long value) {
return WritePOD(value);
}
- bool WriteUInt16(uint16 value) {
- return WritePOD(value);
- }
- bool WriteUInt32(uint32 value) {
- return WritePOD(value);
- }
- bool WriteInt64(int64 value) {
- return WritePOD(value);
- }
- bool WriteUInt64(uint64 value) {
- return WritePOD(value);
- }
+ bool WriteUInt16(uint16_t value) { return WritePOD(value); }
+ bool WriteUInt32(uint32_t value) { return WritePOD(value); }
+ bool WriteInt64(int64_t value) { return WritePOD(value); }
+ bool WriteUInt64(uint64_t value) { return WritePOD(value); }
bool WriteSizeT(size_t value) {
// Always write size_t as a 64-bit value to ensure compatibility between
// 32-bit and 64-bit processes.
- return WritePOD(static_cast<uint64>(value));
+ return WritePOD(static_cast<uint64_t>(value));
}
bool WriteFloat(float value) {
return WritePOD(value);
@@ -224,7 +213,7 @@ class BASE_EXPORT Pickle {
// Payload follows after allocation of Header (header size is customizable).
struct Header {
- uint32 payload_size; // Specifies the size of the payload.
+ uint32_t payload_size; // Specifies the size of the payload.
};
// Returns the header, cast to a user-specified type T. The type T must be a
@@ -270,10 +259,12 @@ class BASE_EXPORT Pickle {
// of the header.
void 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;
- }
+ // Claims |num_bytes| bytes of payload. This is similar to Reserve() in that
+ // it may grow the capacity, but it also advances the write offset of the
+ // pickle by |num_bytes|. Claimed memory, including padding, is zeroed.
+ //
+ // Returns the address of the first byte claimed.
+ void* ClaimBytes(size_t num_bytes);
// 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.
@@ -281,6 +272,18 @@ class BASE_EXPORT Pickle {
const char* range_start,
const char* range_end);
+ // Parse pickle header and return total size of the pickle. Data range
+ // doesn't need to contain entire pickle.
+ // Returns true if pickle header was found and parsed. Callers must check
+ // returned |pickle_size| for sanity (against maximum message size, etc).
+ // NOTE: when function successfully parses a header, but encounters an
+ // overflow during pickle size calculation, it sets |pickle_size| to the
+ // maximum size_t value and returns true.
+ static bool PeekNext(size_t header_size,
+ const char* range_start,
+ const char* range_end,
+ size_t* pickle_size);
+
// The allocation granularity of the payload.
static const int kPayloadUnit;
@@ -304,9 +307,14 @@ class BASE_EXPORT Pickle {
WriteBytesStatic<sizeof(data)>(&data);
return true;
}
+
+ inline void* ClaimUninitializedBytesInternal(size_t num_bytes);
inline void WriteBytesCommon(const void* data, size_t length);
+ FRIEND_TEST_ALL_PREFIXES(PickleTest, DeepCopyResize);
FRIEND_TEST_ALL_PREFIXES(PickleTest, Resize);
+ FRIEND_TEST_ALL_PREFIXES(PickleTest, PeekNext);
+ FRIEND_TEST_ALL_PREFIXES(PickleTest, PeekNextOverflow);
FRIEND_TEST_ALL_PREFIXES(PickleTest, FindNext);
FRIEND_TEST_ALL_PREFIXES(PickleTest, FindNextWithIncompleteHeader);
FRIEND_TEST_ALL_PREFIXES(PickleTest, FindNextOverflow);
diff --git a/base/pickle_unittest.cc b/base/pickle_unittest.cc
index b0a8f21f89..b195a81e5e 100644
--- a/base/pickle_unittest.cc
+++ b/base/pickle_unittest.cc
@@ -2,9 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <limits.h>
+#include <stddef.h>
+#include <stdint.h>
+
#include <string>
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/pickle.h"
#include "base/strings/string16.h"
@@ -19,10 +23,10 @@ const bool testbool1 = false;
const bool testbool2 = true;
const int testint = 2093847192;
const long testlong = 1093847192;
-const uint16 testuint16 = 32123;
-const uint32 testuint32 = 1593847192;
-const int64 testint64 = -0x7E8CA9253104BDFCLL;
-const uint64 testuint64 = 0xCE8CA9253104BDF7ULL;
+const uint16_t testuint16 = 32123;
+const uint32_t testuint32 = 1593847192;
+const int64_t testint64 = -0x7E8CA9253104BDFCLL;
+const uint64_t testuint64 = 0xCE8CA9253104BDF7ULL;
const size_t testsizet = 0xFEDC7654;
const float testfloat = 3.1415926935f;
const double testdouble = 2.71828182845904523;
@@ -53,19 +57,19 @@ void VerifyResult(const Pickle& pickle) {
EXPECT_TRUE(iter.ReadLong(&outlong));
EXPECT_EQ(testlong, outlong);
- uint16 outuint16;
+ uint16_t outuint16;
EXPECT_TRUE(iter.ReadUInt16(&outuint16));
EXPECT_EQ(testuint16, outuint16);
- uint32 outuint32;
+ uint32_t outuint32;
EXPECT_TRUE(iter.ReadUInt32(&outuint32));
EXPECT_EQ(testuint32, outuint32);
- int64 outint64;
+ int64_t outint64;
EXPECT_TRUE(iter.ReadInt64(&outint64));
EXPECT_EQ(testint64, outint64);
- uint64 outuint64;
+ uint64_t outuint64;
EXPECT_TRUE(iter.ReadUInt64(&outuint64));
EXPECT_EQ(testuint64, outuint64);
@@ -147,12 +151,13 @@ TEST(PickleTest, EncodeDecode) {
TEST(PickleTest, SizeTFrom64Bit) {
Pickle pickle;
// Under the hood size_t is always written as a 64-bit value, so simulate a
- // 64-bit size_t even on 32-bit architectures by explicitly writing a uint64.
+ // 64-bit size_t even on 32-bit architectures by explicitly writing a
+ // uint64_t.
EXPECT_TRUE(pickle.WriteUInt64(testuint64));
PickleIterator iter(pickle);
size_t outsizet;
- if (sizeof(size_t) < sizeof(uint64)) {
+ if (sizeof(size_t) < sizeof(uint64_t)) {
// ReadSizeT() should return false when the original written value can't be
// represented as a size_t.
EXPECT_FALSE(iter.ReadSizeT(&outsizet));
@@ -233,6 +238,88 @@ TEST(PickleTest, BadLenStr16) {
EXPECT_FALSE(iter.ReadString16(&outstr));
}
+TEST(PickleTest, PeekNext) {
+ struct CustomHeader : base::Pickle::Header {
+ int cookies[10];
+ };
+
+ Pickle pickle(sizeof(CustomHeader));
+
+ EXPECT_TRUE(pickle.WriteString("Goooooooooooogle"));
+
+ const char* pickle_data = static_cast<const char*>(pickle.data());
+
+ size_t pickle_size;
+
+ // Data range doesn't contain header
+ EXPECT_FALSE(Pickle::PeekNext(
+ sizeof(CustomHeader),
+ pickle_data,
+ pickle_data + sizeof(CustomHeader) - 1,
+ &pickle_size));
+
+ // Data range contains header
+ EXPECT_TRUE(Pickle::PeekNext(
+ sizeof(CustomHeader),
+ pickle_data,
+ pickle_data + sizeof(CustomHeader),
+ &pickle_size));
+ EXPECT_EQ(pickle_size, pickle.size());
+
+ // Data range contains header and some other data
+ EXPECT_TRUE(Pickle::PeekNext(
+ sizeof(CustomHeader),
+ pickle_data,
+ pickle_data + sizeof(CustomHeader) + 1,
+ &pickle_size));
+ EXPECT_EQ(pickle_size, pickle.size());
+
+ // Data range contains full pickle
+ EXPECT_TRUE(Pickle::PeekNext(
+ sizeof(CustomHeader),
+ pickle_data,
+ pickle_data + pickle.size(),
+ &pickle_size));
+ EXPECT_EQ(pickle_size, pickle.size());
+}
+
+TEST(PickleTest, PeekNextOverflow) {
+ struct CustomHeader : base::Pickle::Header {
+ int cookies[10];
+ };
+
+ CustomHeader header;
+
+ // Check if we can wrap around at all
+ if (sizeof(size_t) > sizeof(header.payload_size))
+ return;
+
+ const char* pickle_data = reinterpret_cast<const char*>(&header);
+
+ size_t pickle_size;
+
+ // Wrapping around is detected and reported as maximum size_t value
+ header.payload_size = static_cast<uint32_t>(
+ 1 - static_cast<int32_t>(sizeof(CustomHeader)));
+ EXPECT_TRUE(Pickle::PeekNext(
+ sizeof(CustomHeader),
+ pickle_data,
+ pickle_data + sizeof(CustomHeader),
+ &pickle_size));
+ EXPECT_EQ(pickle_size, std::numeric_limits<size_t>::max());
+
+ // Ridiculous pickle sizes are fine (callers are supposed to
+ // verify them)
+ header.payload_size =
+ std::numeric_limits<uint32_t>::max() / 2 - sizeof(CustomHeader);
+ EXPECT_TRUE(Pickle::PeekNext(
+ sizeof(CustomHeader),
+ pickle_data,
+ pickle_data + sizeof(CustomHeader),
+ &pickle_size));
+ EXPECT_EQ(pickle_size, std::numeric_limits<uint32_t>::max() / 2);
+}
+
TEST(PickleTest, FindNext) {
Pickle pickle;
EXPECT_TRUE(pickle.WriteInt(1));
@@ -316,10 +403,10 @@ TEST(PickleTest, Resize) {
// 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);
+ const size_t payload_size_after_header = unit - sizeof(uint32_t);
Pickle pickle;
- pickle.WriteData(data_ptr,
- static_cast<int>(payload_size_after_header - sizeof(uint32)));
+ pickle.WriteData(
+ data_ptr, static_cast<int>(payload_size_after_header - sizeof(uint32_t)));
size_t cur_payload = payload_size_after_header;
// note: we assume 'unit' is a power of 2
@@ -327,7 +414,7 @@ TEST(PickleTest, Resize) {
EXPECT_EQ(pickle.payload_size(), payload_size_after_header);
// fill out a full page (noting data header)
- pickle.WriteData(data_ptr, static_cast<int>(unit - sizeof(uint32)));
+ pickle.WriteData(data_ptr, static_cast<int>(unit - sizeof(uint32_t)));
cur_payload += unit;
EXPECT_EQ(unit * 2, pickle.capacity_after_header());
EXPECT_EQ(cur_payload, pickle.payload_size());
@@ -348,7 +435,7 @@ struct CustomHeader : Pickle::Header {
} // namespace
TEST(PickleTest, HeaderPadding) {
- const uint32 kMagic = 0x12345678;
+ const uint32_t kMagic = 0x12345678;
Pickle pickle(sizeof(CustomHeader));
pickle.WriteInt(kMagic);
@@ -360,7 +447,7 @@ TEST(PickleTest, HeaderPadding) {
int result;
ASSERT_TRUE(iter.ReadInt(&result));
- EXPECT_EQ(static_cast<uint32>(result), kMagic);
+ EXPECT_EQ(static_cast<uint32_t>(result), kMagic);
}
TEST(PickleTest, EqualsOperator) {
@@ -428,4 +515,64 @@ TEST(PickleTest, ReadBytes) {
EXPECT_EQ(data, outdata);
}
+// Checks that when a pickle is deep-copied, the result is not larger than
+// needed.
+TEST(PickleTest, DeepCopyResize) {
+ Pickle pickle;
+ while (pickle.capacity_after_header() != pickle.payload_size())
+ pickle.WriteBool(true);
+
+ // Make a deep copy.
+ Pickle pickle2(pickle);
+
+ // Check that there isn't any extraneous capacity.
+ EXPECT_EQ(pickle.capacity_after_header(), pickle2.capacity_after_header());
+}
+
+namespace {
+
+// Publicly exposes the ClaimBytes interface for testing.
+class TestingPickle : public Pickle {
+ public:
+ TestingPickle() {}
+
+ void* ClaimBytes(size_t num_bytes) { return Pickle::ClaimBytes(num_bytes); }
+};
+
+} // namespace
+
+// Checks that claimed bytes are zero-initialized.
+TEST(PickleTest, ClaimBytesInitialization) {
+ static const int kChunkSize = 64;
+ TestingPickle pickle;
+ const char* bytes = static_cast<const char*>(pickle.ClaimBytes(kChunkSize));
+ for (size_t i = 0; i < kChunkSize; ++i) {
+ EXPECT_EQ(0, bytes[i]);
+ }
+}
+
+// Checks that ClaimBytes properly advances the write offset.
+TEST(PickleTest, ClaimBytes) {
+ std::string data("Hello, world!");
+
+ TestingPickle pickle;
+ pickle.WriteSizeT(data.size());
+ void* bytes = pickle.ClaimBytes(data.size());
+ pickle.WriteInt(42);
+ memcpy(bytes, data.data(), data.size());
+
+ PickleIterator iter(pickle);
+ size_t out_data_length;
+ EXPECT_TRUE(iter.ReadSizeT(&out_data_length));
+ EXPECT_EQ(data.size(), out_data_length);
+
+ const char* out_data = nullptr;
+ EXPECT_TRUE(iter.ReadBytes(&out_data, out_data_length));
+ EXPECT_EQ(data, std::string(out_data, out_data_length));
+
+ int out_value;
+ EXPECT_TRUE(iter.ReadInt(&out_value));
+ EXPECT_EQ(42, out_value);
+}
+
} // namespace base
diff --git a/base/port.h b/base/port.h
deleted file mode 100644
index ba6171353c..0000000000
--- a/base/port.h
+++ /dev/null
@@ -1,18 +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 <stdarg.h>
-#include "build/build_config.h"
-
-// 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/safe_strerror.h b/base/posix/safe_strerror.h
index 862a75066c..2945312910 100644
--- a/base/posix/safe_strerror.h
+++ b/base/posix/safe_strerror.h
@@ -5,6 +5,8 @@
#ifndef BASE_POSIX_SAFE_STRERROR_H_
#define BASE_POSIX_SAFE_STRERROR_H_
+#include <stddef.h>
+
#include <string>
#include "base/base_export.h"
diff --git a/base/posix/unix_domain_socket_linux.cc b/base/posix/unix_domain_socket_linux.cc
index 2f007d091d..25ddb5470a 100644
--- a/base/posix/unix_domain_socket_linux.cc
+++ b/base/posix/unix_domain_socket_linux.cc
@@ -12,10 +12,10 @@
#include "base/files/scoped_file.h"
#include "base/logging.h"
-#include "base/memory/scoped_vector.h"
#include "base/pickle.h"
#include "base/posix/eintr_wrapper.h"
#include "base/stl_util.h"
+#include "build/build_config.h"
#if !defined(OS_NACL_NONSFI)
#include <sys/uio.h>
@@ -87,7 +87,7 @@ bool UnixDomainSocket::SendMsg(int fd,
ssize_t UnixDomainSocket::RecvMsg(int fd,
void* buf,
size_t length,
- ScopedVector<ScopedFD>* fds) {
+ std::vector<ScopedFD>* fds) {
return UnixDomainSocket::RecvMsgWithPid(fd, buf, length, fds, NULL);
}
@@ -95,7 +95,7 @@ ssize_t UnixDomainSocket::RecvMsg(int fd,
ssize_t UnixDomainSocket::RecvMsgWithPid(int fd,
void* buf,
size_t length,
- ScopedVector<ScopedFD>* fds,
+ std::vector<ScopedFD>* fds,
ProcessId* pid) {
return UnixDomainSocket::RecvMsgWithFlags(fd, buf, length, 0, fds, pid);
}
@@ -105,7 +105,7 @@ ssize_t UnixDomainSocket::RecvMsgWithFlags(int fd,
void* buf,
size_t length,
int flags,
- ScopedVector<ScopedFD>* fds,
+ std::vector<ScopedFD>* fds,
ProcessId* out_pid) {
fds->clear();
@@ -167,7 +167,7 @@ ssize_t UnixDomainSocket::RecvMsgWithFlags(int fd,
if (wire_fds) {
for (unsigned i = 0; i < wire_fds_len; ++i)
- fds->push_back(new ScopedFD(wire_fds[i]));
+ fds->push_back(ScopedFD(wire_fds[i])); // TODO(mdempsky): emplace_back
}
if (out_pid) {
@@ -221,7 +221,7 @@ ssize_t UnixDomainSocket::SendRecvMsgWithFlags(int fd,
// return EOF instead of hanging.
send_sock.reset();
- ScopedVector<ScopedFD> recv_fds;
+ std::vector<ScopedFD> recv_fds;
// 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(
@@ -238,7 +238,7 @@ ssize_t UnixDomainSocket::SendRecvMsgWithFlags(int fd,
}
if (result_fd)
- *result_fd = recv_fds.empty() ? -1 : recv_fds[0]->release();
+ *result_fd = recv_fds.empty() ? -1 : recv_fds[0].release();
return reply_len;
}
diff --git a/base/posix/unix_domain_socket_linux.h b/base/posix/unix_domain_socket_linux.h
index 94da4b4f91..2ba739e108 100644
--- a/base/posix/unix_domain_socket_linux.h
+++ b/base/posix/unix_domain_socket_linux.h
@@ -5,14 +5,15 @@
#ifndef BASE_POSIX_UNIX_DOMAIN_SOCKET_LINUX_H_
#define BASE_POSIX_UNIX_DOMAIN_SOCKET_LINUX_H_
+#include <stddef.h>
#include <stdint.h>
#include <sys/types.h>
#include <vector>
#include "base/base_export.h"
#include "base/files/scoped_file.h"
-#include "base/memory/scoped_vector.h"
#include "base/process/process_handle.h"
+#include "build/build_config.h"
namespace base {
@@ -42,7 +43,7 @@ class BASE_EXPORT UnixDomainSocket {
static ssize_t RecvMsg(int fd,
void* msg,
size_t length,
- ScopedVector<ScopedFD>* fds);
+ std::vector<ScopedFD>* fds);
// Same as RecvMsg above, but also returns the sender's process ID (as seen
// from the caller's namespace). However, before using this function to
@@ -51,7 +52,7 @@ class BASE_EXPORT UnixDomainSocket {
static ssize_t RecvMsgWithPid(int fd,
void* msg,
size_t length,
- ScopedVector<ScopedFD>* fds,
+ std::vector<ScopedFD>* fds,
ProcessId* pid);
#if !defined(OS_NACL_NONSFI)
@@ -94,7 +95,7 @@ class BASE_EXPORT UnixDomainSocket {
void* msg,
size_t length,
int flags,
- ScopedVector<ScopedFD>* fds,
+ std::vector<ScopedFD>* fds,
ProcessId* pid);
};
diff --git a/base/posix/unix_domain_socket_linux_unittest.cc b/base/posix/unix_domain_socket_linux_unittest.cc
index 175ec52f08..e4b63c0cd4 100644
--- a/base/posix/unix_domain_socket_linux_unittest.cc
+++ b/base/posix/unix_domain_socket_linux_unittest.cc
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stddef.h>
+#include <stdint.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
@@ -11,7 +13,6 @@
#include "base/files/file_util.h"
#include "base/files/scoped_file.h"
#include "base/location.h"
-#include "base/memory/scoped_vector.h"
#include "base/pickle.h"
#include "base/posix/unix_domain_socket_linux.h"
#include "base/single_thread_task_runner.h"
@@ -40,7 +41,7 @@ TEST(UnixDomainSocketTest, SendRecvMsgAbortOnReplyFDClose) {
static_cast<uint8_t*>(NULL), 0U, static_cast<int*>(NULL), request));
// Receive the message.
- ScopedVector<ScopedFD> message_fds;
+ std::vector<ScopedFD> message_fds;
uint8_t buffer[16];
ASSERT_EQ(static_cast<int>(request.size()),
UnixDomainSocket::RecvMsg(fds[0], buffer, sizeof(buffer),
@@ -95,7 +96,7 @@ TEST(UnixDomainSocketTest, RecvPid) {
// sizeof(kHello) bytes and it wasn't just truncated to fit the buffer.
char buf[sizeof(kHello) + 1];
ProcessId sender_pid;
- ScopedVector<ScopedFD> fd_vec;
+ std::vector<ScopedFD> fd_vec;
const ssize_t nread = UnixDomainSocket::RecvMsgWithPid(
recv_sock.get(), buf, sizeof(buf), &fd_vec, &sender_pid);
ASSERT_EQ(sizeof(kHello), static_cast<size_t>(nread));
@@ -124,7 +125,7 @@ TEST(UnixDomainSocketTest, RecvPidWithMaxDescriptors) {
// sizeof(kHello) bytes and it wasn't just truncated to fit the buffer.
char buf[sizeof(kHello) + 1];
ProcessId sender_pid;
- ScopedVector<ScopedFD> recv_fds;
+ std::vector<ScopedFD> recv_fds;
const ssize_t nread = UnixDomainSocket::RecvMsgWithPid(
recv_sock.get(), buf, sizeof(buf), &recv_fds, &sender_pid);
ASSERT_EQ(sizeof(kHello), static_cast<size_t>(nread));
@@ -148,7 +149,7 @@ TEST(UnixDomianSocketTest, RecvPidDisconnectedSocket) {
char ch;
ProcessId sender_pid;
- ScopedVector<ScopedFD> recv_fds;
+ std::vector<ScopedFD> recv_fds;
const ssize_t nread = UnixDomainSocket::RecvMsgWithPid(
recv_sock.get(), &ch, sizeof(ch), &recv_fds, &sender_pid);
ASSERT_EQ(0, nread);
diff --git a/base/power_monitor/power_monitor.h b/base/power_monitor/power_monitor.h
index 4acb3bf122..683eeb9733 100644
--- a/base/power_monitor/power_monitor.h
+++ b/base/power_monitor/power_monitor.h
@@ -6,7 +6,7 @@
#define BASE_POWER_MONITOR_POWER_MONITOR_H_
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/observer_list_threadsafe.h"
#include "base/power_monitor/power_observer.h"
diff --git a/base/power_monitor/power_monitor_device_source.h b/base/power_monitor/power_monitor_device_source.h
index 29f17c2a7d..2dabac8865 100644
--- a/base/power_monitor/power_monitor_device_source.h
+++ b/base/power_monitor/power_monitor_device_source.h
@@ -6,11 +6,12 @@
#define BASE_POWER_MONITOR_POWER_MONITOR_DEVICE_SOURCE_H_
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.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"
+#include "build/build_config.h"
#if defined(OS_WIN)
#include <windows.h>
@@ -102,7 +103,7 @@ class BASE_EXPORT PowerMonitorDeviceSource : public PowerMonitorSource {
#endif
#if defined(ENABLE_BATTERY_MONITORING)
- base::OneShotTimer<PowerMonitorDeviceSource> delayed_battery_check_;
+ base::OneShotTimer delayed_battery_check_;
#endif
#if defined(OS_WIN)
diff --git a/base/power_monitor/power_monitor_source.h b/base/power_monitor/power_monitor_source.h
index b8f41850ef..e63f4f82bf 100644
--- a/base/power_monitor/power_monitor_source.h
+++ b/base/power_monitor/power_monitor_source.h
@@ -6,7 +6,7 @@
#define BASE_POWER_MONITOR_POWER_MONITOR_SOURCE_H_
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/observer_list_threadsafe.h"
#include "base/synchronization/lock.h"
diff --git a/base/prefs/OWNERS b/base/prefs/OWNERS
index 97ab695224..2d870381cb 100644
--- a/base/prefs/OWNERS
+++ b/base/prefs/OWNERS
@@ -1,5 +1,4 @@
battre@chromium.org
bauerb@chromium.org
gab@chromium.org
-mnissler@chromium.org
pam@chromium.org
diff --git a/base/prefs/persistent_pref_store.h b/base/prefs/persistent_pref_store.h
index ad8a0a3a66..89c7a71961 100644
--- a/base/prefs/persistent_pref_store.h
+++ b/base/prefs/persistent_pref_store.h
@@ -33,9 +33,6 @@ class BASE_PREFS_EXPORT PersistentPrefStore : public WriteablePrefStore {
// Indicates that ReadPrefs() couldn't complete synchronously and is waiting
// for an asynchronous task to complete first.
PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE = 10,
- PREF_READ_ERROR_LEVELDB_IO = 11,
- PREF_READ_ERROR_LEVELDB_CORRUPTION_READ_ONLY = 12,
- PREF_READ_ERROR_LEVELDB_CORRUPTION = 13,
PREF_READ_ERROR_MAX_ENUM
};
diff --git a/base/prefs/writeable_pref_store.h b/base/prefs/writeable_pref_store.h
index d85b4c8d42..f7da279ac0 100644
--- a/base/prefs/writeable_pref_store.h
+++ b/base/prefs/writeable_pref_store.h
@@ -5,9 +5,12 @@
#ifndef BASE_PREFS_WRITEABLE_PREF_STORE_H_
#define BASE_PREFS_WRITEABLE_PREF_STORE_H_
+#include <stdint.h>
+
#include <string>
-#include "base/basictypes.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
#include "base/prefs/pref_store.h"
namespace base {
@@ -19,7 +22,7 @@ class BASE_PREFS_EXPORT WriteablePrefStore : public PrefStore {
public:
// PrefWriteFlags can be used to change the way a pref will be written to
// storage.
- enum PrefWriteFlags : uint32 {
+ enum PrefWriteFlags : uint32_t {
// No flags are specified.
DEFAULT_PREF_WRITE_FLAGS = 0,
@@ -30,14 +33,14 @@ class BASE_PREFS_EXPORT WriteablePrefStore : public PrefStore {
WriteablePrefStore() {}
- // Sets a |value| for |key| in the store. Assumes ownership of |value|, which
- // must be non-NULL. |flags| is a bitmask of PrefWriteFlags.
+ // Sets a |value| for |key| in the store. |value| must be non-NULL. |flags| is
+ // a bitmask of PrefWriteFlags.
virtual void SetValue(const std::string& key,
- base::Value* value,
- uint32 flags) = 0;
+ scoped_ptr<base::Value> value,
+ uint32_t flags) = 0;
// Removes the value for |key|.
- virtual void RemoveValue(const std::string& key, uint32 flags) = 0;
+ virtual void RemoveValue(const std::string& key, uint32_t flags) = 0;
// Equivalent to PrefStore::GetValue but returns a mutable value.
virtual bool GetMutableValue(const std::string& key,
@@ -48,7 +51,7 @@ class BASE_PREFS_EXPORT WriteablePrefStore : public PrefStore {
// value. SetValue takes care of notifications itself. Note that
// ReportValueChanged will trigger notifications even if nothing has changed.
// |flags| is a bitmask of PrefWriteFlags.
- virtual void ReportValueChanged(const std::string& key, uint32 flags) = 0;
+ virtual void ReportValueChanged(const std::string& key, uint32_t flags) = 0;
// Same as SetValue, but doesn't generate notifications. This is used by
// PrefService::GetMutableUserPref() in order to put empty entries
@@ -56,8 +59,8 @@ class BASE_PREFS_EXPORT WriteablePrefStore : public PrefStore {
// tests rely on the number of notifications generated. |flags| is a bitmask
// of PrefWriteFlags.
virtual void SetValueSilently(const std::string& key,
- base::Value* value,
- uint32 flags) = 0;
+ scoped_ptr<base::Value> value,
+ uint32_t flags) = 0;
protected:
~WriteablePrefStore() override {}
diff --git a/base/process/BUILD.gn b/base/process/BUILD.gn
deleted file mode 100644
index 814459b13e..0000000000
--- a/base/process/BUILD.gn
+++ /dev/null
@@ -1,108 +0,0 @@
-# Copyright (c) 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-source_set("process") {
- sources = [
- "internal_linux.cc",
- "internal_linux.h",
- "kill.cc",
- "kill.h",
- "kill_mac.cc",
- "kill_posix.cc",
- "kill_win.cc",
- "launch.cc",
- "launch.h",
- "launch_ios.cc",
- "launch_mac.cc",
- "launch_posix.cc",
- "launch_win.cc",
- "memory.cc",
- "memory.h",
- "memory_linux.cc",
- "memory_mac.mm",
- "memory_win.cc",
- "process.h",
- "process_handle_freebsd.cc",
- "process_handle_linux.cc",
- "process_handle_mac.cc",
- "process_handle_openbsd.cc",
- "process_handle_posix.cc",
- "process_handle_win.cc",
- "process_info.h",
- "process_info_linux.cc",
- "process_info_mac.cc",
- "process_info_win.cc",
- "process_iterator.cc",
- "process_iterator.h",
- "process_iterator_freebsd.cc",
- "process_iterator_linux.cc",
- "process_iterator_mac.cc",
- "process_iterator_openbsd.cc",
- "process_iterator_win.cc",
- "process_linux.cc",
- "process_mac.cc",
- "process_metrics.cc",
- "process_metrics.h",
- "process_metrics_freebsd.cc",
- "process_metrics_ios.cc",
- "process_metrics_linux.cc",
- "process_metrics_mac.cc",
- "process_metrics_openbsd.cc",
- "process_metrics_posix.cc",
- "process_metrics_win.cc",
- "process_posix.cc",
- "process_win.cc",
- ]
-
- sources -= [
- "process_handle_freebsd.cc",
- "process_handle_openbsd.cc",
- "process_iterator_freebsd.cc",
- "process_iterator_openbsd.cc",
- "process_metrics_freebsd.cc",
- "process_metrics_openbsd.cc",
- ]
-
- if (is_android) {
- # Android uses some Linux sources, put those back.
- set_sources_assignment_filter([])
- sources += [
- "internal_linux.cc",
- "memory_linux.cc",
- "process_handle_linux.cc",
- "process_iterator_linux.cc",
- "process_metrics_linux.cc",
- ]
- set_sources_assignment_filter(sources_assignment_filter)
- }
-
- if (is_nacl) {
- sources -= [
- "kill.cc",
- "kill.h",
- "kill_posix.cc",
- "launch.cc",
- "launch.h",
- "launch_posix.cc",
- "memory.cc",
- "memory.h",
- "process_iterator.cc",
- "process_iterator.h",
- "process_metrics.cc",
- "process_metrics_posix.cc",
- "process_posix.cc",
- ]
- }
-
- configs += [ "//base:base_implementation" ]
-
- deps = [
- "//base/memory",
- "//base/third_party/dynamic_annotations",
- ]
-
- allow_circular_includes_from = [ "//base/memory" ]
-
- visibility = [ "//base/*" ]
-}
diff --git a/base/process/internal_linux.cc b/base/process/internal_linux.cc
index d2e9ec52e5..d286f4e753 100644
--- a/base/process/internal_linux.cc
+++ b/base/process/internal_linux.cc
@@ -4,6 +4,7 @@
#include "base/process/internal_linux.h"
+#include <limits.h>
#include <unistd.h>
#include <map>
@@ -25,8 +26,8 @@ const char kProcDir[] = "/proc";
const char kStatFile[] = "stat";
-base::FilePath GetProcPidDir(pid_t pid) {
- return base::FilePath(kProcDir).Append(IntToString(pid));
+FilePath GetProcPidDir(pid_t pid) {
+ return FilePath(kProcDir).Append(IntToString(pid));
}
pid_t ProcDirSlotToPid(const char* d_name) {
@@ -97,8 +98,9 @@ bool ParseProcStats(const std::string& stats_data,
close_parens_idx - (open_parens_idx + 1)));
// Split the rest.
- std::vector<std::string> other_stats;
- SplitString(stats_data.substr(close_parens_idx + 2), ' ', &other_stats);
+ std::vector<std::string> other_stats = SplitString(
+ stats_data.substr(close_parens_idx + 2), " ",
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
for (size_t i = 0; i < other_stats.size(); ++i)
proc_stats->push_back(other_stats[i]);
return true;
@@ -106,19 +108,19 @@ bool ParseProcStats(const std::string& stats_data,
typedef std::map<std::string, std::string> ProcStatMap;
void ParseProcStat(const std::string& contents, ProcStatMap* output) {
- base::StringPairs key_value_pairs;
+ StringPairs key_value_pairs;
SplitStringIntoKeyValuePairs(contents, ' ', '\n', &key_value_pairs);
for (size_t i = 0; i < key_value_pairs.size(); ++i) {
output->insert(key_value_pairs[i]);
}
}
-int64 GetProcStatsFieldAsInt64(const std::vector<std::string>& proc_stats,
- ProcStatsFields field_num) {
+int64_t GetProcStatsFieldAsInt64(const std::vector<std::string>& proc_stats,
+ ProcStatsFields field_num) {
DCHECK_GE(field_num, VM_PPID);
CHECK_LT(static_cast<size_t>(field_num), proc_stats.size());
- int64 value;
+ int64_t value;
return StringToInt64(proc_stats[field_num], &value) ? value : 0;
}
@@ -131,7 +133,7 @@ size_t GetProcStatsFieldAsSizeT(const std::vector<std::string>& proc_stats,
return StringToSizeT(proc_stats[field_num], &value) ? value : 0;
}
-int64 ReadProcStatsAndGetFieldAsInt64(pid_t pid, ProcStatsFields field_num) {
+int64_t ReadProcStatsAndGetFieldAsInt64(pid_t pid, ProcStatsFields field_num) {
std::string stats_data;
if (!ReadProcStats(pid, &stats_data))
return 0;
diff --git a/base/process/internal_linux.h b/base/process/internal_linux.h
index 1837f94ce5..ba793f7cc7 100644
--- a/base/process/internal_linux.h
+++ b/base/process/internal_linux.h
@@ -8,6 +8,8 @@
#ifndef BASE_PROCESS_INTERNAL_LINUX_H_
#define BASE_PROCESS_INTERNAL_LINUX_H_
+#include <stddef.h>
+#include <stdint.h>
#include <unistd.h>
#include "base/files/file_path.h"
@@ -63,8 +65,8 @@ enum ProcStatsFields {
// 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.
-int64 GetProcStatsFieldAsInt64(const std::vector<std::string>& proc_stats,
- ProcStatsFields field_num);
+int64_t GetProcStatsFieldAsInt64(const std::vector<std::string>& proc_stats,
+ ProcStatsFields field_num);
// Same as GetProcStatsFieldAsInt64(), but for size_t values.
size_t GetProcStatsFieldAsSizeT(const std::vector<std::string>& proc_stats,
@@ -72,7 +74,7 @@ size_t GetProcStatsFieldAsSizeT(const std::vector<std::string>& proc_stats,
// Convenience wrapper around GetProcStatsFieldAsInt64(), ParseProcStats() and
// ReadProcStats(). See GetProcStatsFieldAsInt64() for details.
-int64 ReadProcStatsAndGetFieldAsInt64(pid_t pid, ProcStatsFields field_num);
+int64_t ReadProcStatsAndGetFieldAsInt64(pid_t pid, ProcStatsFields field_num);
// Same as ReadProcStatsAndGetFieldAsInt64() but for size_t values.
size_t ReadProcStatsAndGetFieldAsSizeT(pid_t pid,
diff --git a/base/process/kill.h b/base/process/kill.h
index dbd32e1705..c664f33262 100644
--- a/base/process/kill.h
+++ b/base/process/kill.h
@@ -12,6 +12,7 @@
#include "base/process/process.h"
#include "base/process/process_handle.h"
#include "base/time/time.h"
+#include "build/build_config.h"
namespace base {
@@ -37,6 +38,7 @@ enum TerminationStatus {
// a hint.
TERMINATION_STATUS_OOM_PROTECTED, // child was protected from oom kill
#endif
+ TERMINATION_STATUS_LAUNCH_FAILED, // child process never launched
TERMINATION_STATUS_MAX_ENUM
};
diff --git a/base/process/kill_posix.cc b/base/process/kill_posix.cc
index f0d2d44227..85470e05f9 100644
--- a/base/process/kill_posix.cc
+++ b/base/process/kill_posix.cc
@@ -4,6 +4,7 @@
#include "base/process/kill.h"
+#include <errno.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
@@ -12,10 +13,12 @@
#include "base/files/file_util.h"
#include "base/files/scoped_file.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/posix/eintr_wrapper.h"
#include "base/process/process_iterator.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/platform_thread.h"
+#include "build/build_config.h"
namespace base {
diff --git a/base/process/launch.cc b/base/process/launch.cc
index c179b2f5f3..f09317dc73 100644
--- a/base/process/launch.cc
+++ b/base/process/launch.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "base/process/launch.h"
+#include "build/build_config.h"
namespace base {
diff --git a/base/process/launch.h b/base/process/launch.h
index 56f27a8210..9a76e2048e 100644
--- a/base/process/launch.h
+++ b/base/process/launch.h
@@ -7,16 +7,19 @@
#ifndef BASE_PROCESS_LAUNCH_H_
#define BASE_PROCESS_LAUNCH_H_
+#include <stddef.h>
+
#include <string>
#include <utility>
#include <vector>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/environment.h"
+#include "base/macros.h"
#include "base/process/process.h"
#include "base/process/process_handle.h"
#include "base/strings/string_piece.h"
+#include "build/build_config.h"
#if defined(OS_POSIX)
#include "base/posix/file_descriptor_shuffle.h"
@@ -164,16 +167,6 @@ struct BASE_EXPORT LaunchOptions {
// process' controlling terminal.
int ctrl_terminal_fd;
#endif // defined(OS_CHROMEOS)
-
-#if defined(OS_MACOSX)
- // If this name is non-empty, the new child, after fork() but before exec(),
- // will look up this server name in the bootstrap namespace. The resulting
- // service port will be replaced as the bootstrap port in the child. Because
- // the process's IPC space is cleared on exec(), any rights to the old
- // bootstrap port will not be transferred to the new process.
- std::string replacement_bootstrap_name;
-#endif
-
#endif // !defined(OS_WIN)
};
@@ -236,7 +229,7 @@ BASE_EXPORT bool SetJobObjectLimitFlags(HANDLE job_object, DWORD limit_flags);
// 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();
+BASE_EXPORT void RouteStdioToConsole(bool create_console_if_not_found);
#endif // defined(OS_WIN)
// Executes the application specified by |cl| and wait for it to exit. Stores
@@ -245,6 +238,10 @@ BASE_EXPORT void RouteStdioToConsole();
// indicating success).
BASE_EXPORT bool GetAppOutput(const CommandLine& cl, std::string* output);
+// Like GetAppOutput, but also includes stderr.
+BASE_EXPORT bool GetAppOutputAndError(const CommandLine& cl,
+ std::string* output);
+
#if defined(OS_WIN)
// A Windows-specific version of GetAppOutput that takes a command line string
// instead of a CommandLine object. Useful for situations where you need to
@@ -286,18 +283,13 @@ BASE_EXPORT void RaiseProcessToHighPriority();
// in the child after forking will restore the standard exception handler.
// See http://crbug.com/20371/ for more details.
void RestoreDefaultExceptionHandler();
-
-// Look up the bootstrap server named |replacement_bootstrap_name| via the
-// current |bootstrap_port|. Then replace the task's bootstrap port with the
-// received right.
-void ReplaceBootstrapPort(const std::string& replacement_bootstrap_name);
#endif // defined(OS_MACOSX)
// Creates a LaunchOptions object suitable for launching processes in a test
// binary. This should not be called in production/released code.
BASE_EXPORT LaunchOptions LaunchOptionsForTest();
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_NACL_NONSFI)
// A wrapper for clone with fork-like behavior, meaning that it returns the
// child's pid in the parent and 0 in the child. |flags|, |ptid|, and |ctid| are
// as in the clone system call (the CLONE_VM flag is not supported).
diff --git a/base/process/launch_mac.cc b/base/process/launch_mac.cc
index ce02475541..5895eae435 100644
--- a/base/process/launch_mac.cc
+++ b/base/process/launch_mac.cc
@@ -28,21 +28,4 @@ void RestoreDefaultExceptionHandler() {
EXCEPTION_DEFAULT, THREAD_STATE_NONE);
}
-void ReplaceBootstrapPort(const std::string& new_bootstrap_name) {
- // This function is called between fork() and exec(), so it should take care
- // to run properly in that situation.
-
- mach_port_t port = MACH_PORT_NULL;
- kern_return_t kr = bootstrap_look_up(bootstrap_port,
- new_bootstrap_name.c_str(), &port);
- if (kr != KERN_SUCCESS) {
- RAW_LOG(FATAL, "Failed to look up replacement bootstrap port.");
- }
-
- kr = task_set_bootstrap_port(mach_task_self(), port);
- if (kr != KERN_SUCCESS) {
- RAW_LOG(FATAL, "Failed to replace bootstrap port.");
- }
-}
-
} // namespace base
diff --git a/base/process/launch_posix.cc b/base/process/launch_posix.cc
index 6beae2d607..6a2f5ce339 100644
--- a/base/process/launch_posix.cc
+++ b/base/process/launch_posix.cc
@@ -10,6 +10,8 @@
#include <sched.h>
#include <setjmp.h>
#include <signal.h>
+#include <stddef.h>
+#include <stdint.h>
#include <stdlib.h>
#include <sys/resource.h>
#include <sys/syscall.h>
@@ -22,7 +24,6 @@
#include <limits>
#include <set>
-#include "base/allocator/type_profiler_control.h"
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/debug/debugger.h"
@@ -64,6 +65,8 @@ extern char** environ;
namespace base {
+#if !defined(OS_NACL_NONSFI)
+
namespace {
// Get the process's "environment" (i.e. the thing that setenv/getenv
@@ -188,55 +191,6 @@ void ResetChildSignalHandlersToDefaults(void) {
}
#endif // !defined(OS_LINUX) ||
// (!defined(__i386__) && !defined(__x86_64__) && !defined(__arm__))
-
-#if defined(OS_LINUX)
-bool IsRunningOnValgrind() {
- return RUNNING_ON_VALGRIND;
-}
-
-// This function runs on the stack specified on the clone call. It uses longjmp
-// to switch back to the original stack so the child can return from sys_clone.
-int CloneHelper(void* arg) {
- jmp_buf* env_ptr = reinterpret_cast<jmp_buf*>(arg);
- longjmp(*env_ptr, 1);
-
- // Should not be reached.
- RAW_CHECK(false);
- return 1;
-}
-
-// This function is noinline to ensure that stack_buf is below the stack pointer
-// that is saved when setjmp is called below. This is needed because when
-// compiled with FORTIFY_SOURCE, glibc's longjmp checks that the stack is moved
-// upwards. See crbug.com/442912 for more details.
-#if defined(ADDRESS_SANITIZER)
-// Disable AddressSanitizer instrumentation for this function to make sure
-// |stack_buf| is allocated on thread stack instead of ASan's fake stack.
-// Under ASan longjmp() will attempt to clean up the area between the old and
-// new stack pointers and print a warning that may confuse the user.
-__attribute__((no_sanitize_address))
-#endif
-NOINLINE pid_t CloneAndLongjmpInChild(unsigned long flags,
- pid_t* ptid,
- pid_t* ctid,
- jmp_buf* env) {
- // We use the libc clone wrapper instead of making the syscall
- // directly because making the syscall may fail to update the libc's
- // internal pid cache. The libc interface unfortunately requires
- // specifying a new stack, so we use setjmp/longjmp to emulate
- // fork-like behavior.
- char stack_buf[PTHREAD_STACK_MIN];
-#if defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARM_FAMILY) || \
- defined(ARCH_CPU_MIPS64_FAMILY) || defined(ARCH_CPU_MIPS_FAMILY)
- // The stack grows downward.
- void* stack = stack_buf + sizeof(stack_buf);
-#else
-#error "Unsupported architecture"
-#endif
- return clone(&CloneHelper, stack, flags, env, ptid, nullptr, ctid);
-}
-#endif // defined(OS_LINUX)
-
} // anonymous namespace
// Functor for |ScopedDIR| (below).
@@ -439,11 +393,6 @@ Process LaunchProcess(const std::vector<std::string>& argv,
}
}
- // 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.
for (size_t i = 0; i < options.maximize_rlimits->size(); ++i) {
@@ -462,8 +411,6 @@ Process LaunchProcess(const std::vector<std::string>& argv,
#if defined(OS_MACOSX)
RestoreDefaultExceptionHandler();
- if (!options.replacement_bootstrap_name.empty())
- ReplaceBootstrapPort(options.replacement_bootstrap_name);
#endif // defined(OS_MACOSX)
ResetChildSignalHandlersToDefaults();
@@ -577,7 +524,8 @@ enum GetAppOutputInternalResult {
// 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.
+// environment. If |include_stderr| is true, includes stderr otherwise redirects
+// it 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.
@@ -590,6 +538,7 @@ enum GetAppOutputInternalResult {
static GetAppOutputInternalResult GetAppOutputInternal(
const std::vector<std::string>& argv,
char* const envp[],
+ bool include_stderr,
std::string* output,
size_t max_output,
bool do_search_path,
@@ -638,13 +587,10 @@ static GetAppOutputInternalResult GetAppOutputInternal(
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(
+ include_stderr ? pipe_fd[1] : 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.
@@ -713,11 +659,20 @@ bool GetAppOutput(const std::vector<std::string>& 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<std::size_t>::max(), true,
+ argv, NULL, false, output, std::numeric_limits<std::size_t>::max(), true,
&exit_code);
return result == EXECUTE_SUCCESS && exit_code == EXIT_SUCCESS;
}
+bool GetAppOutputAndError(const CommandLine& cl, std::string* output) {
+ // Run |execve()| with the current environment and store "unlimited" data.
+ int exit_code;
+ GetAppOutputInternalResult result = GetAppOutputInternal(
+ cl.argv(), NULL, true, output, std::numeric_limits<std::size_t>::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,
@@ -726,7 +681,7 @@ bool GetAppOutputRestricted(const CommandLine& cl,
char* const empty_environ = NULL;
int exit_code;
GetAppOutputInternalResult result = GetAppOutputInternal(
- cl.argv(), &empty_environ, output, max_output, false, &exit_code);
+ cl.argv(), &empty_environ, false, output, max_output, false, &exit_code);
return result == GOT_MAX_OUTPUT || (result == EXECUTE_SUCCESS &&
exit_code == EXIT_SUCCESS);
}
@@ -736,12 +691,64 @@ bool GetAppOutputWithExitCode(const CommandLine& cl,
int* exit_code) {
// Run |execve()| with the current environment and store "unlimited" data.
GetAppOutputInternalResult result = GetAppOutputInternal(
- cl.argv(), NULL, output, std::numeric_limits<std::size_t>::max(), true,
- exit_code);
+ cl.argv(), NULL, false, output, std::numeric_limits<std::size_t>::max(),
+ true, exit_code);
return result == EXECUTE_SUCCESS;
}
-#if defined(OS_LINUX)
+#endif // !defined(OS_NACL_NONSFI)
+
+#if defined(OS_LINUX) || defined(OS_NACL_NONSFI)
+namespace {
+
+bool IsRunningOnValgrind() {
+ return RUNNING_ON_VALGRIND;
+}
+
+// This function runs on the stack specified on the clone call. It uses longjmp
+// to switch back to the original stack so the child can return from sys_clone.
+int CloneHelper(void* arg) {
+ jmp_buf* env_ptr = reinterpret_cast<jmp_buf*>(arg);
+ longjmp(*env_ptr, 1);
+
+ // Should not be reached.
+ RAW_CHECK(false);
+ return 1;
+}
+
+// This function is noinline to ensure that stack_buf is below the stack pointer
+// that is saved when setjmp is called below. This is needed because when
+// compiled with FORTIFY_SOURCE, glibc's longjmp checks that the stack is moved
+// upwards. See crbug.com/442912 for more details.
+#if defined(ADDRESS_SANITIZER)
+// Disable AddressSanitizer instrumentation for this function to make sure
+// |stack_buf| is allocated on thread stack instead of ASan's fake stack.
+// Under ASan longjmp() will attempt to clean up the area between the old and
+// new stack pointers and print a warning that may confuse the user.
+__attribute__((no_sanitize_address))
+#endif
+NOINLINE pid_t CloneAndLongjmpInChild(unsigned long flags,
+ pid_t* ptid,
+ pid_t* ctid,
+ jmp_buf* env) {
+ // We use the libc clone wrapper instead of making the syscall
+ // directly because making the syscall may fail to update the libc's
+ // internal pid cache. The libc interface unfortunately requires
+ // specifying a new stack, so we use setjmp/longjmp to emulate
+ // fork-like behavior.
+ char stack_buf[PTHREAD_STACK_MIN];
+#if defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARM_FAMILY) || \
+ defined(ARCH_CPU_MIPS64_FAMILY) || defined(ARCH_CPU_MIPS_FAMILY)
+ // The stack grows downward.
+ void* stack = stack_buf + sizeof(stack_buf);
+#else
+#error "Unsupported architecture"
+#endif
+ return clone(&CloneHelper, stack, flags, env, ptid, nullptr, ctid);
+}
+
+} // anonymous namespace
+
pid_t ForkWithFlags(unsigned long flags, pid_t* ptid, pid_t* ctid) {
const bool clone_tls_used = flags & CLONE_SETTLS;
const bool invalid_ctid =
@@ -780,6 +787,6 @@ pid_t ForkWithFlags(unsigned long flags, pid_t* ptid, pid_t* ctid) {
return 0;
}
-#endif // defined(OS_LINUX)
+#endif // defined(OS_LINUX) || defined(OS_NACL_NONSFI)
} // namespace base
diff --git a/base/process/process.h b/base/process/process.h
index 1559554c01..75f6a009df 100644
--- a/base/process/process.h
+++ b/base/process/process.h
@@ -6,7 +6,6 @@
#define BASE_PROCESS_PROCESS_H_
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/move.h"
#include "base/process/process_handle.h"
#include "base/time/time.h"
@@ -32,19 +31,17 @@ namespace base {
// the process dies, and it may be reused by the system, which means that it may
// end up pointing to the wrong process.
class BASE_EXPORT Process {
- MOVE_ONLY_TYPE_FOR_CPP_03(Process, RValue)
+ MOVE_ONLY_TYPE_FOR_CPP_03(Process)
public:
explicit Process(ProcessHandle handle = kNullProcessHandle);
- // Move constructor for C++03 move emulation of this type.
- Process(RValue other);
+ Process(Process&& other);
// The destructor does not terminate the process.
~Process();
- // Move operator= for C++03 move emulation of this type.
- Process& operator=(RValue other);
+ Process& operator=(Process&& other);
// Returns an object for the current process.
static Process Current();
@@ -111,24 +108,6 @@ class BASE_EXPORT Process {
// is not required.
bool WaitForExitWithTimeout(TimeDelta timeout, int* exit_code);
-#if defined(OS_MACOSX)
- // The Mac needs a Mach port in order to manipulate a process's priority,
- // and there's no good way to get that from base given the pid. These Mac
- // variants of the IsProcessBackgrounded and SetProcessBackgrounded API take
- // the Mach port for this reason. See crbug.com/460102
- //
- // A process is backgrounded when its priority is lower than normal.
- // Return true if the process with mach port |task_port| is backgrounded,
- // false otherwise.
- bool IsProcessBackgrounded(mach_port_t task_port) const;
-
- // Set the process with the specified mach port 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(mach_port_t task_port, bool value);
-#else
// A process is backgrounded when it's priority is lower than normal.
// Return true if this process is backgrounded, false otherwise.
bool IsProcessBackgrounded() const;
@@ -138,11 +117,18 @@ class BASE_EXPORT Process {
// will be made "normal" - equivalent to default process priority.
// Returns true if the priority was changed, false otherwise.
bool SetProcessBackgrounded(bool value);
-#endif // defined(OS_MACOSX)
+
// Returns an integer representing the priority of a process. The meaning
// of this value is OS dependent.
int GetPriority() const;
+#if defined(OS_CHROMEOS)
+ // Get the PID in its PID namespace.
+ // If the process is not in a PID namespace or /proc/<pid>/status does not
+ // report NSpid, kNullProcessId is returned.
+ ProcessId GetPidInNamespace() const;
+#endif
+
private:
#if defined(OS_WIN)
bool is_current_process_;
@@ -152,6 +138,14 @@ class BASE_EXPORT Process {
#endif
};
+#if defined(OS_CHROMEOS)
+// Exposed for testing.
+// Given the contents of the /proc/<pid>/cgroup file, determine whether the
+// process is backgrounded or not.
+BASE_EXPORT bool IsProcessBackgroundedCGroup(
+ const StringPiece& cgroup_contents);
+#endif // defined(OS_CHROMEOS)
+
} // namespace base
#endif // BASE_PROCESS_PROCESS_H_
diff --git a/base/process/process_handle.h b/base/process/process_handle.h
index 77f2c585cf..ef7a602552 100644
--- a/base/process/process_handle.h
+++ b/base/process/process_handle.h
@@ -5,12 +5,13 @@
#ifndef BASE_PROCESS_PROCESS_HANDLE_H_
#define BASE_PROCESS_PROCESS_HANDLE_H_
+#include <stdint.h>
+#include <sys/types.h>
+
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/files/file_path.h"
#include "build/build_config.h"
-#include <sys/types.h>
#if defined(OS_WIN)
#include <windows.h>
#endif
@@ -35,23 +36,44 @@ const ProcessId kNullProcessId = 0;
#endif // defined(OS_WIN)
// Returns the id of the current process.
+// Note that on some platforms, this is not guaranteed to be unique across
+// processes (use GetUniqueIdForProcess if uniqueness is required).
BASE_EXPORT ProcessId GetCurrentProcId();
+// Returns a unique ID for the current process. The ID will be unique across all
+// currently running processes within the chrome session, but IDs of terminated
+// processes may be reused. This returns an opaque value that is different from
+// a process's PID.
+BASE_EXPORT uint32_t GetUniqueIdForProcess();
+
+#if defined(OS_LINUX)
+// When a process is started in a different PID namespace from the browser
+// process, this function must be called with the process's PID in the browser's
+// PID namespace in order to initialize its unique ID. Not thread safe.
+// WARNING: To avoid inconsistent results from GetUniqueIdForProcess, this
+// should only be called very early after process startup - ideally as soon
+// after process creation as possible.
+BASE_EXPORT void InitUniqueIdForProcessInPidNamespace(
+ ProcessId pid_outside_of_namespace);
+#endif
+
// Returns the ProcessHandle of the current process.
BASE_EXPORT ProcessHandle GetCurrentProcessHandle();
-// 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.
+// Returns the process 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.
// DEPRECATED. New code should be using Process::Pid() instead.
+// Note that on some platforms, this is not guaranteed to be unique across
+// processes.
BASE_EXPORT ProcessId GetProcId(ProcessHandle process);
+// Returns the ID for the parent of the given process.
+BASE_EXPORT ProcessId GetParentProcessId(ProcessHandle process);
+
#if defined(OS_POSIX)
// Returns the path to the executable of the given process.
BASE_EXPORT FilePath GetProcessExecutablePath(ProcessHandle process);
-
-// Returns the ID for the parent of the given process.
-BASE_EXPORT ProcessId GetParentProcessId(ProcessHandle process);
#endif
} // namespace base
diff --git a/base/process/process_handle_mac.cc b/base/process/process_handle_mac.cc
index cbf0bc5c43..d9d22f7831 100644
--- a/base/process/process_handle_mac.cc
+++ b/base/process/process_handle_mac.cc
@@ -5,6 +5,7 @@
#include "base/process/process_handle.h"
#include <libproc.h>
+#include <stddef.h>
#include <sys/sysctl.h>
#include <sys/types.h>
diff --git a/base/process/process_info.h b/base/process/process_info.h
index 85f204d04c..1d76f42eb2 100644
--- a/base/process/process_info.h
+++ b/base/process/process_info.h
@@ -6,7 +6,6 @@
#define BASE_PROCESS_PROCESS_INFO_H_
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "build/build_config.h"
namespace base {
diff --git a/base/process/process_iterator.cc b/base/process/process_iterator.cc
index b9ef047732..94f53b60cb 100644
--- a/base/process/process_iterator.cc
+++ b/base/process/process_iterator.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "base/process/process_iterator.h"
+#include "build/build_config.h"
namespace base {
diff --git a/base/process/process_iterator.h b/base/process/process_iterator.h
index ec6500e653..26fe6903ce 100644
--- a/base/process/process_iterator.h
+++ b/base/process/process_iterator.h
@@ -7,13 +7,15 @@
#ifndef BASE_PROCESS_PROCESS_ITERATOR_H_
#define BASE_PROCESS_PROCESS_ITERATOR_H_
+#include <stddef.h>
+
#include <list>
#include <string>
#include <vector>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/files/file_path.h"
+#include "base/macros.h"
#include "base/process/process.h"
#include "build/build_config.h"
diff --git a/base/process/process_iterator_linux.cc b/base/process/process_iterator_linux.cc
index 3319552f38..94a35766e9 100644
--- a/base/process/process_iterator_linux.cc
+++ b/base/process/process_iterator_linux.cc
@@ -4,9 +4,12 @@
#include "base/process/process_iterator.h"
+#include <stddef.h>
+
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/process/internal_linux.h"
+#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/threading/thread_restrictions.h"
@@ -48,7 +51,8 @@ bool GetProcCmdline(pid_t pid, std::vector<std::string>* proc_cmd_line_args) {
return false;
std::string delimiters;
delimiters.push_back('\0');
- Tokenize(cmd_line, delimiters, proc_cmd_line_args);
+ *proc_cmd_line_args = SplitString(cmd_line, delimiters, KEEP_WHITESPACE,
+ SPLIT_WANT_NONEMPTY);
return true;
}
diff --git a/base/process/process_iterator_mac.cc b/base/process/process_iterator_mac.cc
index 99384073ea..3d616980ab 100644
--- a/base/process/process_iterator_mac.cc
+++ b/base/process/process_iterator_mac.cc
@@ -5,11 +5,14 @@
#include "base/process/process_iterator.h"
#include <errno.h>
+#include <stddef.h>
#include <sys/sysctl.h>
#include <sys/types.h>
#include <unistd.h>
#include "base/logging.h"
+#include "base/macros.h"
+#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
namespace base {
@@ -100,7 +103,8 @@ bool ProcessIterator::CheckForNextProcess() {
// |entry_.cmd_line_args_|.
std::string delimiters;
delimiters.push_back('\0');
- Tokenize(data, delimiters, &entry_.cmd_line_args_);
+ entry_.cmd_line_args_ = SplitString(data, delimiters,
+ KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY);
// |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
diff --git a/base/process/process_metrics.cc b/base/process/process_metrics.cc
index e486339107..a21891d912 100644
--- a/base/process/process_metrics.cc
+++ b/base/process/process_metrics.cc
@@ -4,8 +4,11 @@
#include "base/process/process_metrics.h"
+#include <utility>
+
#include "base/logging.h"
#include "base/values.h"
+#include "build/build_config.h"
namespace base {
@@ -40,7 +43,15 @@ scoped_ptr<Value> SystemMetrics::ToValue() const {
res->Set("swapinfo", swap_info_.ToValue());
#endif
- return res.Pass();
+ return std::move(res);
+}
+
+ProcessMetrics* ProcessMetrics::CreateCurrentProcessMetrics() {
+#if !defined(OS_MACOSX) || defined(OS_IOS)
+ return CreateProcessMetrics(base::GetCurrentProcessHandle());
+#else
+ return CreateProcessMetrics(base::GetCurrentProcessHandle(), nullptr);
+#endif // !defined(OS_MACOSX) || defined(OS_IOS)
}
double ProcessMetrics::GetPlatformIndependentCPUUsage() {
@@ -53,7 +64,7 @@ double ProcessMetrics::GetPlatformIndependentCPUUsage() {
#if defined(OS_MACOSX) || defined(OS_LINUX)
int ProcessMetrics::CalculateIdleWakeupsPerSecond(
- uint64 absolute_idle_wakeups) {
+ uint64_t absolute_idle_wakeups) {
TimeTicks time = TimeTicks::Now();
if (last_absolute_idle_wakeups_ == 0) {
@@ -63,8 +74,8 @@ int ProcessMetrics::CalculateIdleWakeupsPerSecond(
return 0;
}
- int64 wakeups_delta = absolute_idle_wakeups - last_absolute_idle_wakeups_;
- int64 time_delta = (time - last_idle_wakeups_time_).InMicroseconds();
+ int64_t wakeups_delta = absolute_idle_wakeups - last_absolute_idle_wakeups_;
+ int64_t time_delta = (time - last_idle_wakeups_time_).InMicroseconds();
if (time_delta == 0) {
NOTREACHED();
return 0;
@@ -74,7 +85,7 @@ int ProcessMetrics::CalculateIdleWakeupsPerSecond(
last_absolute_idle_wakeups_ = absolute_idle_wakeups;
// Round to average wakeups per second.
- int64 wakeups_delta_for_ms = wakeups_delta * Time::kMicrosecondsPerSecond;
+ int64_t wakeups_delta_for_ms = wakeups_delta * Time::kMicrosecondsPerSecond;
return (wakeups_delta_for_ms + time_delta / 2) / time_delta;
}
#else
diff --git a/base/process/process_metrics.h b/base/process/process_metrics.h
index 5916b94148..8d8f7fc4ea 100644
--- a/base/process/process_metrics.h
+++ b/base/process/process_metrics.h
@@ -8,17 +8,22 @@
#ifndef BASE_PROCESS_PROCESS_METRICS_H_
#define BASE_PROCESS_PROCESS_METRICS_H_
+#include <stddef.h>
+#include <stdint.h>
+
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/gtest_prod_util.h"
+#include "base/macros.h"
#include "base/process/process_handle.h"
#include "base/time/time.h"
#include "base/values.h"
+#include "build/build_config.h"
#if defined(OS_MACOSX)
#include <mach/mach.h>
+#include "base/process/port_provider_mac.h"
#endif
namespace base {
@@ -86,11 +91,12 @@ struct CommittedKBytes {
};
// Convert a POSIX timeval to microseconds.
-BASE_EXPORT int64 TimeValToMicroseconds(const struct timeval& tv);
+BASE_EXPORT int64_t 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
+// IO counters). Use CreateCurrentProcessMetrics() to get an instance for the
+// current process, or CreateProcessMetrics() to get an instance for an
+// arbitrary process. Then, access the information with the different get
// methods.
class BASE_EXPORT ProcessMetrics {
public:
@@ -101,16 +107,6 @@ class BASE_EXPORT ProcessMetrics {
#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
@@ -119,6 +115,11 @@ class BASE_EXPORT ProcessMetrics {
PortProvider* port_provider);
#endif // !defined(OS_MACOSX) || defined(OS_IOS)
+ // Creates a ProcessMetrics for the current process. This a cross-platform
+ // convenience wrapper for CreateProcessMetrics().
+ // The caller owns the returned object.
+ static ProcessMetrics* CreateCurrentProcessMetrics();
+
// 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.
@@ -140,7 +141,8 @@ class BASE_EXPORT ProcessMetrics {
// 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.
+ // usage in bytes, as per definition of WorkingSetBytes. Note that this
+ // function is somewhat expensive on Windows (a few ms per process).
bool GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const;
#if defined(OS_MACOSX)
@@ -175,6 +177,12 @@ class BASE_EXPORT ProcessMetrics {
// otherwise.
bool GetIOCounters(IoCounters* io_counters) const;
+#if defined(OS_LINUX)
+ // Returns the number of file descriptors currently open by the process, or
+ // -1 on error.
+ int GetOpenFdCount() const;
+#endif // defined(OS_LINUX)
+
private:
#if !defined(OS_MACOSX) || defined(OS_IOS)
explicit ProcessMetrics(ProcessHandle process);
@@ -191,7 +199,7 @@ class BASE_EXPORT ProcessMetrics {
#endif
#if defined(OS_MACOSX) || defined(OS_LINUX)
- int CalculateIdleWakeupsPerSecond(uint64 absolute_idle_wakeups);
+ int CalculateIdleWakeupsPerSecond(uint64_t absolute_idle_wakeups);
#endif
ProcessHandle process_;
@@ -201,12 +209,12 @@ class BASE_EXPORT ProcessMetrics {
// Used to store the previous times and CPU usage counts so we can
// compute the CPU usage between calls.
TimeTicks last_cpu_time_;
- int64 last_system_time_;
+ int64_t last_system_time_;
#if defined(OS_MACOSX) || defined(OS_LINUX)
// Same thing for idle wakeups.
TimeTicks last_idle_wakeups_time_;
- uint64 last_absolute_idle_wakeups_;
+ uint64_t last_absolute_idle_wakeups_;
#endif
#if !defined(OS_IOS)
@@ -241,23 +249,16 @@ BASE_EXPORT size_t GetMaxFds();
BASE_EXPORT void SetFdLimit(unsigned int max_descriptors);
#endif // defined(OS_POSIX)
-#if defined(OS_LINUX) || defined(OS_ANDROID)
-// Parse the data found in /proc/<pid>/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);
-
-// Get the number of threads of |process| as available in /proc/<pid>/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[];
-
-// Data from /proc/meminfo about system-wide memory consumption.
-// Values are in KB.
+#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) || \
+ defined(OS_ANDROID)
+// Data about system-wide memory consumption. Values are in KB. Available on
+// Windows, Mac, Linux, Android and Chrome OS.
+//
+// Total/free memory are available on all platforms that implement
+// GetSystemMemoryInfo(). Total/free swap memory are available on all platforms
+// except on Mac. Buffers/cached/active_anon/inactive_anon/active_file/
+// inactive_file/dirty/pswpin/pswpout/pgmajfault are available on
+// Linux/Android/Chrome OS. Shmem/slab/gem_objects/gem_size are Chrome OS only.
struct BASE_EXPORT SystemMemoryInfoKB {
SystemMemoryInfoKB();
@@ -266,30 +267,62 @@ struct BASE_EXPORT SystemMemoryInfoKB {
int total;
int free;
+
+#if !defined(OS_MACOSX)
+ int swap_total;
+ int swap_free;
+#endif
+
+#if defined(OS_ANDROID) || defined(OS_LINUX)
int buffers;
int cached;
int active_anon;
int inactive_anon;
int active_file;
int inactive_file;
- int swap_total;
- int swap_free;
int dirty;
// vmstats data.
int pswpin;
int pswpout;
int pgmajfault;
+#endif // defined(OS_ANDROID) || defined(OS_LINUX)
-#ifdef OS_CHROMEOS
+#if defined(OS_CHROMEOS)
int shmem;
int slab;
// Gem data will be -1 if not supported.
int gem_objects;
long long gem_size;
-#endif
+#endif // defined(OS_CHROMEOS)
};
+// On Linux/Android/Chrome OS, system-wide memory consumption data is parsed
+// from /proc/meminfo and /proc/vmstat. On Windows/Mac, it is obtained using
+// system API calls.
+//
+// Fills in the provided |meminfo| structure. Returns true on success.
+// Exposed for memory debugging widget.
+BASE_EXPORT bool GetSystemMemoryInfo(SystemMemoryInfoKB* meminfo);
+
+#endif // defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) ||
+ // defined(OS_ANDROID)
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+// Parse the data found in /proc/<pid>/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);
+
+// Get the number of threads of |process| as available in /proc/<pid>/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[];
+
// Parses a string containing the contents of /proc/meminfo
// returns true on success or false for a parsing error
BASE_EXPORT bool ParseProcMeminfo(const std::string& input,
@@ -300,12 +333,6 @@ BASE_EXPORT bool ParseProcMeminfo(const std::string& input,
BASE_EXPORT bool ParseProcVmstat(const std::string& input,
SystemMemoryInfoKB* meminfo);
-// Retrieves data from /proc/meminfo and /proc/vmstat
-// 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);
-
// Data from /proc/diskstats about system-wide disk I/O.
struct BASE_EXPORT SystemDiskInfo {
SystemDiskInfo();
@@ -313,17 +340,17 @@ struct BASE_EXPORT SystemDiskInfo {
// Serializes the platform specific fields to value.
scoped_ptr<Value> ToValue() const;
- uint64 reads;
- uint64 reads_merged;
- uint64 sectors_read;
- uint64 read_time;
- uint64 writes;
- uint64 writes_merged;
- uint64 sectors_written;
- uint64 write_time;
- uint64 io;
- uint64 io_time;
- uint64 weighted_io_time;
+ uint64_t reads;
+ uint64_t reads_merged;
+ uint64_t sectors_read;
+ uint64_t read_time;
+ uint64_t writes;
+ uint64_t writes_merged;
+ uint64_t sectors_written;
+ uint64_t write_time;
+ uint64_t io;
+ uint64_t io_time;
+ uint64_t weighted_io_time;
};
// Checks whether the candidate string is a valid disk name, [hsv]d[a-z]+
@@ -350,11 +377,11 @@ struct BASE_EXPORT SwapInfo {
// Serializes the platform specific fields to value.
scoped_ptr<Value> ToValue() const;
- uint64 num_reads;
- uint64 num_writes;
- uint64 compr_data_size;
- uint64 orig_data_size;
- uint64 mem_used_total;
+ uint64_t num_reads;
+ uint64_t num_writes;
+ uint64_t compr_data_size;
+ uint64_t orig_data_size;
+ uint64_t mem_used_total;
};
// In ChromeOS, reads files from /sys/block/zram0 that contain ZRAM usage data.
diff --git a/base/process/process_metrics_linux.cc b/base/process/process_metrics_linux.cc
index c564a6798b..bcebcf5729 100644
--- a/base/process/process_metrics_linux.cc
+++ b/base/process/process_metrics_linux.cc
@@ -6,11 +6,15 @@
#include <dirent.h>
#include <fcntl.h>
+#include <stddef.h>
+#include <stdint.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
+#include <utility>
+#include "base/files/dir_reader_posix.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/process/internal_linux.h"
@@ -20,6 +24,7 @@
#include "base/strings/string_util.h"
#include "base/sys_info.h"
#include "base/threading/thread_restrictions.h"
+#include "build/build_config.h"
namespace base {
@@ -35,13 +40,13 @@ void TrimKeyValuePairs(StringPairs* pairs) {
}
#if defined(OS_CHROMEOS)
-// Read a file with a single number string and return the number as a uint64.
-static uint64 ReadFileToUint64(const FilePath file) {
+// Read a file with a single number string and return the number as a uint64_t.
+static uint64_t ReadFileToUint64(const FilePath file) {
std::string file_as_string;
if (!ReadFileToString(file, &file_as_string))
return 0;
TrimWhitespaceASCII(file_as_string, TRIM_ALL, &file_as_string);
- uint64 file_as_uint64 = 0;
+ uint64_t file_as_uint64 = 0;
if (!StringToUint64(file_as_string, &file_as_uint64))
return 0;
return file_as_uint64;
@@ -67,8 +72,8 @@ size_t ReadProcStatusAndGetFieldAsSizeT(pid_t pid, const std::string& field) {
const std::string& key = pairs[i].first;
const std::string& value_str = pairs[i].second;
if (key == field) {
- std::vector<std::string> split_value_str;
- SplitString(value_str, ' ', &split_value_str);
+ std::vector<StringPiece> split_value_str = SplitStringPiece(
+ value_str, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
if (split_value_str.size() != 2 || split_value_str[1] != "kB") {
NOTREACHED();
return 0;
@@ -91,7 +96,7 @@ size_t ReadProcStatusAndGetFieldAsSizeT(pid_t pid, const std::string& field) {
// Only works for fields in the form of "field : uint_value"
bool ReadProcSchedAndGetFieldAsUint64(pid_t pid,
const std::string& field,
- uint64* result) {
+ uint64_t* result) {
std::string sched_data;
{
// Synchronously reading files in /proc does not hit the disk.
@@ -108,7 +113,7 @@ bool ReadProcSchedAndGetFieldAsUint64(pid_t pid,
const std::string& key = pairs[i].first;
const std::string& value_str = pairs[i].second;
if (key == field) {
- uint64 value;
+ uint64_t value;
if (!StringToUint64(value_str, &value))
return false;
*result = value;
@@ -213,13 +218,14 @@ double ProcessMetrics::GetCPUUsage() {
// First call, just set the last values.
last_cpu_time_ = time;
last_cpu_ = GetProcessCPU(process_);
- return 0;
+ return 0.0;
}
- int64 time_delta = (time - last_cpu_time_).InMicroseconds();
- DCHECK_NE(time_delta, 0);
- if (time_delta == 0)
- return 0;
+ TimeDelta time_delta = time - last_cpu_time_;
+ if (time_delta.is_zero()) {
+ NOTREACHED();
+ return 0.0;
+ }
int cpu = GetProcessCPU(process_);
@@ -228,8 +234,18 @@ double ProcessMetrics::GetCPUUsage() {
// are together adding to more than one CPU's worth.
TimeDelta cpu_time = internal::ClockTicksToTimeDelta(cpu);
TimeDelta last_cpu_time = internal::ClockTicksToTimeDelta(last_cpu_);
- double percentage = 100.0 * (cpu_time - last_cpu_time).InSecondsF() /
- TimeDelta::FromMicroseconds(time_delta).InSecondsF();
+
+ // If the number of threads running in the process has decreased since the
+ // last time this function was called, |last_cpu_time| will be greater than
+ // |cpu_time| which will result in a negative value in the below percentage
+ // calculation. We prevent this by clamping to 0. crbug.com/546565.
+ // This computation is known to be shaky when threads are destroyed between
+ // "last" and "now", but for our current purposes, it's all right.
+ double percentage = 0.0;
+ if (last_cpu_time < cpu_time) {
+ percentage = 100.0 * (cpu_time - last_cpu_time).InSecondsF() /
+ time_delta.InSecondsF();
+ }
last_cpu_time_ = time;
last_cpu_ = cpu;
@@ -257,7 +273,7 @@ bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const {
for (size_t i = 0; i < pairs.size(); ++i) {
const std::string& key = pairs[i].first;
const std::string& value_str = pairs[i].second;
- uint64* target_counter = NULL;
+ uint64_t* target_counter = NULL;
if (key == "syscr")
target_counter = &io_counters->ReadOperationCount;
else if (key == "syscw")
@@ -274,6 +290,26 @@ bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const {
return true;
}
+#if defined(OS_LINUX)
+int ProcessMetrics::GetOpenFdCount() const {
+ // Use /proc/<pid>/fd to count the number of entries there.
+ FilePath fd_path = internal::GetProcPidDir(process_).Append("fd");
+
+ DirReaderPosix dir_reader(fd_path.value().c_str());
+ if (!dir_reader.IsValid())
+ return -1;
+
+ int total_count = 0;
+ for (; dir_reader.Next(); ) {
+ const char* name = dir_reader.name();
+ if (strcmp(name, ".") != 0 && strcmp(name, "..") != 0)
+ ++total_count;
+ }
+
+ return total_count;
+}
+#endif // defined(OS_LINUX)
+
ProcessMetrics::ProcessMetrics(ProcessHandle process)
: process_(process),
last_system_time_(0),
@@ -316,8 +352,9 @@ bool ProcessMetrics::GetWorkingSetKBytesTotmaps(WorkingSetKBytes *ws_usage)
return false;
}
- std::vector<std::string> totmaps_fields;
- SplitStringAlongWhitespace(totmaps_data, &totmaps_fields);
+ std::vector<std::string> totmaps_fields = SplitString(
+ totmaps_data, base::kWhitespaceASCII, base::KEEP_WHITESPACE,
+ base::SPLIT_WANT_NONEMPTY);
DCHECK_EQ("Pss:", totmaps_fields[kPssIndex-1]);
DCHECK_EQ("Private_Clean:", totmaps_fields[kPrivate_CleanIndex - 1]);
@@ -368,8 +405,8 @@ bool ProcessMetrics::GetWorkingSetKBytesStatm(WorkingSetKBytes* ws_usage)
return false;
}
- std::vector<std::string> statm_vec;
- SplitString(statm, ' ', &statm_vec);
+ std::vector<StringPiece> statm_vec = SplitStringPiece(
+ statm, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
if (statm_vec.size() != 7)
return false; // Not the format we expect.
@@ -543,7 +580,7 @@ scoped_ptr<Value> SystemMemoryInfoKB::ToValue() const {
res->SetInteger("gem_size", gem_size);
#endif
- return res.Pass();
+ return std::move(res);
}
// exposed for testing
@@ -563,17 +600,15 @@ bool ParseProcMeminfo(const std::string& meminfo_data,
// MemTotal value
meminfo->total = 0;
- std::vector<std::string> meminfo_lines;
- Tokenize(meminfo_data, "\n", &meminfo_lines);
- for (std::vector<std::string>::iterator it = meminfo_lines.begin();
- it != meminfo_lines.end(); ++it) {
- std::vector<std::string> tokens;
- SplitStringAlongWhitespace(*it, &tokens);
+ for (const StringPiece& line : SplitStringPiece(
+ meminfo_data, "\n", KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY)) {
+ std::vector<StringPiece> tokens = SplitStringPiece(
+ line, kWhitespaceASCII, TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
// HugePages_* only has a number and no suffix so we can't rely on
// there being exactly 3 tokens.
if (tokens.size() <= 1) {
DLOG(WARNING) << "meminfo: tokens: " << tokens.size()
- << " malformed line: " << *it;
+ << " malformed line: " << line.as_string();
continue;
}
@@ -630,12 +665,10 @@ bool ParseProcVmstat(const std::string& vmstat_data,
// We iterate through the whole file because the position of the
// fields are dependent on the kernel version and configuration.
- std::vector<std::string> vmstat_lines;
- Tokenize(vmstat_data, "\n", &vmstat_lines);
- for (std::vector<std::string>::iterator it = vmstat_lines.begin();
- it != vmstat_lines.end(); ++it) {
- std::vector<std::string> tokens;
- SplitString(*it, ' ', &tokens);
+ for (const StringPiece& line : SplitStringPiece(
+ vmstat_data, "\n", KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY)) {
+ std::vector<StringPiece> tokens = SplitStringPiece(
+ line, " ", KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY);
if (tokens.size() != 2)
continue;
@@ -736,7 +769,7 @@ SystemDiskInfo::SystemDiskInfo() {
scoped_ptr<Value> SystemDiskInfo::ToValue() const {
scoped_ptr<DictionaryValue> res(new DictionaryValue());
- // Write out uint64 variables as doubles.
+ // Write out uint64_t variables as doubles.
// Note: this may discard some precision, but for JS there's no other option.
res->SetDouble("reads", static_cast<double>(reads));
res->SetDouble("reads_merged", static_cast<double>(reads_merged));
@@ -750,7 +783,7 @@ scoped_ptr<Value> SystemDiskInfo::ToValue() const {
res->SetDouble("io_time", static_cast<double>(io_time));
res->SetDouble("weighted_io_time", static_cast<double>(weighted_io_time));
- return res.Pass();
+ return std::move(res);
}
bool IsValidDiskName(const std::string& candidate) {
@@ -792,9 +825,9 @@ bool GetSystemDiskInfo(SystemDiskInfo* diskinfo) {
return false;
}
- std::vector<std::string> diskinfo_lines;
- size_t line_count = Tokenize(diskinfo_data, "\n", &diskinfo_lines);
- if (line_count == 0) {
+ std::vector<StringPiece> diskinfo_lines = SplitStringPiece(
+ diskinfo_data, "\n", KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY);
+ if (diskinfo_lines.size() == 0) {
DLOG(WARNING) << "No lines found";
return false;
}
@@ -811,24 +844,24 @@ bool GetSystemDiskInfo(SystemDiskInfo* diskinfo) {
diskinfo->io_time = 0;
diskinfo->weighted_io_time = 0;
- uint64 reads = 0;
- uint64 reads_merged = 0;
- uint64 sectors_read = 0;
- uint64 read_time = 0;
- uint64 writes = 0;
- uint64 writes_merged = 0;
- uint64 sectors_written = 0;
- uint64 write_time = 0;
- uint64 io = 0;
- uint64 io_time = 0;
- uint64 weighted_io_time = 0;
-
- for (size_t i = 0; i < line_count; i++) {
- std::vector<std::string> disk_fields;
- SplitStringAlongWhitespace(diskinfo_lines[i], &disk_fields);
+ uint64_t reads = 0;
+ uint64_t reads_merged = 0;
+ uint64_t sectors_read = 0;
+ uint64_t read_time = 0;
+ uint64_t writes = 0;
+ uint64_t writes_merged = 0;
+ uint64_t sectors_written = 0;
+ uint64_t write_time = 0;
+ uint64_t io = 0;
+ uint64_t io_time = 0;
+ uint64_t weighted_io_time = 0;
+
+ for (const StringPiece& line : diskinfo_lines) {
+ std::vector<StringPiece> disk_fields = SplitStringPiece(
+ line, kWhitespaceASCII, TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
// Fields may have overflowed and reset to zero.
- if (IsValidDiskName(disk_fields[kDiskDriveName])) {
+ if (IsValidDiskName(disk_fields[kDiskDriveName].as_string())) {
StringToUint64(disk_fields[kDiskReads], &reads);
StringToUint64(disk_fields[kDiskReadsMerged], &reads_merged);
StringToUint64(disk_fields[kDiskSectorsRead], &sectors_read);
@@ -862,7 +895,7 @@ bool GetSystemDiskInfo(SystemDiskInfo* diskinfo) {
scoped_ptr<Value> SwapInfo::ToValue() const {
scoped_ptr<DictionaryValue> res(new DictionaryValue());
- // Write out uint64 variables as doubles.
+ // Write out uint64_t variables as doubles.
// Note: this may discard some precision, but for JS there's no other option.
res->SetDouble("num_reads", static_cast<double>(num_reads));
res->SetDouble("num_writes", static_cast<double>(num_writes));
@@ -875,7 +908,7 @@ scoped_ptr<Value> SwapInfo::ToValue() const {
else
res->SetDouble("compression_ratio", 0);
- return res.Pass();
+ return std::move(res);
}
void GetSwapInfo(SwapInfo* swap_info) {
@@ -883,7 +916,8 @@ void GetSwapInfo(SwapInfo* swap_info) {
ThreadRestrictions::ScopedAllowIO allow_io;
FilePath zram_path("/sys/block/zram0");
- uint64 orig_data_size = ReadFileToUint64(zram_path.Append("orig_data_size"));
+ uint64_t orig_data_size =
+ ReadFileToUint64(zram_path.Append("orig_data_size"));
if (orig_data_size <= 4096) {
// A single page is compressed at startup, and has a high compression
// ratio. We ignore this as it doesn't indicate any real swapping.
@@ -906,7 +940,7 @@ void GetSwapInfo(SwapInfo* swap_info) {
#if defined(OS_LINUX)
int ProcessMetrics::GetIdleWakeupsPerSecond() {
- uint64 wake_ups;
+ uint64_t wake_ups;
const char kWakeupStat[] = "se.statistics.nr_wakeups";
return ReadProcSchedAndGetFieldAsUint64(process_, kWakeupStat, &wake_ups) ?
CalculateIdleWakeupsPerSecond(wake_ups) : 0;
diff --git a/base/process/process_metrics_mac.cc b/base/process/process_metrics_mac.cc
index 456b118f71..d947ce7377 100644
--- a/base/process/process_metrics_mac.cc
+++ b/base/process/process_metrics_mac.cc
@@ -7,6 +7,8 @@
#include <mach/mach.h>
#include <mach/mach_vm.h>
#include <mach/shared_region.h>
+#include <stddef.h>
+#include <stdint.h>
#include <sys/sysctl.h>
#include "base/containers/hash_tables.h"
@@ -77,6 +79,11 @@ bool IsAddressInSharedRegion(mach_vm_address_t addr, cpu_type_t type) {
} // namespace
+SystemMemoryInfoKB::SystemMemoryInfoKB() {
+ total = 0;
+ free = 0;
+}
+
// 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
@@ -86,7 +93,7 @@ bool IsAddressInSharedRegion(mach_vm_address_t addr, cpu_type_t type) {
// static
ProcessMetrics* ProcessMetrics::CreateProcessMetrics(
ProcessHandle process,
- ProcessMetrics::PortProvider* port_provider) {
+ PortProvider* port_provider) {
return new ProcessMetrics(process, port_provider);
}
@@ -279,7 +286,7 @@ double ProcessMetrics::GetCPUUsage() {
timeradd(&system_timeval, &task_timeval, &task_timeval);
TimeTicks time = TimeTicks::Now();
- int64 task_time = TimeValToMicroseconds(task_timeval);
+ int64_t task_time = TimeValToMicroseconds(task_timeval);
if (last_system_time_ == 0) {
// First call, just set the last values.
@@ -288,8 +295,8 @@ double ProcessMetrics::GetCPUUsage() {
return 0;
}
- int64 system_time_delta = task_time - last_system_time_;
- int64 time_delta = (time - last_cpu_time_).InMicroseconds();
+ int64_t system_time_delta = task_time - last_system_time_;
+ int64_t time_delta = (time - last_cpu_time_).InMicroseconds();
DCHECK_NE(0U, time_delta);
if (time_delta == 0)
return 0;
@@ -325,7 +332,7 @@ bool ProcessMetrics::GetIOCounters(IoCounters* /* io_counters */) const {
}
ProcessMetrics::ProcessMetrics(ProcessHandle process,
- ProcessMetrics::PortProvider* port_provider)
+ PortProvider* port_provider)
: process_(process),
last_system_time_(0),
last_absolute_idle_wakeups_(0),
@@ -347,7 +354,7 @@ size_t GetSystemCommitCharge() {
base::mac::ScopedMachSendRight 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,
+ kern_return_t kr = host_statistics(host.get(), HOST_VM_INFO,
reinterpret_cast<host_info_t>(&data),
&count);
if (kr != KERN_SUCCESS) {
@@ -358,4 +365,32 @@ size_t GetSystemCommitCharge() {
return (data.active_count * PAGE_SIZE) / 1024;
}
+// On Mac, We only get total memory and free memory from the system.
+bool GetSystemMemoryInfo(SystemMemoryInfoKB* meminfo) {
+ struct host_basic_info hostinfo;
+ mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT;
+ base::mac::ScopedMachSendRight host(mach_host_self());
+ int result = host_info(host.get(), HOST_BASIC_INFO,
+ reinterpret_cast<host_info_t>(&hostinfo), &count);
+ if (result != KERN_SUCCESS)
+ return false;
+
+ DCHECK_EQ(HOST_BASIC_INFO_COUNT, count);
+ meminfo->total = static_cast<int>(hostinfo.max_mem / 1024);
+
+ vm_statistics_data_t vm_info;
+ count = HOST_VM_INFO_COUNT;
+
+ if (host_statistics(host.get(), HOST_VM_INFO,
+ reinterpret_cast<host_info_t>(&vm_info),
+ &count) != KERN_SUCCESS) {
+ return false;
+ }
+
+ meminfo->free = static_cast<int>(
+ (vm_info.free_count - vm_info.speculative_count) * PAGE_SIZE / 1024);
+
+ return true;
+}
+
} // namespace base
diff --git a/base/process/process_metrics_posix.cc b/base/process/process_metrics_posix.cc
index 42b3f2d665..fad581eece 100644
--- a/base/process/process_metrics_posix.cc
+++ b/base/process/process_metrics_posix.cc
@@ -4,15 +4,20 @@
#include "base/process/process_metrics.h"
+#include <limits.h>
+#include <stddef.h>
+#include <stdint.h>
#include <sys/resource.h>
#include <sys/time.h>
+#include <unistd.h>
#include "base/logging.h"
+#include "build/build_config.h"
namespace base {
-int64 TimeValToMicroseconds(const struct timeval& tv) {
- int64 ret = tv.tv_sec; // Avoid (int * int) integer overflow.
+int64_t TimeValToMicroseconds(const struct timeval& tv) {
+ int64_t ret = tv.tv_sec; // Avoid (int * int) integer overflow.
ret *= Time::kMicrosecondsPerSecond;
ret += tv.tv_usec;
return ret;
diff --git a/base/process/process_metrics_unittest.cc b/base/process/process_metrics_unittest.cc
index 76767b09a9..96ba6ceabd 100644
--- a/base/process/process_metrics_unittest.cc
+++ b/base/process/process_metrics_unittest.cc
@@ -4,16 +4,42 @@
#include "base/process/process_metrics.h"
+#include <stddef.h>
+#include <stdint.h>
+
#include <sstream>
#include <string>
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/files/file.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/macros.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/test/multiprocess_test.h"
#include "base/threading/thread.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
-
+#include "testing/multiprocess_func_list.h"
namespace base {
namespace debug {
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+namespace {
+
+void BusyWork(std::vector<std::string>* vec) {
+ int64_t test_value = 0;
+ for (int i = 0; i < 100000; ++i) {
+ ++test_value;
+ vec->push_back(Int64ToString(test_value));
+ }
+}
+
+} // namespace
+#endif // defined(OS_LINUX) || defined(OS_CHROMEOS)
+
// Tests for SystemMetrics.
// Exists as a class so it can be a friend of SystemMetrics.
class SystemMetricsTest : public testing::Test {
@@ -270,29 +296,79 @@ TEST_F(SystemMetricsTest, ParseVmstat) {
}
#endif // defined(OS_LINUX) || defined(OS_ANDROID)
-#if defined(OS_LINUX) || defined(OS_ANDROID)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+
+// Test that ProcessMetrics::GetCPUUsage() doesn't return negative values when
+// the number of threads running on the process decreases between two successive
+// calls to it.
+TEST_F(SystemMetricsTest, TestNoNegativeCpuUsage) {
+ ProcessHandle handle = GetCurrentProcessHandle();
+ scoped_ptr<ProcessMetrics> metrics(
+ ProcessMetrics::CreateProcessMetrics(handle));
+
+ EXPECT_GE(metrics->GetCPUUsage(), 0.0);
+ Thread thread1("thread1");
+ Thread thread2("thread2");
+ Thread thread3("thread3");
+
+ thread1.StartAndWaitForTesting();
+ thread2.StartAndWaitForTesting();
+ thread3.StartAndWaitForTesting();
+
+ ASSERT_TRUE(thread1.IsRunning());
+ ASSERT_TRUE(thread2.IsRunning());
+ ASSERT_TRUE(thread3.IsRunning());
+
+ std::vector<std::string> vec1;
+ std::vector<std::string> vec2;
+ std::vector<std::string> vec3;
+
+ thread1.task_runner()->PostTask(FROM_HERE, Bind(&BusyWork, &vec1));
+ thread2.task_runner()->PostTask(FROM_HERE, Bind(&BusyWork, &vec2));
+ thread3.task_runner()->PostTask(FROM_HERE, Bind(&BusyWork, &vec3));
+
+ EXPECT_GE(metrics->GetCPUUsage(), 0.0);
+
+ thread1.Stop();
+ EXPECT_GE(metrics->GetCPUUsage(), 0.0);
+
+ thread2.Stop();
+ EXPECT_GE(metrics->GetCPUUsage(), 0.0);
+
+ thread3.Stop();
+ EXPECT_GE(metrics->GetCPUUsage(), 0.0);
+}
+
+#endif // defined(OS_LINUX) || defined(OS_CHROMEOS)
+
+#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) || \
+ defined(OS_LINUX) || defined(OS_ANDROID)
TEST(SystemMetrics2Test, GetSystemMemoryInfo) {
- base::SystemMemoryInfoKB info;
- EXPECT_TRUE(base::GetSystemMemoryInfo(&info));
+ SystemMemoryInfoKB info;
+ EXPECT_TRUE(GetSystemMemoryInfo(&info));
// Ensure each field received a value.
EXPECT_GT(info.total, 0);
EXPECT_GT(info.free, 0);
+#if defined(OS_LINUX) || defined(OS_ANDROID)
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);
+#endif // defined(OS_LINUX) || defined(OS_ANDROID)
// All the values should be less than the total amount of memory.
EXPECT_LT(info.free, info.total);
+#if defined(OS_LINUX) || defined(OS_ANDROID)
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);
+#endif // defined(OS_LINUX) || defined(OS_ANDROID)
#if defined(OS_CHROMEOS)
// Chrome OS exposes shmem.
@@ -302,7 +378,8 @@ TEST(SystemMetrics2Test, GetSystemMemoryInfo) {
// and gem_size cannot be tested here.
#endif
}
-#endif // defined(OS_LINUX) || defined(OS_ANDROID)
+#endif // defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) ||
+ // defined(OS_LINUX) || defined(OS_ANDROID)
#if defined(OS_LINUX) || defined(OS_ANDROID)
TEST(ProcessMetricsTest, ParseProcStatCPU) {
@@ -313,7 +390,7 @@ TEST(ProcessMetricsTest, ParseProcStatCPU) {
"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));
+ EXPECT_EQ(12 + 16, ParseProcStatCPU(kTopStat));
// cat /proc/self/stat on a random other machine I have.
const char kSelfStat[] = "5364 (cat) R 5354 5364 5354 34819 5364 "
@@ -322,7 +399,7 @@ TEST(ProcessMetricsTest, ParseProcStatCPU) {
"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));
+ EXPECT_EQ(0, ParseProcStatCPU(kSelfStat));
// Some weird long-running process with a weird name that I created for the
// purposes of this test.
@@ -333,29 +410,96 @@ TEST(ProcessMetricsTest, ParseProcStatCPU) {
"140735857761568 140735857761160 4195644 0 0 0 0 0 0 0 17 14 0 0 0 0 0 "
"6295056 6295616 16519168 140735857770710 140735857770737 "
"140735857770737 140735857774557 0";
- EXPECT_EQ(5186 + 11, base::ParseProcStatCPU(kWeirdNameStat));
+ EXPECT_EQ(5186 + 11, ParseProcStatCPU(kWeirdNameStat));
}
-#endif // defined(OS_LINUX) || defined(OS_ANDROID)
+#endif // defined(OS_LINUX) || defined(OS_ANDROID)
// Disable on Android because base_unittests runs inside a Dalvik VM that
// starts and stop threads (crbug.com/175563).
#if defined(OS_LINUX)
// http://crbug.com/396455
TEST(ProcessMetricsTest, DISABLED_GetNumberOfThreads) {
- const base::ProcessHandle current = base::GetCurrentProcessHandle();
- const int initial_threads = base::GetNumberOfThreads(current);
+ const ProcessHandle current = GetCurrentProcessHandle();
+ const int initial_threads = GetNumberOfThreads(current);
ASSERT_GT(initial_threads, 0);
const int kNumAdditionalThreads = 10;
{
- scoped_ptr<base::Thread> my_threads[kNumAdditionalThreads];
+ scoped_ptr<Thread> my_threads[kNumAdditionalThreads];
for (int i = 0; i < kNumAdditionalThreads; ++i) {
- my_threads[i].reset(new base::Thread("GetNumberOfThreadsTest"));
+ my_threads[i].reset(new Thread("GetNumberOfThreadsTest"));
my_threads[i]->Start();
- ASSERT_EQ(base::GetNumberOfThreads(current), initial_threads + 1 + i);
+ ASSERT_EQ(GetNumberOfThreads(current), initial_threads + 1 + i);
}
}
// The Thread destructor will stop them.
- ASSERT_EQ(initial_threads, base::GetNumberOfThreads(current));
+ ASSERT_EQ(initial_threads, GetNumberOfThreads(current));
+}
+#endif // defined(OS_LINUX)
+
+#if defined(OS_LINUX)
+namespace {
+
+// Keep these in sync so the GetOpenFdCount test can refer to correct test main.
+#define ChildMain ChildFdCount
+#define ChildMainString "ChildFdCount"
+
+// Command line flag name and file name used for synchronization.
+const char kTempDirFlag[] = "temp-dir";
+const char kSignalClosed[] = "closed";
+
+bool SignalEvent(const FilePath& signal_dir, const char* signal_file) {
+ File file(signal_dir.AppendASCII(signal_file),
+ File::FLAG_CREATE | File::FLAG_WRITE);
+ return file.IsValid();
+}
+
+// Check whether an event was signaled.
+bool CheckEvent(const FilePath& signal_dir, const char* signal_file) {
+ File file(signal_dir.AppendASCII(signal_file),
+ File::FLAG_OPEN | File::FLAG_READ);
+ return file.IsValid();
+}
+
+// Busy-wait for an event to be signaled.
+void WaitForEvent(const FilePath& signal_dir, const char* signal_file) {
+ while (!CheckEvent(signal_dir, signal_file))
+ PlatformThread::Sleep(TimeDelta::FromMilliseconds(10));
+}
+
+// Subprocess to test the number of open file descriptors.
+MULTIPROCESS_TEST_MAIN(ChildMain) {
+ CommandLine* command_line = CommandLine::ForCurrentProcess();
+ const FilePath temp_path = command_line->GetSwitchValuePath(kTempDirFlag);
+ CHECK(DirectoryExists(temp_path));
+
+ // Try to close all the file descriptors, so the open count goes to 0.
+ for (size_t i = 0; i < 1000; ++i)
+ close(i);
+ CHECK(SignalEvent(temp_path, kSignalClosed));
+
+ // Wait to be terminated.
+ while (true)
+ PlatformThread::Sleep(TimeDelta::FromSeconds(1));
+ return 0;
+}
+
+} // namespace
+
+TEST(ProcessMetricsTest, GetOpenFdCount) {
+ ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ const FilePath temp_path = temp_dir.path();
+ CommandLine child_command_line(GetMultiProcessTestChildBaseCommandLine());
+ child_command_line.AppendSwitchPath(kTempDirFlag, temp_path);
+ Process child = SpawnMultiProcessTestChild(
+ ChildMainString, child_command_line, LaunchOptions());
+ ASSERT_TRUE(child.IsValid());
+ WaitForEvent(temp_path, kSignalClosed);
+
+ scoped_ptr<ProcessMetrics> metrics(
+ ProcessMetrics::CreateProcessMetrics(child.Handle()));
+ EXPECT_EQ(0, metrics->GetOpenFdCount());
+ ASSERT_TRUE(child.Terminate(0, true));
}
#endif // defined(OS_LINUX)
diff --git a/base/process/process_posix.cc b/base/process/process_posix.cc
index 775b78e4a0..c6c0732fbe 100644
--- a/base/process/process_posix.cc
+++ b/base/process/process_posix.cc
@@ -4,6 +4,8 @@
#include "base/process/process.h"
+#include <errno.h>
+#include <stdint.h>
#include <sys/resource.h>
#include <sys/wait.h>
@@ -11,6 +13,7 @@
#include "base/logging.h"
#include "base/posix/eintr_wrapper.h"
#include "base/process/kill.h"
+#include "build/build_config.h"
#if defined(OS_MACOSX)
#include <sys/event.h>
@@ -52,9 +55,9 @@ bool WaitpidWithTimeout(base::ProcessHandle handle,
}
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;
+ static const int64_t kMaxSleepInMicroseconds = 1 << 18; // ~256 milliseconds.
+ int64_t max_sleep_time_usecs = 1 << 10; // ~1 milliseconds.
+ int64_t double_sleep_time = 0;
// If the process hasn't exited yet, then sleep and try again.
base::TimeTicks wakeup_time = base::TimeTicks::Now() + wait;
@@ -63,7 +66,7 @@ bool WaitpidWithTimeout(base::ProcessHandle handle,
if (now > wakeup_time)
break;
// Guaranteed to be non-negative!
- int64 sleep_time_usecs = (wakeup_time - now).InMicroseconds();
+ int64_t 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;
@@ -217,16 +220,14 @@ Process::Process(ProcessHandle handle) : process_(handle) {
Process::~Process() {
}
-Process::Process(RValue other)
- : process_(other.object->process_) {
- other.object->Close();
+Process::Process(Process&& other) : process_(other.process_) {
+ other.Close();
}
-Process& Process::operator=(RValue other) {
- if (this != other.object) {
- process_ = other.object->process_;
- other.object->Close();
- }
+Process& Process::operator=(Process&& other) {
+ DCHECK_NE(this, &other);
+ process_ = other.process_;
+ other.Close();
return *this;
}
@@ -256,12 +257,12 @@ Process Process::DeprecatedGetProcessFromHandle(ProcessHandle handle) {
return Process(handle);
}
-#if !defined(OS_LINUX) && !defined(OS_MACOSX)
+#if !defined(OS_LINUX)
// static
bool Process::CanBackgroundProcesses() {
return false;
}
-#endif // !defined(OS_LINUX) && !defined(OS_MACOSX)
+#endif // !defined(OS_LINUX)
bool Process::IsValid() const {
return process_ != kNullProcessHandle;
@@ -296,9 +297,10 @@ void Process::Close() {
#if !defined(OS_NACL_NONSFI)
bool Process::Terminate(int /* exit_code */, bool wait) const {
- // result_code isn't supportable.
+ // exit_code isn't supportable.
DCHECK(IsValid());
- DCHECK_GT(process_, 1);
+ CHECK_GT(process_, 0);
+
bool result = kill(process_, SIGTERM) == 0;
if (result && wait) {
int tries = 60;
@@ -350,7 +352,7 @@ bool Process::WaitForExitWithTimeout(TimeDelta timeout, int* exit_code) {
return WaitForExitWithTimeoutImpl(Handle(), exit_code, timeout);
}
-#if !defined(OS_LINUX) && !defined(OS_MACOSX)
+#if !defined(OS_LINUX)
bool Process::IsProcessBackgrounded() const {
// See SetProcessBackgrounded().
DCHECK(IsValid());
@@ -358,13 +360,13 @@ bool Process::IsProcessBackgrounded() const {
}
bool Process::SetProcessBackgrounded(bool value) {
- // Not implemented for POSIX systems other than Mac and Linux. With POSIX, if
- // we were to lower the process priority we wouldn't be able to raise it back
- // to its initial priority.
+ // Not implemented for POSIX systems other than Linux. With POSIX, if we were
+ // to lower the process priority we wouldn't be able to raise it back to its
+ // initial priority.
NOTIMPLEMENTED();
return false;
}
-#endif // !defined(OS_LINUX) && !defined(OS_MACOSX)
+#endif // !defined(OS_LINUX)
int Process::GetPriority() const {
DCHECK(IsValid());
diff --git a/base/profiler/alternate_timer.cc b/base/profiler/alternate_timer.cc
index 02763cd9ef..b2d2c70320 100644
--- a/base/profiler/alternate_timer.cc
+++ b/base/profiler/alternate_timer.cc
@@ -4,11 +4,9 @@
#include "base/profiler/alternate_timer.h"
-#include "base/basictypes.h"
-
namespace {
-tracked_objects::NowFunction* g_time_function = NULL;
+tracked_objects::NowFunction* g_time_function = nullptr;
tracked_objects::TimeSourceType g_time_source_type =
tracked_objects::TIME_SOURCE_TYPE_WALL_TIME;
diff --git a/base/profiler/scoped_profile.h b/base/profiler/scoped_profile.h
index 2c4105d24a..657150a0f1 100644
--- a/base/profiler/scoped_profile.h
+++ b/base/profiler/scoped_profile.h
@@ -14,6 +14,7 @@
#include "base/base_export.h"
#include "base/location.h"
+#include "base/macros.h"
#include "base/profiler/tracked_time.h"
#include "base/tracked_objects.h"
diff --git a/base/profiler/scoped_tracker.h b/base/profiler/scoped_tracker.h
index 23e2f07b61..a61de9115c 100644
--- a/base/profiler/scoped_tracker.h
+++ b/base/profiler/scoped_tracker.h
@@ -13,6 +13,7 @@
#include "base/bind.h"
#include "base/callback_forward.h"
#include "base/location.h"
+#include "base/macros.h"
#include "base/profiler/scoped_profile.h"
namespace tracked_objects {
diff --git a/base/profiler/tracked_time.cc b/base/profiler/tracked_time.cc
index e5da68f522..7e0040c03c 100644
--- a/base/profiler/tracked_time.cc
+++ b/base/profiler/tracked_time.cc
@@ -13,7 +13,7 @@
namespace tracked_objects {
Duration::Duration() : ms_(0) {}
-Duration::Duration(int32 duration) : ms_(duration) {}
+Duration::Duration(int32_t duration) : ms_(duration) {}
Duration& Duration::operator+=(const Duration& other) {
ms_ += other.ms_;
@@ -39,15 +39,16 @@ bool Duration::operator>(const Duration& other) const {
// static
Duration Duration::FromMilliseconds(int ms) { return Duration(ms); }
-int32 Duration::InMilliseconds() const { return ms_; }
+int32_t Duration::InMilliseconds() const {
+ return ms_;
+}
//------------------------------------------------------------------------------
TrackedTime::TrackedTime() : ms_(0) {}
-TrackedTime::TrackedTime(int32 ms) : ms_(ms) {}
+TrackedTime::TrackedTime(int32_t ms) : ms_(ms) {}
TrackedTime::TrackedTime(const base::TimeTicks& time)
- : ms_(static_cast<int32>((time - base::TimeTicks()).InMilliseconds())) {
-}
+ : ms_(static_cast<int32_t>((time - base::TimeTicks()).InMilliseconds())) {}
// static
TrackedTime TrackedTime::Now() {
diff --git a/base/profiler/tracked_time.h b/base/profiler/tracked_time.h
index 23632749a0..b32f41b39c 100644
--- a/base/profiler/tracked_time.h
+++ b/base/profiler/tracked_time.h
@@ -5,9 +5,9 @@
#ifndef BASE_PROFILER_TRACKED_TIME_H_
#define BASE_PROFILER_TRACKED_TIME_H_
+#include <stdint.h>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/time/time.h"
namespace tracked_objects {
@@ -36,14 +36,14 @@ class BASE_EXPORT Duration { // Similar to base::TimeDelta.
static Duration FromMilliseconds(int ms);
- int32 InMilliseconds() const;
+ int32_t InMilliseconds() const;
private:
friend class TrackedTime;
- explicit Duration(int32 duration);
+ explicit Duration(int32_t duration);
// Internal time is stored directly in milliseconds.
- int32 ms_;
+ int32_t ms_;
};
class BASE_EXPORT TrackedTime { // Similar to base::TimeTicks.
@@ -56,14 +56,14 @@ class BASE_EXPORT TrackedTime { // Similar to base::TimeTicks.
TrackedTime operator+(const Duration& other) const;
bool is_null() const;
- static TrackedTime FromMilliseconds(int32 ms) { return TrackedTime(ms); }
+ static TrackedTime FromMilliseconds(int32_t ms) { return TrackedTime(ms); }
private:
friend class Duration;
- explicit TrackedTime(int32 ms);
+ explicit TrackedTime(int32_t ms);
// Internal duration is stored directly in milliseconds.
- uint32 ms_;
+ uint32_t ms_;
};
} // namespace tracked_objects
diff --git a/base/profiler/tracked_time_unittest.cc b/base/profiler/tracked_time_unittest.cc
index c105688b31..f6d35baab3 100644
--- a/base/profiler/tracked_time_unittest.cc
+++ b/base/profiler/tracked_time_unittest.cc
@@ -4,6 +4,8 @@
// Test of classes in tracked_time.cc
+#include <stdint.h>
+
#include "base/profiler/tracked_time.h"
#include "base/time/time.h"
#include "base/tracked_objects.h"
@@ -14,8 +16,8 @@ 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;
+ int32_t kSomeMilliseconds = 243; // Some example times.
+ int64_t kReallyBigMilliseconds = (1LL << 35) + kSomeMilliseconds;
TrackedTime some = TrackedTime() +
Duration::FromMilliseconds(kSomeMilliseconds);
diff --git a/base/rand_util.cc b/base/rand_util.cc
index 931eb4e943..fab6c6613c 100644
--- a/base/rand_util.cc
+++ b/base/rand_util.cc
@@ -4,13 +4,13 @@
#include "base/rand_util.h"
+#include <limits.h>
#include <math.h>
#include <stdint.h>
#include <algorithm>
#include <limits>
-#include "base/basictypes.h"
#include "base/logging.h"
#include "base/strings/string_util.h"
@@ -19,8 +19,11 @@ namespace base {
int RandInt(int min, int max) {
DCHECK_LE(min, max);
- uint64 range = static_cast<uint64>(max) - min + 1;
- int result = min + static_cast<int>(base::RandGenerator(range));
+ uint64_t range = static_cast<uint64_t>(max) - min + 1;
+ // |range| is at most UINT_MAX + 1, so the result of RandGenerator(range)
+ // is at most UINT_MAX. Hence it's safe to cast it from uint64_t to int64_t.
+ int result =
+ static_cast<int>(min + static_cast<int64_t>(base::RandGenerator(range)));
DCHECK_GE(result, min);
DCHECK_LE(result, max);
return result;
@@ -30,31 +33,32 @@ double RandDouble() {
return BitsToOpenEndedUnitInterval(base::RandUint64());
}
-double BitsToOpenEndedUnitInterval(uint64 bits) {
+double BitsToOpenEndedUnitInterval(uint64_t 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<double>::radix == 2, otherwise_use_scalbn);
+ static_assert(std::numeric_limits<double>::radix == 2,
+ "otherwise use scalbn");
static const int kBits = std::numeric_limits<double>::digits;
- uint64 random_bits = bits & ((UINT64_C(1) << kBits) - 1);
+ uint64_t random_bits = bits & ((UINT64_C(1) << kBits) - 1);
double result = ldexp(static_cast<double>(random_bits), -1 * kBits);
DCHECK_GE(result, 0.0);
DCHECK_LT(result, 1.0);
return result;
}
-uint64 RandGenerator(uint64 range) {
+uint64_t RandGenerator(uint64_t 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<uint64>::max() / range) * range - 1;
+ uint64_t max_acceptable_value =
+ (std::numeric_limits<uint64_t>::max() / range) * range - 1;
- uint64 value;
+ uint64_t value;
do {
value = base::RandUint64();
} while (value > max_acceptable_value);
diff --git a/base/rand_util.h b/base/rand_util.h
index 6130c129b7..881dbd50bb 100644
--- a/base/rand_util.h
+++ b/base/rand_util.h
@@ -5,15 +5,18 @@
#ifndef BASE_RAND_UTIL_H_
#define BASE_RAND_UTIL_H_
+#include <stddef.h>
+#include <stdint.h>
+
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "build/build_config.h"
namespace base {
-// Returns a random number in range [0, kuint64max]. Thread-safe.
-BASE_EXPORT uint64 RandUint64();
+// Returns a random number in range [0, UINT64_MAX]. Thread-safe.
+BASE_EXPORT uint64_t RandUint64();
// Returns a random number between min and max (inclusive). Thread-safe.
BASE_EXPORT int RandInt(int min, int max);
@@ -23,14 +26,14 @@ BASE_EXPORT int RandInt(int min, int max);
// Note that this can be used as an adapter for std::random_shuffle():
// Given a pre-populated |std::vector<int> myvector|, shuffle it as
// std::random_shuffle(myvector.begin(), myvector.end(), base::RandGenerator);
-BASE_EXPORT uint64 RandGenerator(uint64 range);
+BASE_EXPORT uint64_t RandGenerator(uint64_t 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);
+BASE_EXPORT double BitsToOpenEndedUnitInterval(uint64_t bits);
// Fills |output_length| bytes of |output| with random data.
//
diff --git a/base/rand_util_posix.cc b/base/rand_util_posix.cc
index fe73b960f9..6a6e05ada8 100644
--- a/base/rand_util_posix.cc
+++ b/base/rand_util_posix.cc
@@ -6,6 +6,8 @@
#include <errno.h>
#include <fcntl.h>
+#include <stddef.h>
+#include <stdint.h>
#include <unistd.h>
#include "base/files/file_util.h"
@@ -39,8 +41,8 @@ base::LazyInstance<URandomFd>::Leaky g_urandom_fd = LAZY_INSTANCE_INITIALIZER;
namespace base {
// NOTE: This function must be cryptographically secure. http://crbug.com/140076
-uint64 RandUint64() {
- uint64 number;
+uint64_t RandUint64() {
+ uint64_t number;
RandBytes(&number, sizeof(number));
return number;
}
diff --git a/base/rand_util_unittest.cc b/base/rand_util_unittest.cc
index 90690ec2db..ea803ee73f 100644
--- a/base/rand_util_unittest.cc
+++ b/base/rand_util_unittest.cc
@@ -4,6 +4,9 @@
#include "base/rand_util.h"
+#include <stddef.h>
+#include <stdint.h>
+
#include <algorithm>
#include <limits>
@@ -19,10 +22,16 @@ const int kIntMax = std::numeric_limits<int>::max();
} // namespace
-TEST(RandUtilTest, SameMinAndMax) {
+TEST(RandUtilTest, RandInt) {
EXPECT_EQ(base::RandInt(0, 0), 0);
EXPECT_EQ(base::RandInt(kIntMin, kIntMin), kIntMin);
EXPECT_EQ(base::RandInt(kIntMax, kIntMax), kIntMax);
+
+ // Check that the DCHECKS in RandInt() don't fire due to internal overflow.
+ // There was a 50% chance of that happening, so calling it 40 times means
+ // the chances of this passing by accident are tiny (9e-13).
+ for (int i = 0; i < 40; ++i)
+ base::RandInt(kIntMin, kIntMax);
}
TEST(RandUtilTest, RandDouble) {
@@ -61,7 +70,7 @@ TEST(RandUtilTest, RandBytesAsString) {
TEST(RandUtilTest, RandGeneratorForRandomShuffle) {
EXPECT_EQ(base::RandGenerator(1), 0U);
EXPECT_LE(std::numeric_limits<ptrdiff_t>::max(),
- std::numeric_limits<int64>::max());
+ std::numeric_limits<int64_t>::max());
}
TEST(RandUtilTest, RandGeneratorIsUniform) {
@@ -77,16 +86,17 @@ TEST(RandUtilTest, RandGeneratorIsUniform) {
// 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<uint64>::max() / 4ULL) * 3ULL;
- const uint64 kExpectedAverage = kTopOfRange / 2ULL;
- const uint64 kAllowedVariance = kExpectedAverage / 50ULL; // +/- 2%
+ const uint64_t kTopOfRange =
+ (std::numeric_limits<uint64_t>::max() / 4ULL) * 3ULL;
+ const uint64_t kExpectedAverage = kTopOfRange / 2ULL;
+ const uint64_t 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);
+ uint64_t 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
@@ -107,13 +117,13 @@ TEST(RandUtilTest, RandGeneratorIsUniform) {
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;
+ uint64_t kAllZeros = 0ULL;
+ uint64_t kAllOnes = ~kAllZeros;
+ uint64_t found_ones = kAllZeros;
+ uint64_t found_zeros = kAllOnes;
for (size_t i = 0; i < 1000; ++i) {
- uint64 value = base::RandUint64();
+ uint64_t value = base::RandUint64();
found_ones |= value;
found_zeros &= value;
@@ -133,7 +143,7 @@ TEST(RandUtilTest, DISABLED_RandBytesPerf) {
const int kTestIterations = 10;
const size_t kTestBufferSize = 1 * 1024 * 1024;
- scoped_ptr<uint8[]> buffer(new uint8[kTestBufferSize]);
+ scoped_ptr<uint8_t[]> buffer(new uint8_t[kTestBufferSize]);
const base::TimeTicks now = base::TimeTicks::Now();
for (int i = 0; i < kTestIterations; ++i)
base::RandBytes(buffer.get(), kTestBufferSize);
diff --git a/base/run_loop.cc b/base/run_loop.cc
index 2aa4def957..b8558db487 100644
--- a/base/run_loop.cc
+++ b/base/run_loop.cc
@@ -6,6 +6,7 @@
#include "base/bind.h"
#include "base/tracked_objects.h"
+#include "build/build_config.h"
#if defined(OS_WIN)
#include "base/message_loop/message_pump_dispatcher.h"
diff --git a/base/run_loop.h b/base/run_loop.h
index 002410892f..e23d073077 100644
--- a/base/run_loop.h
+++ b/base/run_loop.h
@@ -7,8 +7,10 @@
#include "base/base_export.h"
#include "base/callback.h"
+#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
+#include "build/build_config.h"
namespace base {
#if defined(OS_ANDROID)
@@ -38,8 +40,8 @@ class BASE_EXPORT RunLoop {
// 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.
+ // stop the MessageLoop asynchronously. MessageLoop::QuitWhenIdle 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
diff --git a/base/scoped_clear_errno.h b/base/scoped_clear_errno.h
index 7b972fc85a..585f6f768f 100644
--- a/base/scoped_clear_errno.h
+++ b/base/scoped_clear_errno.h
@@ -7,7 +7,7 @@
#include <errno.h>
-#include "base/basictypes.h"
+#include "base/macros.h"
namespace base {
diff --git a/base/scoped_generic.h b/base/scoped_generic.h
index f6807e2b58..d41f19512c 100644
--- a/base/scoped_generic.h
+++ b/base/scoped_generic.h
@@ -10,6 +10,7 @@
#include <algorithm>
#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "base/move.h"
namespace base {
@@ -53,7 +54,7 @@ namespace base {
// typedef ScopedGeneric<int, FooScopedTraits> ScopedFoo;
template<typename T, typename Traits>
class ScopedGeneric {
- MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(ScopedGeneric)
+ DISALLOW_COPY_AND_ASSIGN_WITH_MOVE_FOR_BIND(ScopedGeneric)
private:
// This must be first since it's used inline below.
diff --git a/base/scoped_generic_unittest.cc b/base/scoped_generic_unittest.cc
index b28e154372..5a6abfb3c4 100644
--- a/base/scoped_generic_unittest.cc
+++ b/base/scoped_generic_unittest.cc
@@ -2,9 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/scoped_generic.h"
+
+#include <utility>
#include <vector>
-#include "base/scoped_generic.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
@@ -85,10 +87,10 @@ TEST(ScopedGenericTest, ScopedGeneric) {
EXPECT_EQ(kSecond, values_freed[1]);
values_freed.clear();
- // Pass constructor.
+ // Move constructor.
{
ScopedInt a(kFirst, traits);
- ScopedInt b(a.Pass());
+ ScopedInt b(std::move(a));
EXPECT_TRUE(values_freed.empty()); // Nothing should be freed.
ASSERT_EQ(IntTraits::InvalidValue(), a.get());
ASSERT_EQ(kFirst, b.get());
@@ -98,11 +100,11 @@ TEST(ScopedGenericTest, ScopedGeneric) {
ASSERT_EQ(kFirst, values_freed[0]);
values_freed.clear();
- // Pass assign.
+ // Move assign.
{
ScopedInt a(kFirst, traits);
ScopedInt b(kSecond, traits);
- b = a.Pass();
+ b = std::move(a);
ASSERT_EQ(1u, values_freed.size());
EXPECT_EQ(kSecond, values_freed[0]);
ASSERT_EQ(IntTraits::InvalidValue(), a.get());
diff --git a/base/scoped_observer.h b/base/scoped_observer.h
index 422701bc21..13d7ca8bb1 100644
--- a/base/scoped_observer.h
+++ b/base/scoped_observer.h
@@ -5,11 +5,14 @@
#ifndef BASE_SCOPED_OBSERVER_H_
#define BASE_SCOPED_OBSERVER_H_
+#include <stddef.h>
+
#include <algorithm>
#include <vector>
-#include "base/basictypes.h"
#include "base/logging.h"
+#include "base/macros.h"
+#include "base/stl_util.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
@@ -44,8 +47,7 @@ class ScopedObserver {
}
bool IsObserving(Source* source) const {
- return std::find(sources_.begin(), sources_.end(), source) !=
- sources_.end();
+ return ContainsValue(sources_, source);
}
bool IsObservingSources() const { return !sources_.empty(); }
diff --git a/base/security_unittest.cc b/base/security_unittest.cc
index 1cff1b44ed..eebe6e0f99 100644
--- a/base/security_unittest.cc
+++ b/base/security_unittest.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include <fcntl.h>
+#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -23,47 +24,11 @@
#include <unistd.h>
#endif
-#if defined(OS_WIN)
-#include <new.h>
-#endif
-
using std::nothrow;
using std::numeric_limits;
namespace {
-#if defined(OS_WIN)
-// This is a permitted size but exhausts memory pretty quickly.
-const size_t kLargePermittedAllocation = 0x7FFFE000;
-
-int OnNoMemory(size_t) {
- _exit(1);
-}
-
-void ExhaustMemoryWithMalloc() {
- for (;;) {
- // Without the |volatile|, clang optimizes away the allocation.
- void* volatile buf = malloc(kLargePermittedAllocation);
- if (!buf)
- break;
- }
-}
-
-void ExhaustMemoryWithRealloc() {
- size_t size = kLargePermittedAllocation;
- void* buf = malloc(size);
- if (!buf)
- return;
- for (;;) {
- size += kLargePermittedAllocation;
- void* new_buf = realloc(buf, size);
- if (!buf)
- break;
- buf = new_buf;
- }
-}
-#endif
-
// 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
@@ -92,146 +57,16 @@ NOINLINE Type HideValueFromCompiler(volatile Type value) {
#define MALLOC_OVERFLOW_TEST(function) DISABLED_##function
#endif
-// TODO(jln): switch to std::numeric_limits<int>::max() when we switch to
-// C++11.
-const size_t kTooBigAllocSize = INT_MAX;
-
+#if defined(OS_LINUX) && defined(__x86_64__)
// Detect runtime TCMalloc bypasses.
bool IsTcMallocBypassed() {
-#if defined(OS_LINUX)
// This should detect a TCMalloc bypass from Valgrind.
char* g_slice = getenv("G_SLICE");
if (g_slice && !strcmp(g_slice, "always-malloc"))
return true;
-#endif
return false;
}
-
-bool CallocDiesOnOOM() {
-// The sanitizers' calloc dies on OOM instead of returning NULL.
-// The wrapper function in base/process/memory_linux.cc that is used when we
-// compile without TCMalloc will just die on OOM instead of returning NULL,
-// but the wrapper only works with glibc, and the file is not currently
-// included in the libchrome build.
-#if defined(ADDRESS_SANITIZER) || \
- defined(MEMORY_SANITIZER) || \
- defined(THREAD_SANITIZER) || \
- (defined(OS_LINUX) && defined(NO_TCMALLOC))
- return true;
-#else
- return false;
#endif
-}
-
-// Fake test that allow to know the state of TCMalloc by looking at bots.
-TEST(SecurityTest, MALLOC_OVERFLOW_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, MALLOC_OVERFLOW_TEST(MemoryAllocationRestrictionsMalloc)) {
- if (!IsTcMallocBypassed()) {
- scoped_ptr<char, base::FreeDeleter> ptr(static_cast<char*>(
- HideValueFromCompiler(malloc(kTooBigAllocSize))));
- ASSERT_TRUE(!ptr);
- }
-}
-
-#if defined(GTEST_HAS_DEATH_TEST) && defined(OS_WIN)
-TEST(SecurityTest, MALLOC_OVERFLOW_TEST(MemoryAllocationMallocDeathTest)) {
- _set_new_handler(&OnNoMemory);
- _set_new_mode(1);
- {
- scoped_ptr<char, base::FreeDeleter> ptr;
- EXPECT_DEATH(ptr.reset(static_cast<char*>(
- HideValueFromCompiler(malloc(kTooBigAllocSize)))),
- "");
- ASSERT_TRUE(!ptr);
- }
- _set_new_handler(NULL);
- _set_new_mode(0);
-}
-
-TEST(SecurityTest, MALLOC_OVERFLOW_TEST(MemoryAllocationExhaustDeathTest)) {
- _set_new_handler(&OnNoMemory);
- _set_new_mode(1);
- {
- ASSERT_DEATH(ExhaustMemoryWithMalloc(), "");
- }
- _set_new_handler(NULL);
- _set_new_mode(0);
-}
-
-TEST(SecurityTest, MALLOC_OVERFLOW_TEST(MemoryReallocationExhaustDeathTest)) {
- _set_new_handler(&OnNoMemory);
- _set_new_mode(1);
- {
- ASSERT_DEATH(ExhaustMemoryWithRealloc(), "");
- }
- _set_new_handler(NULL);
- _set_new_mode(0);
-}
-#endif
-
-TEST(SecurityTest, MALLOC_OVERFLOW_TEST(MemoryAllocationRestrictionsCalloc)) {
- if (!IsTcMallocBypassed()) {
- scoped_ptr<char, base::FreeDeleter> ptr(static_cast<char*>(
- HideValueFromCompiler(calloc(kTooBigAllocSize, 1))));
- ASSERT_TRUE(!ptr);
- }
-}
-
-TEST(SecurityTest, MALLOC_OVERFLOW_TEST(MemoryAllocationRestrictionsRealloc)) {
- if (!IsTcMallocBypassed()) {
- char* orig_ptr = static_cast<char*>(malloc(1));
- ASSERT_TRUE(orig_ptr);
- scoped_ptr<char, base::FreeDeleter> ptr(static_cast<char*>(
- 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, MALLOC_OVERFLOW_TEST(MemoryAllocationRestrictionsNew)) {
- if (!IsTcMallocBypassed()) {
- scoped_ptr<VeryLargeStruct> ptr(
- HideValueFromCompiler(new (nothrow) VeryLargeStruct));
- ASSERT_TRUE(!ptr);
- }
-}
-
-#if defined(GTEST_HAS_DEATH_TEST) && defined(OS_WIN)
-TEST(SecurityTest, MALLOC_OVERFLOW_TEST(MemoryAllocationNewDeathTest)) {
- _set_new_handler(&OnNoMemory);
- {
- scoped_ptr<VeryLargeStruct> ptr;
- EXPECT_DEATH(
- ptr.reset(HideValueFromCompiler(new (nothrow) VeryLargeStruct)), "");
- ASSERT_TRUE(!ptr);
- }
- _set_new_handler(NULL);
-}
-#endif
-
-TEST(SecurityTest, MALLOC_OVERFLOW_TEST(MemoryAllocationRestrictionsNewArray)) {
- if (!IsTcMallocBypassed()) {
- scoped_ptr<char[]> ptr(
- HideValueFromCompiler(new (nothrow) char[kTooBigAllocSize]));
- ASSERT_TRUE(!ptr);
- }
-}
-
-// The tests bellow check for overflows in new[] and calloc().
// 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
@@ -251,7 +86,7 @@ void OverflowTestsSoftExpectTrue(bool overflow_detected) {
}
}
-#if defined(OS_IOS) || defined(OS_WIN) || defined(THREAD_SANITIZER) || defined(OS_MACOSX)
+#if defined(OS_IOS) || defined(OS_WIN) || defined(OS_MACOSX)
#define MAYBE_NewOverflow DISABLED_NewOverflow
#else
#define MAYBE_NewOverflow NewOverflow
@@ -289,35 +124,6 @@ TEST(SecurityTest, MAYBE_NewOverflow) {
#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<char, base::FreeDeleter> array_pointer(
- static_cast<char*>(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.
-// Currently disabled, see b/23428680
-TEST(SecurityTest, DISABLED_CallocOverflow) {
- const size_t kArraySize = 4096;
- const size_t kMaxSizeT = numeric_limits<size_t>::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(__x86_64__)
// Check if ptr1 and ptr2 are separated by less than size chars.
bool ArePointersToSameArea(void* ptr1, void* ptr2, size_t size) {
diff --git a/base/sequence_checker_impl.h b/base/sequence_checker_impl.h
index 741aafee64..e3c5fed508 100644
--- a/base/sequence_checker_impl.h
+++ b/base/sequence_checker_impl.h
@@ -6,7 +6,7 @@
#define BASE_SEQUENCE_CHECKER_IMPL_H_
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/synchronization/lock.h"
#include "base/threading/sequenced_worker_pool.h"
#include "base/threading/thread_checker_impl.h"
diff --git a/base/sequence_checker_unittest.cc b/base/sequence_checker_unittest.cc
index 0aa0f9cdbb..e261b04d72 100644
--- a/base/sequence_checker_unittest.cc
+++ b/base/sequence_checker_unittest.cc
@@ -2,14 +2,19 @@
// 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/sequence_checker.h"
+
+#include <stddef.h>
+
+#include <utility>
+
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/location.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
-#include "base/sequence_checker.h"
#include "base/single_thread_task_runner.h"
#include "base/test/sequenced_worker_pool_owner.h"
#include "base/threading/thread.h"
@@ -63,7 +68,6 @@ class SequenceCheckerTest : public testing::Test {
void TearDown() override {
other_thread_.Stop();
- pool()->Shutdown();
}
protected:
@@ -130,7 +134,7 @@ TEST_F(SequenceCheckerTest, DestructorAllowedOnDifferentThread) {
new SequenceCheckedObject);
// Verify the destructor doesn't assert when called on a different thread.
- PostDeleteToOtherThread(sequence_checked_object.Pass());
+ PostDeleteToOtherThread(std::move(sequence_checked_object));
other_thread()->Stop();
}
@@ -157,7 +161,7 @@ TEST_F(SequenceCheckerTest, SameSequenceTokenValid) {
PostDoStuffToWorkerPool(sequence_checked_object.get(), "A");
pool()->FlushForTesting();
- PostDeleteToOtherThread(sequence_checked_object.Pass());
+ PostDeleteToOtherThread(std::move(sequence_checked_object));
other_thread()->Stop();
}
@@ -175,7 +179,7 @@ TEST_F(SequenceCheckerTest, DetachSequenceTokenValid) {
PostDoStuffToWorkerPool(sequence_checked_object.get(), "B");
pool()->FlushForTesting();
- PostDeleteToOtherThread(sequence_checked_object.Pass());
+ PostDeleteToOtherThread(std::move(sequence_checked_object));
other_thread()->Stop();
}
@@ -245,7 +249,7 @@ void SequenceCheckerTest::DifferentSequenceTokensDeathTest() {
PostDoStuffToWorkerPool(sequence_checked_object.get(), "B");
pool()->FlushForTesting();
- PostDeleteToOtherThread(sequence_checked_object.Pass());
+ PostDeleteToOtherThread(std::move(sequence_checked_object));
other_thread()->Stop();
}
@@ -306,7 +310,6 @@ void SequenceCheckerTest::TwoDifferentWorkerPoolsDeathTest() {
base::Bind(&SequenceCheckedObject::DoStuff,
base::Unretained(sequence_checked_object.get())));
second_pool_owner.pool()->FlushForTesting();
- second_pool_owner.pool()->Shutdown();
}
#if ENABLE_SEQUENCE_CHECKER
diff --git a/base/sequenced_task_runner_helpers.h b/base/sequenced_task_runner_helpers.h
index da519bf918..7980b46b6c 100644
--- a/base/sequenced_task_runner_helpers.h
+++ b/base/sequenced_task_runner_helpers.h
@@ -5,8 +5,8 @@
#ifndef BASE_SEQUENCED_TASK_RUNNER_HELPERS_H_
#define BASE_SEQUENCED_TASK_RUNNER_HELPERS_H_
-#include "base/basictypes.h"
#include "base/debug/alias.h"
+#include "base/macros.h"
// TODO(akalin): Investigate whether it's possible to just have
// SequencedTaskRunner use these helpers (instead of MessageLoop).
diff --git a/base/sha1.h b/base/sha1.h
index 998cccba8d..902e301331 100644
--- a/base/sha1.h
+++ b/base/sha1.h
@@ -5,6 +5,8 @@
#ifndef BASE_SHA1_H_
#define BASE_SHA1_H_
+#include <stddef.h>
+
#include <string>
#include "base/base_export.h"
diff --git a/base/sha1_portable.cc b/base/sha1_portable.cc
index 0b9df83079..dd2ab6fe17 100644
--- a/base/sha1_portable.cc
+++ b/base/sha1_portable.cc
@@ -4,9 +4,10 @@
#include "base/sha1.h"
+#include <stddef.h>
+#include <stdint.h>
#include <string.h>
-#include "base/basictypes.h"
namespace base {
@@ -50,20 +51,20 @@ class SecureHashAlgorithm {
void Pad();
void Process();
- uint32 A, B, C, D, E;
+ uint32_t A, B, C, D, E;
- uint32 H[5];
+ uint32_t H[5];
union {
- uint32 W[80];
- uint8 M[64];
+ uint32_t W[80];
+ uint8_t M[64];
};
- uint32 cursor;
- uint64 l;
+ uint32_t cursor;
+ uint64_t l;
};
-static inline uint32 f(uint32 t, uint32 B, uint32 C, uint32 D) {
+static inline uint32_t f(uint32_t t, uint32_t B, uint32_t C, uint32_t D) {
if (t < 20) {
return (B & C) | ((~B) & D);
} else if (t < 40) {
@@ -75,11 +76,11 @@ static inline uint32 f(uint32 t, uint32 B, uint32 C, uint32 D) {
}
}
-static inline uint32 S(uint32 n, uint32 X) {
+static inline uint32_t S(uint32_t n, uint32_t X) {
return (X << n) | (X >> (32-n));
}
-static inline uint32 K(uint32 t) {
+static inline uint32_t K(uint32_t t) {
if (t < 20) {
return 0x5a827999;
} else if (t < 40) {
@@ -91,7 +92,7 @@ static inline uint32 K(uint32 t) {
}
}
-static inline void swapends(uint32* t) {
+static inline void swapends(uint32_t* t) {
*t = (*t >> 24) | ((*t >> 8) & 0xff00) | ((*t & 0xff00) << 8) | (*t << 24);
}
@@ -121,7 +122,7 @@ void SecureHashAlgorithm::Final() {
}
void SecureHashAlgorithm::Update(const void* data, size_t nbytes) {
- const uint8* d = reinterpret_cast<const uint8*>(data);
+ const uint8_t* d = reinterpret_cast<const uint8_t*>(data);
while (nbytes--) {
M[cursor++] = *d++;
if (cursor >= 64)
@@ -155,7 +156,7 @@ void SecureHashAlgorithm::Pad() {
}
void SecureHashAlgorithm::Process() {
- uint32 t;
+ uint32_t t;
// Each a...e corresponds to a section in the FIPS 180-3 algorithm.
@@ -179,7 +180,7 @@ void SecureHashAlgorithm::Process() {
// d.
for (t = 0; t < 80; ++t) {
- uint32 TEMP = S(5, A) + f(t, B, C, D) + E + W[t] + K(t);
+ uint32_t TEMP = S(5, A) + f(t, B, C, D) + E + W[t] + K(t);
E = D;
D = C;
C = S(30, B);
diff --git a/base/sha1_unittest.cc b/base/sha1_unittest.cc
index b29fe4662a..ea9cf634a5 100644
--- a/base/sha1_unittest.cc
+++ b/base/sha1_unittest.cc
@@ -4,9 +4,10 @@
#include "base/sha1.h"
+#include <stddef.h>
+
#include <string>
-#include "base/basictypes.h"
#include "testing/gtest/include/gtest/gtest.h"
TEST(SHA1Test, Test1) {
diff --git a/base/stl_util.h b/base/stl_util.h
index e937d2f3ed..12e226a9db 100644
--- a/base/stl_util.h
+++ b/base/stl_util.h
@@ -98,19 +98,6 @@ STLCount(const Container& container, const T& val) {
return std::count(container.begin(), container.end(), val);
}
-// 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<typename T>
-inline T* vector_as_array(std::vector<T>* v) {
- return v->empty() ? NULL : &*v->begin();
-}
-
-template<typename T>
-inline const T* vector_as_array(const std::vector<T>* 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.
diff --git a/base/strings/pattern.cc b/base/strings/pattern.cc
new file mode 100644
index 0000000000..af30aab86d
--- /dev/null
+++ b/base/strings/pattern.cc
@@ -0,0 +1,169 @@
+// Copyright 2015 The Chromium Authors. All 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/pattern.h"
+
+#include "base/third_party/icu/icu_utf.h"
+
+namespace base {
+
+namespace {
+
+static bool IsWildcard(base_icu::UChar32 character) {
+ return character == '*' || character == '?';
+}
+
+// Move the strings pointers to the point where they start to differ.
+template <typename CHAR, typename NEXT>
+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 != CBU_SENTINEL) {
+ *pattern = pattern_next;
+ *string = string_next;
+ } else {
+ // Uh oh, 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 <typename CHAR, typename NEXT>
+static void EatWildcard(const CHAR** pattern, const CHAR* end, NEXT next) {
+ while (*pattern != end) {
+ if (!IsWildcard(**pattern))
+ return;
+ next(pattern, end);
+ }
+}
+
+template <typename CHAR, typename NEXT>
+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;
+ }
+};
+
+} // namespace
+
+bool MatchPattern(const StringPiece& eval, const StringPiece& pattern) {
+ return MatchPatternT(eval.data(), eval.data() + eval.size(),
+ pattern.data(), pattern.data() + pattern.size(),
+ 0, NextCharUTF8());
+}
+
+bool MatchPattern(const StringPiece16& eval, const StringPiece16& pattern) {
+ return MatchPatternT(eval.data(), eval.data() + eval.size(),
+ pattern.data(), pattern.data() + pattern.size(),
+ 0, NextCharUTF16());
+}
+
+} // namespace base
diff --git a/base/strings/pattern.h b/base/strings/pattern.h
new file mode 100644
index 0000000000..b698207b9d
--- /dev/null
+++ b/base/strings/pattern.h
@@ -0,0 +1,26 @@
+// Copyright 2015 The Chromium Authors. All 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_PATTERN_H_
+#define BASE_STRINGS_PATTERN_H_
+
+#include "base/base_export.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+
+// 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 StringPiece& string,
+ const StringPiece& pattern);
+BASE_EXPORT bool MatchPattern(const StringPiece16& string,
+ const StringPiece16& pattern);
+
+} // namespace base
+
+#endif // BASE_STRINGS_PATTERN_H_
diff --git a/base/strings/pattern_unittest.cc b/base/strings/pattern_unittest.cc
new file mode 100644
index 0000000000..9e82b3cba1
--- /dev/null
+++ b/base/strings/pattern_unittest.cc
@@ -0,0 +1,50 @@
+// Copyright 2015 The Chromium Authors. All 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/pattern.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+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")));
+}
+
+} // namespace base
diff --git a/base/strings/safe_sprintf.cc b/base/strings/safe_sprintf.cc
index b1fcf45b24..a51c778271 100644
--- a/base/strings/safe_sprintf.cc
+++ b/base/strings/safe_sprintf.cc
@@ -4,8 +4,14 @@
#include "base/strings/safe_sprintf.h"
+#include <errno.h>
+#include <string.h>
+
#include <limits>
+#include "base/macros.h"
+#include "build/build_config.h"
+
#if !defined(NDEBUG)
// In debug builds, we use RAW_CHECK() to print useful error messages, if
// SafeSPrintf() is called with broken arguments.
@@ -69,7 +75,7 @@ const char kDownCaseHexDigits[] = "0123456789abcdef";
#if defined(NDEBUG)
// We would like to define kSSizeMax as std::numeric_limits<ssize_t>::max(),
// but C++ doesn't allow us to do that for constants. Instead, we have to
-// use careful casting and shifting. We later use a COMPILE_ASSERT to
+// use careful casting and shifting. We later use a static_assert to
// verify that this worked correctly.
namespace {
const size_t kSSizeMax = kSSizeMaxConst;
@@ -107,18 +113,13 @@ class Buffer {
: buffer_(buffer),
size_(size - 1), // Account for trailing NUL byte
count_(0) {
-// The following assertion does not build on Mac and Android. This is because
-// static_assert only works with compile-time constants, but mac uses
-// libstdc++4.2 and android uses stlport, which both don't mark
-// numeric_limits::max() as constexp. Likewise, MSVS2013's standard library
-// also doesn't mark max() as constexpr yet. cl.exe supports static_cast but
-// doesn't really implement constexpr yet so it doesn't complain, but clang
-// does.
-#if __cplusplus >= 201103 && !defined(OS_ANDROID) && !defined(OS_MACOSX) && \
- !defined(OS_IOS) && !(defined(__clang__) && defined(OS_WIN))
- COMPILE_ASSERT(kSSizeMaxConst == \
- static_cast<size_t>(std::numeric_limits<ssize_t>::max()),
- kSSizeMax_is_the_max_value_of_an_ssize_t);
+// MSVS2013's standard library doesn't mark max() as constexpr yet. cl.exe
+// supports static_cast but doesn't really implement constexpr yet so it doesn't
+// complain, but clang does.
+#if __cplusplus >= 201103 && !(defined(__clang__) && defined(OS_WIN))
+ static_assert(kSSizeMaxConst ==
+ static_cast<size_t>(std::numeric_limits<ssize_t>::max()),
+ "kSSizeMaxConst should be the max value of an ssize_t");
#endif
DEBUG_CHECK(size > 0);
DEBUG_CHECK(size <= kSSizeMax);
diff --git a/base/strings/safe_sprintf.h b/base/strings/safe_sprintf.h
index 2d173202d3..65524a50c3 100644
--- a/base/strings/safe_sprintf.h
+++ b/base/strings/safe_sprintf.h
@@ -17,7 +17,6 @@
#endif
#include "base/base_export.h"
-#include "base/basictypes.h"
namespace base {
namespace strings {
diff --git a/base/strings/string16.h b/base/strings/string16.h
index 1a01a9613e..e47669c1b5 100644
--- a/base/strings/string16.h
+++ b/base/strings/string16.h
@@ -26,11 +26,13 @@
// libc functions with custom, 2-byte-char compatible routines. It is capable
// of carrying UTF-16-encoded data.
+#include <stddef.h>
+#include <stdint.h>
#include <stdio.h>
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "build/build_config.h"
#if defined(WCHAR_T_IS_UTF16)
@@ -46,7 +48,7 @@ typedef std::char_traits<wchar_t> string16_char_traits;
namespace base {
-typedef uint16 char16;
+typedef uint16_t 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"
@@ -64,7 +66,8 @@ struct string16_char_traits {
// 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);
+ static_assert(sizeof(int_type) > sizeof(char_type),
+ "int must be larger than 16 bits wide");
typedef std::streamoff off_type;
typedef mbstate_t state_type;
diff --git a/base/strings/string_number_conversions.cc b/base/strings/string_number_conversions.cc
index cd7481810c..f869b416be 100644
--- a/base/strings/string_number_conversions.cc
+++ b/base/strings/string_number_conversions.cc
@@ -12,83 +12,45 @@
#include <limits>
#include "base/logging.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/numerics/safe_math.h"
#include "base/strings/utf_string_conversions.h"
namespace base {
namespace {
-template <typename STR, typename INT, typename UINT, bool NEG>
+template <typename STR, typename INT>
struct IntToStringT {
- // This is to avoid a compiler warning about unary minus on unsigned type.
- // For example, say you had the following code:
- // template <typename INT>
- // 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 <typename INT2, typename UINT2, bool NEG2>
- struct ToUnsignedT {};
-
- template <typename INT2, typename UINT2>
- struct ToUnsignedT<INT2, UINT2, false> {
- static UINT2 ToUnsigned(INT2 value) {
- return static_cast<UINT2>(value);
- }
- };
-
- template <typename INT2, typename UINT2>
- struct ToUnsignedT<INT2, UINT2, true> {
- static UINT2 ToUnsigned(INT2 value) {
- return static_cast<UINT2>(value < 0 ? -value : value);
- }
- };
-
- // This set of templates is very similar to the above templates, but
- // for testing whether an integer is negative.
- template <typename INT2, bool NEG2>
- struct TestNegT {};
- template <typename INT2>
- struct TestNegT<INT2, false> {
- static bool TestNeg(INT2 /* value */) {
- // value is unsigned, and can never be negative.
- return false;
- }
- };
- template <typename INT2>
- struct TestNegT<INT2, true> {
- 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;
+ const size_t kOutputBufSize =
+ 3 * sizeof(INT) + std::numeric_limits<INT>::is_signed;
- // Allocate the whole string right away, we will right back to front, and
+ // Create the string in a temporary buffer, write it back to front, and
// then return the substr of what we ended up using.
- STR outbuf(kOutputBufSize, 0);
+ using CHR = typename STR::value_type;
+ CHR outbuf[kOutputBufSize];
- bool is_neg = TestNegT<INT, NEG>::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<INT, UINT, NEG>::ToUnsigned(value);
+ // The ValueOrDie call below can never fail, because UnsignedAbs is valid
+ // for all valid inputs.
+ auto res = CheckedNumeric<INT>(value).UnsignedAbs().ValueOrDie();
- typename STR::iterator it(outbuf.end());
+ CHR* end = outbuf + kOutputBufSize;
+ CHR* i = end;
do {
- --it;
- DCHECK(it != outbuf.begin());
- *it = static_cast<typename STR::value_type>((res % 10) + '0');
+ --i;
+ DCHECK(i != outbuf);
+ *i = static_cast<CHR>((res % 10) + '0');
res /= 10;
} while (res != 0);
- if (is_neg) {
- --it;
- DCHECK(it != outbuf.begin());
- *it = static_cast<typename STR::value_type>('-');
+ if (IsValueNegative(value)) {
+ --i;
+ DCHECK(i != outbuf);
+ *i = static_cast<CHR>('-');
}
- return STR(it, outbuf.end());
+ return STR(i, end);
}
};
@@ -99,9 +61,9 @@ template<typename CHAR, int BASE, bool BASE_LTE_10> class BaseCharToDigit {
// Faster specialization for bases <= 10
template<typename CHAR, int BASE> class BaseCharToDigit<CHAR, BASE, true> {
public:
- static bool Convert(CHAR c, uint8* digit) {
+ static bool Convert(CHAR c, uint8_t* digit) {
if (c >= '0' && c < '0' + BASE) {
- *digit = static_cast<uint8>(c - '0');
+ *digit = static_cast<uint8_t>(c - '0');
return true;
}
return false;
@@ -111,7 +73,7 @@ template<typename CHAR, int BASE> class BaseCharToDigit<CHAR, BASE, true> {
// Specialization for bases where 10 < base <= 36
template<typename CHAR, int BASE> class BaseCharToDigit<CHAR, BASE, false> {
public:
- static bool Convert(CHAR c, uint8* digit) {
+ static bool Convert(CHAR c, uint8_t* digit) {
if (c >= '0' && c <= '9') {
*digit = c - '0';
} else if (c >= 'a' && c < 'a' + BASE - 10) {
@@ -125,14 +87,15 @@ template<typename CHAR, int BASE> class BaseCharToDigit<CHAR, BASE, false> {
}
};
-template<int BASE, typename CHAR> bool CharToDigit(CHAR c, uint8* digit) {
+template <int BASE, typename CHAR>
+bool CharToDigit(CHAR c, uint8_t* digit) {
return BaseCharToDigit<CHAR, BASE, BASE <= 10>::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.
+// There is an IsUnicodeWhitespace 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<typename CHAR> class WhitespaceHelper {
};
@@ -222,7 +185,7 @@ class IteratorRangeToNumber {
}
for (const_iterator current = begin; current != end; ++current) {
- uint8 new_digit = 0;
+ uint8_t new_digit = 0;
if (!CharToDigit<traits::kBase>(*current, &new_digit)) {
return false;
@@ -243,7 +206,7 @@ class IteratorRangeToNumber {
class Positive : public Base<Positive> {
public:
- static bool CheckBounds(value_type* output, uint8 new_digit) {
+ static bool CheckBounds(value_type* output, uint8_t new_digit) {
if (*output > static_cast<value_type>(traits::max() / traits::kBase) ||
(*output == static_cast<value_type>(traits::max() / traits::kBase) &&
new_digit > traits::max() % traits::kBase)) {
@@ -252,14 +215,14 @@ class IteratorRangeToNumber {
}
return true;
}
- static void Increment(uint8 increment, value_type* output) {
+ static void Increment(uint8_t increment, value_type* output) {
*output += increment;
}
};
class Negative : public Base<Negative> {
public:
- static bool CheckBounds(value_type* output, uint8 new_digit) {
+ static bool CheckBounds(value_type* output, uint8_t new_digit) {
if (*output < traits::min() / traits::kBase ||
(*output == traits::min() / traits::kBase &&
new_digit > 0 - traits::min() % traits::kBase)) {
@@ -268,7 +231,7 @@ class IteratorRangeToNumber {
}
return true;
}
- static void Increment(uint8 increment, value_type* output) {
+ static void Increment(uint8_t increment, value_type* output) {
*output -= increment;
}
};
@@ -293,20 +256,17 @@ class BaseHexIteratorRangeToIntTraits
: public BaseIteratorRangeToNumberTraits<ITERATOR, int, 16> {
};
-template<typename ITERATOR>
+template <typename ITERATOR>
class BaseHexIteratorRangeToUIntTraits
- : public BaseIteratorRangeToNumberTraits<ITERATOR, uint32, 16> {
-};
+ : public BaseIteratorRangeToNumberTraits<ITERATOR, uint32_t, 16> {};
-template<typename ITERATOR>
+template <typename ITERATOR>
class BaseHexIteratorRangeToInt64Traits
- : public BaseIteratorRangeToNumberTraits<ITERATOR, int64, 16> {
-};
+ : public BaseIteratorRangeToNumberTraits<ITERATOR, int64_t, 16> {};
-template<typename ITERATOR>
+template <typename ITERATOR>
class BaseHexIteratorRangeToUInt64Traits
- : public BaseIteratorRangeToNumberTraits<ITERATOR, uint64, 16> {
-};
+ : public BaseIteratorRangeToNumberTraits<ITERATOR, uint64_t, 16> {};
typedef BaseHexIteratorRangeToIntTraits<StringPiece::const_iterator>
HexIteratorRangeToIntTraits;
@@ -320,15 +280,15 @@ typedef BaseHexIteratorRangeToInt64Traits<StringPiece::const_iterator>
typedef BaseHexIteratorRangeToUInt64Traits<StringPiece::const_iterator>
HexIteratorRangeToUInt64Traits;
-template<typename STR>
-bool HexStringToBytesT(const STR& input, std::vector<uint8>* output) {
+template <typename STR>
+bool HexStringToBytesT(const STR& input, std::vector<uint8_t>* 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
+ uint8_t msb = 0; // most significant 4 bits
+ uint8_t lsb = 0; // least significant 4 bits
if (!CharToDigit<16>(input[i * 2], &msb) ||
!CharToDigit<16>(input[i * 2 + 1], &lsb))
return false;
@@ -366,47 +326,43 @@ bool String16ToIntImpl(const StringPiece16& input, VALUE* output) {
} // namespace
std::string IntToString(int value) {
- return IntToStringT<std::string, int, unsigned int, true>::
- IntToString(value);
+ return IntToStringT<std::string, int>::IntToString(value);
}
string16 IntToString16(int value) {
- return IntToStringT<string16, int, unsigned int, true>::
- IntToString(value);
+ return IntToStringT<string16, int>::IntToString(value);
}
std::string UintToString(unsigned int value) {
- return IntToStringT<std::string, unsigned int, unsigned int, false>::
- IntToString(value);
+ return IntToStringT<std::string, unsigned int>::IntToString(value);
}
string16 UintToString16(unsigned int value) {
- return IntToStringT<string16, unsigned int, unsigned int, false>::
- IntToString(value);
+ return IntToStringT<string16, unsigned int>::IntToString(value);
}
-std::string Int64ToString(int64 value) {
- return IntToStringT<std::string, int64, uint64, true>::IntToString(value);
+std::string Int64ToString(int64_t value) {
+ return IntToStringT<std::string, int64_t>::IntToString(value);
}
-string16 Int64ToString16(int64 value) {
- return IntToStringT<string16, int64, uint64, true>::IntToString(value);
+string16 Int64ToString16(int64_t value) {
+ return IntToStringT<string16, int64_t>::IntToString(value);
}
-std::string Uint64ToString(uint64 value) {
- return IntToStringT<std::string, uint64, uint64, false>::IntToString(value);
+std::string Uint64ToString(uint64_t value) {
+ return IntToStringT<std::string, uint64_t>::IntToString(value);
}
-string16 Uint64ToString16(uint64 value) {
- return IntToStringT<string16, uint64, uint64, false>::IntToString(value);
+string16 Uint64ToString16(uint64_t value) {
+ return IntToStringT<string16, uint64_t>::IntToString(value);
}
std::string SizeTToString(size_t value) {
- return IntToStringT<std::string, size_t, size_t, false>::IntToString(value);
+ return IntToStringT<std::string, size_t>::IntToString(value);
}
string16 SizeTToString16(size_t value) {
- return IntToStringT<string16, size_t, size_t, false>::IntToString(value);
+ return IntToStringT<string16, size_t>::IntToString(value);
}
std::string DoubleToString(double value) {
@@ -440,19 +396,19 @@ bool StringToUint(const StringPiece16& input, unsigned* output) {
return String16ToIntImpl(input, output);
}
-bool StringToInt64(const StringPiece& input, int64* output) {
+bool StringToInt64(const StringPiece& input, int64_t* output) {
return StringToIntImpl(input, output);
}
-bool StringToInt64(const StringPiece16& input, int64* output) {
+bool StringToInt64(const StringPiece16& input, int64_t* output) {
return String16ToIntImpl(input, output);
}
-bool StringToUint64(const StringPiece& input, uint64* output) {
+bool StringToUint64(const StringPiece& input, uint64_t* output) {
return StringToIntImpl(input, output);
}
-bool StringToUint64(const StringPiece16& input, uint64* output) {
+bool StringToUint64(const StringPiece16& input, uint64_t* output) {
return String16ToIntImpl(input, output);
}
@@ -510,22 +466,22 @@ bool HexStringToInt(const StringPiece& input, int* output) {
input.begin(), input.end(), output);
}
-bool HexStringToUInt(const StringPiece& input, uint32* output) {
+bool HexStringToUInt(const StringPiece& input, uint32_t* output) {
return IteratorRangeToNumber<HexIteratorRangeToUIntTraits>::Invoke(
input.begin(), input.end(), output);
}
-bool HexStringToInt64(const StringPiece& input, int64* output) {
+bool HexStringToInt64(const StringPiece& input, int64_t* output) {
return IteratorRangeToNumber<HexIteratorRangeToInt64Traits>::Invoke(
input.begin(), input.end(), output);
}
-bool HexStringToUInt64(const StringPiece& input, uint64* output) {
+bool HexStringToUInt64(const StringPiece& input, uint64_t* output) {
return IteratorRangeToNumber<HexIteratorRangeToUInt64Traits>::Invoke(
input.begin(), input.end(), output);
}
-bool HexStringToBytes(const std::string& input, std::vector<uint8>* output) {
+bool HexStringToBytes(const std::string& input, std::vector<uint8_t>* output) {
return HexStringToBytesT(input, output);
}
diff --git a/base/strings/string_number_conversions.h b/base/strings/string_number_conversions.h
index ee4c7a56e4..4a50284c87 100644
--- a/base/strings/string_number_conversions.h
+++ b/base/strings/string_number_conversions.h
@@ -5,11 +5,13 @@
#ifndef BASE_STRINGS_STRING_NUMBER_CONVERSIONS_H_
#define BASE_STRINGS_STRING_NUMBER_CONVERSIONS_H_
+#include <stddef.h>
+#include <stdint.h>
+
#include <string>
#include <vector>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/strings/string16.h"
#include "base/strings/string_piece.h"
@@ -35,11 +37,11 @@ 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 Int64ToString(int64_t value);
+BASE_EXPORT string16 Int64ToString16(int64_t value);
-BASE_EXPORT std::string Uint64ToString(uint64 value);
-BASE_EXPORT string16 Uint64ToString16(uint64 value);
+BASE_EXPORT std::string Uint64ToString(uint64_t value);
+BASE_EXPORT string16 Uint64ToString16(uint64_t value);
BASE_EXPORT std::string SizeTToString(size_t value);
BASE_EXPORT string16 SizeTToString16(size_t value);
@@ -65,17 +67,19 @@ BASE_EXPORT std::string DoubleToString(double value);
// - 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.
+// WARNING: Will write to |output| even when returning false.
+// Read the comments above carefully.
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 StringToInt64(const StringPiece& input, int64_t* output);
+BASE_EXPORT bool StringToInt64(const StringPiece16& input, int64_t* output);
-BASE_EXPORT bool StringToUint64(const StringPiece& input, uint64* output);
-BASE_EXPORT bool StringToUint64(const StringPiece16& input, uint64* output);
+BASE_EXPORT bool StringToUint64(const StringPiece& input, uint64_t* output);
+BASE_EXPORT bool StringToUint64(const StringPiece16& input, uint64_t* output);
BASE_EXPORT bool StringToSizeT(const StringPiece& input, size_t* output);
BASE_EXPORT bool StringToSizeT(const StringPiece16& input, size_t* output);
@@ -83,10 +87,12 @@ BASE_EXPORT bool StringToSizeT(const StringPiece16& input, size_t* output);
// Deprecated: prefer std::stod() instead.
// 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
+// numbers in hexadecimal, and strings representing non-finite 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.
+// WARNING: Will write to |output| even when returning false.
+// Read the comments here and above StringToInt() carefully.
BASE_EXPORT bool StringToDouble(const std::string& input, double* output);
// Hex encoding ----------------------------------------------------------------
@@ -108,25 +114,25 @@ BASE_EXPORT bool HexStringToInt(const StringPiece& input, int* output);
// Will only successful parse hex values that will fit into |output|, i.e.
// 0x00000000 < |input| < 0xFFFFFFFF.
// The string is not required to start with 0x.
-BASE_EXPORT bool HexStringToUInt(const StringPiece& input, uint32* output);
+BASE_EXPORT bool HexStringToUInt(const StringPiece& input, uint32_t* 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);
+BASE_EXPORT bool HexStringToInt64(const StringPiece& input, int64_t* 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);
+BASE_EXPORT bool HexStringToUInt64(const StringPiece& input, uint64_t* 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<uint8>* output);
+ std::vector<uint8_t>* output);
} // namespace base
diff --git a/base/strings/string_number_conversions_unittest.cc b/base/strings/string_number_conversions_unittest.cc
index e5b855a0e8..0ed06a1549 100644
--- a/base/strings/string_number_conversions_unittest.cc
+++ b/base/strings/string_number_conversions_unittest.cc
@@ -5,6 +5,8 @@
#include "base/strings/string_number_conversions.h"
#include <errno.h>
+#include <limits.h>
+#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
@@ -12,6 +14,7 @@
#include <limits>
#include "base/format_macros.h"
+#include "base/macros.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -36,15 +39,15 @@ TEST(StringNumberConversionsTest, IntToString) {
{ std::numeric_limits<int>::max(), "2147483647", "2147483647" },
{ std::numeric_limits<int>::min(), "-2147483648", "2147483648" },
};
- static const IntToStringTest<int64> int64_tests[] = {
- { 0, "0", "0" },
- { -1, "-1", "18446744073709551615" },
- { std::numeric_limits<int64>::max(),
- "9223372036854775807",
- "9223372036854775807", },
- { std::numeric_limits<int64>::min(),
- "-9223372036854775808",
- "9223372036854775808" },
+ static const IntToStringTest<int64_t> int64_tests[] = {
+ {0, "0", "0"},
+ {-1, "-1", "18446744073709551615"},
+ {
+ std::numeric_limits<int64_t>::max(), "9223372036854775807",
+ "9223372036854775807",
+ },
+ {std::numeric_limits<int64_t>::min(), "-9223372036854775808",
+ "9223372036854775808"},
};
for (size_t i = 0; i < arraysize(int_tests); ++i) {
@@ -55,7 +58,7 @@ TEST(StringNumberConversionsTest, IntToString) {
EXPECT_EQ(UintToString16(test->num), UTF8ToUTF16(test->uexpected));
}
for (size_t i = 0; i < arraysize(int64_tests); ++i) {
- const IntToStringTest<int64>* test = &int64_tests[i];
+ const IntToStringTest<int64_t>* 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);
@@ -65,13 +68,13 @@ TEST(StringNumberConversionsTest, IntToString) {
TEST(StringNumberConversionsTest, Uint64ToString) {
static const struct {
- uint64 input;
+ uint64_t input;
std::string output;
} cases[] = {
- {0, "0"},
- {42, "42"},
- {INT_MAX, "2147483647"},
- {kuint64max, "18446744073709551615"},
+ {0, "0"},
+ {42, "42"},
+ {INT_MAX, "2147483647"},
+ {std::numeric_limits<uint64_t>::max(), "18446744073709551615"},
};
for (size_t i = 0; i < arraysize(cases); ++i)
@@ -231,44 +234,44 @@ TEST(StringNumberConversionsTest, StringToUint) {
TEST(StringNumberConversionsTest, StringToInt64) {
static const struct {
std::string input;
- int64 output;
+ int64_t output;
bool success;
} cases[] = {
- {"0", 0, true},
- {"42", 42, true},
- {"-2147483648", INT_MIN, true},
- {"2147483647", INT_MAX, true},
- {"-2147483649", INT64_C(-2147483649), true},
- {"-99999999999", INT64_C(-99999999999), true},
- {"2147483648", INT64_C(2147483648), true},
- {"99999999999", 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},
+ {"0", 0, true},
+ {"42", 42, true},
+ {"-2147483648", INT_MIN, true},
+ {"2147483647", INT_MAX, true},
+ {"-2147483649", INT64_C(-2147483649), true},
+ {"-99999999999", INT64_C(-99999999999), true},
+ {"2147483648", INT64_C(2147483648), true},
+ {"99999999999", INT64_C(99999999999), true},
+ {"9223372036854775807", std::numeric_limits<int64_t>::max(), true},
+ {"-9223372036854775808", std::numeric_limits<int64_t>::min(), 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", std::numeric_limits<int64_t>::min(), false},
+ {"-99999999999999999999", std::numeric_limits<int64_t>::min(), false},
+ {"9223372036854775808", std::numeric_limits<int64_t>::max(), false},
+ {"99999999999999999999", std::numeric_limits<int64_t>::max(), false},
};
for (size_t i = 0; i < arraysize(cases); ++i) {
- int64 output = 0;
+ int64_t output = 0;
EXPECT_EQ(cases[i].success, StringToInt64(cases[i].input, &output));
EXPECT_EQ(cases[i].output, output);
@@ -283,7 +286,7 @@ TEST(StringNumberConversionsTest, StringToInt64) {
// interpreted as junk after the number.
const char input[] = "6\06";
std::string input_string(input, arraysize(input) - 1);
- int64 output;
+ int64_t output;
EXPECT_FALSE(StringToInt64(input_string, &output));
EXPECT_EQ(6, output);
@@ -296,46 +299,46 @@ TEST(StringNumberConversionsTest, StringToInt64) {
TEST(StringNumberConversionsTest, StringToUint64) {
static const struct {
std::string input;
- uint64 output;
+ uint64_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", UINT64_C(2147483648), true},
- {"99999999999", 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", UINT64_C(9223372036854775808), true},
- {"99999999999999999999", kuint64max, false},
- {"18446744073709551615", kuint64max, true},
- {"18446744073709551616", kuint64max, false},
+ {"0", 0, true},
+ {"42", 42, true},
+ {"-2147483648", 0, false},
+ {"2147483647", INT_MAX, true},
+ {"-2147483649", 0, false},
+ {"-99999999999", 0, false},
+ {"2147483648", UINT64_C(2147483648), true},
+ {"99999999999", UINT64_C(99999999999), true},
+ {"9223372036854775807", std::numeric_limits<int64_t>::max(), 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", UINT64_C(9223372036854775808), true},
+ {"99999999999999999999", std::numeric_limits<uint64_t>::max(), false},
+ {"18446744073709551615", std::numeric_limits<uint64_t>::max(), true},
+ {"18446744073709551616", std::numeric_limits<uint64_t>::max(), false},
};
for (size_t i = 0; i < arraysize(cases); ++i) {
- uint64 output = 0;
+ uint64_t output = 0;
EXPECT_EQ(cases[i].success, StringToUint64(cases[i].input, &output));
EXPECT_EQ(cases[i].output, output);
@@ -350,7 +353,7 @@ TEST(StringNumberConversionsTest, StringToUint64) {
// interpreted as junk after the number.
const char input[] = "6\06";
std::string input_string(input, arraysize(input) - 1);
- uint64 output;
+ uint64_t output;
EXPECT_FALSE(StringToUint64(input_string, &output));
EXPECT_EQ(6U, output);
@@ -432,7 +435,7 @@ TEST(StringNumberConversionsTest, StringToSizeT) {
TEST(StringNumberConversionsTest, HexStringToInt) {
static const struct {
std::string input;
- int64 output;
+ int64_t output;
bool success;
} cases[] = {
{"0", 0, true},
@@ -484,50 +487,55 @@ TEST(StringNumberConversionsTest, HexStringToInt) {
TEST(StringNumberConversionsTest, HexStringToUInt) {
static const struct {
std::string input;
- uint32 output;
+ uint32_t output;
bool success;
} cases[] = {
- {"0", 0, true},
- {"42", 0x42, true},
- {"-42", 0, false},
- {"+42", 0x42, true},
- {"7fffffff", INT_MAX, true},
- {"-80000000", 0, false},
- {"ffffffff", 0xffffffff, true},
- {"DeadBeef", 0xdeadbeef, true},
- {"0x42", 0x42, true},
- {"-0x42", 0, false},
- {"+0x42", 0x42, true},
- {"0x7fffffff", INT_MAX, true},
- {"-0x80000000", 0, false},
- {"0xffffffff", kuint32max, true},
- {"0XDeadBeef", 0xdeadbeef, true},
- {"0x7fffffffffffffff", kuint32max, false}, // Overflow test.
- {"-0x8000000000000000", 0, false},
- {"0x8000000000000000", kuint32max, false}, // Overflow test.
- {"-0x8000000000000001", 0, false},
- {"0xFFFFFFFFFFFFFFFF", kuint32max, false}, // Overflow test.
- {"FFFFFFFFFFFFFFFF", kuint32max, false}, // Overflow test.
- {"0x0000000000000000", 0, true},
- {"0000000000000000", 0, true},
- {"1FFFFFFFFFFFFFFFF", kuint32max, false}, // Overflow test.
- {"0x0f", 0x0f, true},
- {"0f", 0x0f, 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},
+ {"0", 0, true},
+ {"42", 0x42, true},
+ {"-42", 0, false},
+ {"+42", 0x42, true},
+ {"7fffffff", INT_MAX, true},
+ {"-80000000", 0, false},
+ {"ffffffff", 0xffffffff, true},
+ {"DeadBeef", 0xdeadbeef, true},
+ {"0x42", 0x42, true},
+ {"-0x42", 0, false},
+ {"+0x42", 0x42, true},
+ {"0x7fffffff", INT_MAX, true},
+ {"-0x80000000", 0, false},
+ {"0xffffffff", std::numeric_limits<uint32_t>::max(), true},
+ {"0XDeadBeef", 0xdeadbeef, true},
+ {"0x7fffffffffffffff", std::numeric_limits<uint32_t>::max(),
+ false}, // Overflow test.
+ {"-0x8000000000000000", 0, false},
+ {"0x8000000000000000", std::numeric_limits<uint32_t>::max(),
+ false}, // Overflow test.
+ {"-0x8000000000000001", 0, false},
+ {"0xFFFFFFFFFFFFFFFF", std::numeric_limits<uint32_t>::max(),
+ false}, // Overflow test.
+ {"FFFFFFFFFFFFFFFF", std::numeric_limits<uint32_t>::max(),
+ false}, // Overflow test.
+ {"0x0000000000000000", 0, true},
+ {"0000000000000000", 0, true},
+ {"1FFFFFFFFFFFFFFFF", std::numeric_limits<uint32_t>::max(),
+ false}, // Overflow test.
+ {"0x0f", 0x0f, true},
+ {"0f", 0x0f, 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(cases); ++i) {
- uint32 output = 0;
+ uint32_t output = 0;
EXPECT_EQ(cases[i].success, HexStringToUInt(cases[i].input, &output));
EXPECT_EQ(cases[i].output, output);
}
@@ -536,7 +544,7 @@ TEST(StringNumberConversionsTest, HexStringToUInt) {
// interpreted as junk after the number.
const char input[] = "0xc0ffee\0" "9";
std::string input_string(input, arraysize(input) - 1);
- uint32 output;
+ uint32_t output;
EXPECT_FALSE(HexStringToUInt(input_string, &output));
EXPECT_EQ(0xc0ffeeU, output);
}
@@ -544,47 +552,49 @@ TEST(StringNumberConversionsTest, HexStringToUInt) {
TEST(StringNumberConversionsTest, HexStringToInt64) {
static const struct {
std::string input;
- int64 output;
+ int64_t output;
bool success;
} cases[] = {
- {"0", 0, true},
- {"42", 66, true},
- {"-42", -66, true},
- {"+42", 66, true},
- {"40acd88557b", 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", 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},
+ {"0", 0, true},
+ {"42", 66, true},
+ {"-42", -66, true},
+ {"+42", 66, true},
+ {"40acd88557b", 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", INT64_C(4444444448123), true},
+ {"0x7fffffff", INT_MAX, true},
+ {"-0x80000000", INT_MIN, true},
+ {"0xffffffff", 0xffffffff, true},
+ {"0XDeadBeef", 0xdeadbeef, true},
+ {"0x7fffffffffffffff", std::numeric_limits<int64_t>::max(), true},
+ {"-0x8000000000000000", std::numeric_limits<int64_t>::min(), true},
+ {"0x8000000000000000", std::numeric_limits<int64_t>::max(),
+ false}, // Overflow test.
+ {"-0x8000000000000001", std::numeric_limits<int64_t>::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(cases); ++i) {
- int64 output = 0;
+ int64_t output = 0;
EXPECT_EQ(cases[i].success, HexStringToInt64(cases[i].input, &output));
EXPECT_EQ(cases[i].output, output);
}
@@ -593,7 +603,7 @@ TEST(StringNumberConversionsTest, HexStringToInt64) {
// interpreted as junk after the number.
const char input[] = "0xc0ffee\0" "9";
std::string input_string(input, arraysize(input) - 1);
- int64 output;
+ int64_t output;
EXPECT_FALSE(HexStringToInt64(input_string, &output));
EXPECT_EQ(0xc0ffee, output);
}
@@ -601,52 +611,53 @@ TEST(StringNumberConversionsTest, HexStringToInt64) {
TEST(StringNumberConversionsTest, HexStringToUInt64) {
static const struct {
std::string input;
- uint64 output;
+ uint64_t output;
bool success;
} cases[] = {
- {"0", 0, true},
- {"42", 66, true},
- {"-42", 0, false},
- {"+42", 66, true},
- {"40acd88557b", 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", INT64_C(4444444448123), true},
- {"0x7fffffff", INT_MAX, true},
- {"-0x80000000", 0, false},
- {"0xffffffff", 0xffffffff, true},
- {"0XDeadBeef", 0xdeadbeef, true},
- {"0x7fffffffffffffff", kint64max, true},
- {"-0x8000000000000000", 0, false},
- {"0x8000000000000000", 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},
+ {"0", 0, true},
+ {"42", 66, true},
+ {"-42", 0, false},
+ {"+42", 66, true},
+ {"40acd88557b", 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", INT64_C(4444444448123), true},
+ {"0x7fffffff", INT_MAX, true},
+ {"-0x80000000", 0, false},
+ {"0xffffffff", 0xffffffff, true},
+ {"0XDeadBeef", 0xdeadbeef, true},
+ {"0x7fffffffffffffff", std::numeric_limits<int64_t>::max(), true},
+ {"-0x8000000000000000", 0, false},
+ {"0x8000000000000000", UINT64_C(0x8000000000000000), true},
+ {"-0x8000000000000001", 0, false},
+ {"0xFFFFFFFFFFFFFFFF", std::numeric_limits<uint64_t>::max(), true},
+ {"FFFFFFFFFFFFFFFF", std::numeric_limits<uint64_t>::max(), true},
+ {"0x0000000000000000", 0, true},
+ {"0000000000000000", 0, true},
+ {"1FFFFFFFFFFFFFFFF", std::numeric_limits<uint64_t>::max(),
+ 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(cases); ++i) {
- uint64 output = 0;
+ uint64_t output = 0;
EXPECT_EQ(cases[i].success, HexStringToUInt64(cases[i].input, &output));
EXPECT_EQ(cases[i].output, output);
}
@@ -655,7 +666,7 @@ TEST(StringNumberConversionsTest, HexStringToUInt64) {
// interpreted as junk after the number.
const char input[] = "0xc0ffee\0" "9";
std::string input_string(input, arraysize(input) - 1);
- uint64 output;
+ uint64_t output;
EXPECT_FALSE(HexStringToUInt64(input_string, &output));
EXPECT_EQ(0xc0ffeeU, output);
}
@@ -688,12 +699,12 @@ TEST(StringNumberConversionsTest, HexStringToBytes) {
for (size_t i = 0; i < arraysize(cases); ++i) {
- std::vector<uint8> output;
- std::vector<uint8> compare;
+ std::vector<uint8_t> output;
+ std::vector<uint8_t> 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<uint8>(cases[i].output[j]));
+ compare.push_back(static_cast<uint8_t>(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;
diff --git a/base/strings/string_piece.cc b/base/strings/string_piece.cc
index 4c7f1122f2..c26bb3652f 100644
--- a/base/strings/string_piece.cc
+++ b/base/strings/string_piece.cc
@@ -5,9 +5,13 @@
#include "base/strings/string_piece.h"
+#include <limits.h>
+
#include <algorithm>
#include <ostream>
+#include "base/logging.h"
+
namespace base {
namespace {
@@ -433,5 +437,16 @@ StringPiece16 substr(const StringPiece16& self,
return substrT(self, pos, n);
}
+#if DCHECK_IS_ON()
+void AssertIteratorsInOrder(std::string::const_iterator begin,
+ std::string::const_iterator end) {
+ DCHECK(begin <= end) << "StringPiece iterators swapped or invalid.";
+}
+void AssertIteratorsInOrder(string16::const_iterator begin,
+ string16::const_iterator end) {
+ DCHECK(begin <= end) << "StringPiece iterators swapped or invalid.";
+}
+#endif
+
} // namespace internal
} // namespace base
diff --git a/base/strings/string_piece.h b/base/strings/string_piece.h
index a83b7d8f66..31e7596d11 100644
--- a/base/strings/string_piece.h
+++ b/base/strings/string_piece.h
@@ -28,8 +28,8 @@
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/containers/hash_tables.h"
+#include "base/logging.h"
#include "base/strings/string16.h"
namespace base {
@@ -143,6 +143,14 @@ BASE_EXPORT StringPiece16 substr(const StringPiece16& self,
size_t pos,
size_t n);
+#if DCHECK_IS_ON()
+// Asserts that begin <= end to catch some errors with iterator usage.
+BASE_EXPORT void AssertIteratorsInOrder(std::string::const_iterator begin,
+ std::string::const_iterator end);
+BASE_EXPORT void AssertIteratorsInOrder(string16::const_iterator begin,
+ string16::const_iterator end);
+#endif
+
} // namespace internal
// BasicStringPiece ------------------------------------------------------------
@@ -180,9 +188,18 @@ template <typename STRING_TYPE> class BasicStringPiece {
BasicStringPiece(const value_type* offset, size_type len)
: ptr_(offset), length_(len) {}
BasicStringPiece(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) {}
+ const typename STRING_TYPE::const_iterator& end) {
+#if DCHECK_IS_ON()
+ // This assertion is done out-of-line to avoid bringing in logging.h and
+ // instantiating logging macros for every instantiation.
+ internal::AssertIteratorsInOrder(begin, end);
+#endif
+ length_ = static_cast<size_t>(std::distance(begin, end));
+
+ // The length test before assignment is to avoid dereferencing an iterator
+ // that may point to the end() of a string.
+ ptr_ = length_ > 0 ? &*begin : nullptr;
+ }
// 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
diff --git a/base/strings/string_piece_unittest.cc b/base/strings/string_piece_unittest.cc
index 53366036d6..f05aa152b5 100644
--- a/base/strings/string_piece_unittest.cc
+++ b/base/strings/string_piece_unittest.cc
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stddef.h>
+
#include <string>
#include "base/strings/string16.h"
diff --git a/base/strings/string_split.cc b/base/strings/string_split.cc
index e23ce3fa03..6c949b989a 100644
--- a/base/strings/string_split.cc
+++ b/base/strings/string_split.cc
@@ -4,6 +4,8 @@
#include "base/strings/string_split.h"
+#include <stddef.h>
+
#include "base/logging.h"
#include "base/strings/string_util.h"
#include "base/third_party/icu/icu_utf.h"
@@ -99,52 +101,57 @@ static std::vector<OutputStringType> SplitStringT(
return result;
}
-bool SplitStringIntoKeyValue(const std::string& line,
- char key_value_delimiter,
- std::string* key,
- std::string* value) {
- key->clear();
- value->clear();
+bool AppendStringKeyValue(StringPiece input,
+ char delimiter,
+ StringPairs* result) {
+ // Always append a new item regardless of success (it might be empty). The
+ // below code will copy the strings directly into the result pair.
+ result->resize(result->size() + 1);
+ auto& result_pair = result->back();
// Find the delimiter.
- size_t end_key_pos = line.find_first_of(key_value_delimiter);
+ size_t end_key_pos = input.find_first_of(delimiter);
if (end_key_pos == std::string::npos) {
- DVLOG(1) << "cannot find delimiter in: " << line;
- return false; // no delimiter
+ DVLOG(1) << "cannot find delimiter in: " << input;
+ return false; // No delimiter.
}
- key->assign(line, 0, end_key_pos);
+ input.substr(0, end_key_pos).CopyToString(&result_pair.first);
// Find the value string.
- std::string remains(line, end_key_pos, line.size() - end_key_pos);
- size_t begin_value_pos = remains.find_first_not_of(key_value_delimiter);
- if (begin_value_pos == std::string::npos) {
- DVLOG(1) << "cannot parse value from line: " << line;
- return false; // no value
+ StringPiece remains = input.substr(end_key_pos, input.size() - end_key_pos);
+ size_t begin_value_pos = remains.find_first_not_of(delimiter);
+ if (begin_value_pos == StringPiece::npos) {
+ DVLOG(1) << "cannot parse value from input: " << input;
+ return false; // No value.
}
- value->assign(remains, begin_value_pos, remains.size() - begin_value_pos);
+ remains.substr(begin_value_pos, remains.size() - begin_value_pos)
+ .CopyToString(&result_pair.second);
+
return true;
}
-template <typename STR>
-void SplitStringUsingSubstrT(const STR& str,
- const STR& s,
- std::vector<STR>* 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();
+template <typename Str, typename OutputStringType>
+void SplitStringUsingSubstrT(BasicStringPiece<Str> input,
+ BasicStringPiece<Str> delimiter,
+ WhitespaceHandling whitespace,
+ SplitResult result_type,
+ std::vector<OutputStringType>* result) {
+ using Piece = BasicStringPiece<Str>;
+ using size_type = typename Piece::size_type;
+
+ result->clear();
+ for (size_type begin_index = 0, end_index = 0; end_index != Piece::npos;
+ begin_index = end_index + delimiter.size()) {
+ end_index = input.find(delimiter, begin_index);
+ Piece term = end_index == Piece::npos
+ ? input.substr(begin_index)
+ : input.substr(begin_index, end_index - begin_index);
+
+ if (whitespace == TRIM_WHITESPACE)
+ term = TrimString(term, WhitespaceForType<Str>(), TRIM_ALL);
+
+ if (result_type == SPLIT_WANT_ALL || !term.empty())
+ result->push_back(PieceToOutputType<Str, OutputStringType>(term));
}
}
@@ -198,111 +205,60 @@ std::vector<StringPiece16> SplitStringPiece(StringPiece16 input,
input, separators, whitespace, result_type);
}
-void SplitString(const string16& str,
- char16 c,
- std::vector<string16>* result) {
- DCHECK(CBU16_IS_SINGLE(c));
- *result = SplitStringT<string16, string16, char16>(
- str, c, TRIM_WHITESPACE, SPLIT_WANT_ALL);
-
- // Backward-compat hack: The old SplitString implementation would keep
- // empty substrings, for example:
- // "a,,b" -> ["a", "", "b"]
- // "a, ,b" -> ["a", "", "b"]
- // which the current code also does. But the old one would discard them when
- // the only result was that empty string:
- // " " -> []
- // In the latter case, our new code will give [""]
- if (result->size() == 1 && (*result)[0].empty())
- result->clear();
-}
-
-void SplitString(const std::string& str,
- char c,
- std::vector<std::string>* result) {
-#if CHAR_MIN < 0
- DCHECK_GE(c, 0);
-#endif
- DCHECK_LT(c, 0x7F);
- *result = SplitStringT<std::string, std::string, char>(
- str, c, TRIM_WHITESPACE, SPLIT_WANT_ALL);
-
- // Backward-compat hack, see above.
- if (result->size() == 1 && (*result)[0].empty())
- result->clear();
-
-}
-
-bool SplitStringIntoKeyValuePairs(const std::string& line,
+bool SplitStringIntoKeyValuePairs(StringPiece input,
char key_value_delimiter,
char key_value_pair_delimiter,
StringPairs* key_value_pairs) {
key_value_pairs->clear();
- std::vector<std::string> pairs;
- SplitString(line, key_value_pair_delimiter, &pairs);
+ std::vector<StringPiece> pairs = SplitStringPiece(
+ input, std::string(1, key_value_pair_delimiter),
+ TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
+ key_value_pairs->reserve(pairs.size());
bool success = true;
- for (size_t i = 0; i < pairs.size(); ++i) {
- // Don't add empty pairs into the result.
- if (pairs[i].empty())
- continue;
-
- std::string key;
- std::string value;
- if (!SplitStringIntoKeyValue(pairs[i], key_value_delimiter, &key, &value)) {
+ for (const StringPiece& pair : pairs) {
+ if (!AppendStringKeyValue(pair, key_value_delimiter, key_value_pairs)) {
// Don't return here, to allow for pairs without associated
// value or key; just record that the split failed.
success = false;
}
- key_value_pairs->push_back(make_pair(key, value));
}
return success;
}
-void SplitStringUsingSubstr(const string16& str,
- const string16& s,
- std::vector<string16>* r) {
- SplitStringUsingSubstrT(str, s, r);
+void SplitStringUsingSubstr(StringPiece16 input,
+ StringPiece16 delimiter,
+ std::vector<string16>* result) {
+ SplitStringUsingSubstrT(input, delimiter, TRIM_WHITESPACE, SPLIT_WANT_ALL,
+ result);
}
-void SplitStringUsingSubstr(const std::string& str,
- const std::string& s,
- std::vector<std::string>* r) {
- SplitStringUsingSubstrT(str, s, r);
+void SplitStringUsingSubstr(StringPiece input,
+ StringPiece delimiter,
+ std::vector<std::string>* result) {
+ SplitStringUsingSubstrT(input, delimiter, TRIM_WHITESPACE, SPLIT_WANT_ALL,
+ result);
}
-void SplitStringDontTrim(StringPiece16 str,
- char16 c,
- std::vector<string16>* result) {
- DCHECK(CBU16_IS_SINGLE(c));
- *result = SplitStringT<string16, string16, char16>(
- str, c, KEEP_WHITESPACE, SPLIT_WANT_ALL);
-}
-
-void SplitStringDontTrim(StringPiece str,
- char c,
- std::vector<std::string>* result) {
-#if CHAR_MIN < 0
- DCHECK_GE(c, 0);
-#endif
- DCHECK_LT(c, 0x7F);
- *result = SplitStringT<std::string, std::string, char>(
- str, c, KEEP_WHITESPACE, SPLIT_WANT_ALL);
-}
-
-void SplitStringAlongWhitespace(const string16& str,
- std::vector<string16>* result) {
- *result = SplitStringT<string16, string16, StringPiece16>(
- str, StringPiece16(kWhitespaceASCIIAs16),
- TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
+std::vector<StringPiece16> SplitStringPieceUsingSubstr(
+ StringPiece16 input,
+ StringPiece16 delimiter,
+ WhitespaceHandling whitespace,
+ SplitResult result_type) {
+ std::vector<StringPiece16> result;
+ SplitStringUsingSubstrT(input, delimiter, whitespace, result_type, &result);
+ return result;
}
-void SplitStringAlongWhitespace(const std::string& str,
- std::vector<std::string>* result) {
- *result = SplitStringT<std::string, std::string, StringPiece>(
- str, StringPiece(kWhitespaceASCII),
- TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
+std::vector<StringPiece> SplitStringPieceUsingSubstr(
+ StringPiece input,
+ StringPiece delimiter,
+ WhitespaceHandling whitespace,
+ SplitResult result_type) {
+ std::vector<StringPiece> result;
+ SplitStringUsingSubstrT(input, delimiter, whitespace, result_type, &result);
+ return result;
}
} // namespace base
diff --git a/base/strings/string_split.h b/base/strings/string_split.h
index dc4108d327..ec9f24604a 100644
--- a/base/strings/string_split.h
+++ b/base/strings/string_split.h
@@ -83,7 +83,7 @@ using StringPairs = std::vector<std::pair<std::string, std::string>>;
// removes whitespace leading each key and trailing each value. Returns true
// only if each pair has a non-empty key and value. |key_value_pairs| will
// include ("","") pairs for entries without |key_value_delimiter|.
-BASE_EXPORT bool SplitStringIntoKeyValuePairs(const std::string& line,
+BASE_EXPORT bool SplitStringIntoKeyValuePairs(StringPiece input,
char key_value_delimiter,
char key_value_pair_delimiter,
StringPairs* key_value_pairs);
@@ -94,64 +94,35 @@ BASE_EXPORT bool SplitStringIntoKeyValuePairs(const std::string& line,
// TODO(brettw) this should probably be changed and expanded to provide a
// mirror of the SplitString[Piece] API above, just with the different
// delimiter handling.
-BASE_EXPORT void SplitStringUsingSubstr(const string16& str,
- const string16& s,
- std::vector<string16>* r);
-BASE_EXPORT void SplitStringUsingSubstr(const std::string& str,
- const std::string& s,
- std::vector<std::string>* r);
-
-// -----------------------------------------------------------------------------
-// Backwards-compat wrappers
-//
-// New code should use one of the more general variants above.
-// TODO(brettw) remove these and convert to the versions above.
-
-// Splits |str| into a vector of strings delimited by |c|, placing the results
-// in |r|. If several instances of |c| are contiguous, or if |str| begins with
-// or ends with |c|, 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<string16>* 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<std::string>* r);
-
-// The same as SplitString, but don't trim white space.
-// NOTE: |c| must be in BMP (Basic Multilingual Plane)
-BASE_EXPORT void SplitStringDontTrim(StringPiece16 str,
- char16 c,
- std::vector<string16>* 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(StringPiece str,
- char c,
- std::vector<std::string>* result);
-
-// WARNING: this uses whitespace as defined by the HTML5 spec (ASCII whitespace
-// only).
+BASE_EXPORT void SplitStringUsingSubstr(StringPiece16 input,
+ StringPiece16 delimiter,
+ std::vector<string16>* result);
+BASE_EXPORT void SplitStringUsingSubstr(StringPiece input,
+ StringPiece delimiter,
+ std::vector<std::string>* result);
+
+// Like SplitStringUsingSubstr above except it returns a vector of StringPieces
+// which reference the original buffer without copying. Although you have to be
+// careful to keep the original string unmodified, this provides an efficient
+// way to iterate through tokens in a string.
//
-// The difference between this and calling SplitString with the whitespace
-// characters as separators is the treatment of the first element when the
-// string starts with whitespace.
+// To iterate through all newline-separated tokens in an input string:
//
-// Input SplitString SplitStringAlongWhitespace
-// --------------------------------------------------------
-// " a " "", "a" "a"
-BASE_EXPORT void SplitStringAlongWhitespace(const string16& str,
- std::vector<string16>* result);
-BASE_EXPORT void SplitStringAlongWhitespace(const std::string& str,
- std::vector<std::string>* result);
+// for (const auto& cur :
+// base::SplitStringUsingSubstr(input, "\r\n",
+// base::KEEP_WHITESPACE,
+// base::SPLIT_WANT_NONEMPTY)) {
+// ...
+BASE_EXPORT std::vector<StringPiece16> SplitStringPieceUsingSubstr(
+ StringPiece16 input,
+ StringPiece16 delimiter,
+ WhitespaceHandling whitespace,
+ SplitResult result_type);
+BASE_EXPORT std::vector<StringPiece> SplitStringPieceUsingSubstr(
+ StringPiece input,
+ StringPiece delimiter,
+ WhitespaceHandling whitespace,
+ SplitResult result_type);
} // namespace base
diff --git a/base/strings/string_split_unittest.cc b/base/strings/string_split_unittest.cc
index c745ab58f0..657a2db7b5 100644
--- a/base/strings/string_split_unittest.cc
+++ b/base/strings/string_split_unittest.cc
@@ -4,6 +4,10 @@
#include "base/strings/string_split.h"
+#include <stddef.h>
+
+#include "base/macros.h"
+#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -12,23 +16,6 @@ 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<std::wstring>* result) {
- std::vector<string16> 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 SplitStringIntoKeyValuePairsTest : public testing::Test {
protected:
base::StringPairs kv_pairs;
@@ -243,77 +230,6 @@ TEST(StringUtilTest, SplitString_WhitespaceAndResultType) {
ASSERT_TRUE(r.empty());
}
-TEST(StringUtilTest, SplitString_Legacy) {
- std::vector<std::wstring> 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"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<std::string> results;
SplitStringUsingSubstr("alongwordwithnodelimiter", "DELIMITER", &results);
@@ -352,21 +268,88 @@ TEST(SplitStringUsingSubstrTest, TrailingDelimitersSkipped) {
results, ElementsAre("un", "deux", "trois", "quatre", "", "", ""));
}
-TEST(StringSplitTest, StringSplitDontTrim) {
+TEST(SplitStringPieceUsingSubstrTest, StringWithNoDelimiter) {
+ std::vector<base::StringPiece> results =
+ SplitStringPieceUsingSubstr("alongwordwithnodelimiter", "DELIMITER",
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+ ASSERT_EQ(1u, results.size());
+ EXPECT_THAT(results, ElementsAre("alongwordwithnodelimiter"));
+}
+
+TEST(SplitStringPieceUsingSubstrTest, LeadingDelimitersSkipped) {
+ std::vector<base::StringPiece> results = SplitStringPieceUsingSubstr(
+ "DELIMITERDELIMITERDELIMITERoneDELIMITERtwoDELIMITERthree", "DELIMITER",
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+ ASSERT_EQ(6u, results.size());
+ EXPECT_THAT(results, ElementsAre("", "", "", "one", "two", "three"));
+}
+
+TEST(SplitStringPieceUsingSubstrTest, ConsecutiveDelimitersSkipped) {
+ std::vector<base::StringPiece> results = SplitStringPieceUsingSubstr(
+ "unoDELIMITERDELIMITERDELIMITERdosDELIMITERtresDELIMITERDELIMITERcuatro",
+ "DELIMITER", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+ ASSERT_EQ(7u, results.size());
+ EXPECT_THAT(results, ElementsAre("uno", "", "", "dos", "tres", "", "cuatro"));
+}
+
+TEST(SplitStringPieceUsingSubstrTest, TrailingDelimitersSkipped) {
+ std::vector<base::StringPiece> results = SplitStringPieceUsingSubstr(
+ "unDELIMITERdeuxDELIMITERtroisDELIMITERquatreDELIMITERDELIMITERDELIMITER",
+ "DELIMITER", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+ ASSERT_EQ(7u, results.size());
+ EXPECT_THAT(results,
+ ElementsAre("un", "deux", "trois", "quatre", "", "", ""));
+}
+
+TEST(SplitStringPieceUsingSubstrTest, KeepWhitespace) {
+ std::vector<base::StringPiece> results = SplitStringPieceUsingSubstr(
+ "un DELIMITERdeux\tDELIMITERtrois\nDELIMITERquatre", "DELIMITER",
+ base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
+ ASSERT_EQ(4u, results.size());
+ EXPECT_THAT(results, ElementsAre("un ", "deux\t", "trois\n", "quatre"));
+}
+
+TEST(SplitStringPieceUsingSubstrTest, TrimWhitespace) {
+ std::vector<base::StringPiece> results = SplitStringPieceUsingSubstr(
+ "un DELIMITERdeux\tDELIMITERtrois\nDELIMITERquatre", "DELIMITER",
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+ ASSERT_EQ(4u, results.size());
+ EXPECT_THAT(results, ElementsAre("un", "deux", "trois", "quatre"));
+}
+
+TEST(SplitStringPieceUsingSubstrTest, SplitWantAll) {
+ std::vector<base::StringPiece> results = SplitStringPieceUsingSubstr(
+ "unDELIMITERdeuxDELIMITERtroisDELIMITERDELIMITER", "DELIMITER",
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+ ASSERT_EQ(5u, results.size());
+ EXPECT_THAT(results, ElementsAre("un", "deux", "trois", "", ""));
+}
+
+TEST(SplitStringPieceUsingSubstrTest, SplitWantNonEmpty) {
+ std::vector<base::StringPiece> results = SplitStringPieceUsingSubstr(
+ "unDELIMITERdeuxDELIMITERtroisDELIMITERDELIMITER", "DELIMITER",
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+ ASSERT_EQ(3u, results.size());
+ EXPECT_THAT(results, ElementsAre("un", "deux", "trois"));
+}
+
+TEST(StringSplitTest, StringSplitKeepWhitespace) {
std::vector<std::string> r;
- SplitStringDontTrim(" ", '*', &r);
+ r = SplitString(" ", "*", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
ASSERT_EQ(1U, r.size());
EXPECT_EQ(r[0], " ");
- SplitStringDontTrim("\t \ta\t ", '\t', &r);
+ r = SplitString("\t \ta\t ", "\t", base::KEEP_WHITESPACE,
+ base::SPLIT_WANT_ALL);
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);
+ r = SplitString("\ta\t\nb\tcc", "\n", base::KEEP_WHITESPACE,
+ base::SPLIT_WANT_ALL);
ASSERT_EQ(2U, r.size());
EXPECT_EQ(r[0], "\ta\t");
EXPECT_EQ(r[1], "b\tcc");
@@ -394,8 +377,9 @@ TEST(StringSplitTest, SplitStringAlongWhitespace) {
{ "b\t at", 2, "b", "at" },
};
for (size_t i = 0; i < arraysize(data); ++i) {
- std::vector<std::string> results;
- SplitStringAlongWhitespace(data[i].input, &results);
+ std::vector<std::string> results = base::SplitString(
+ data[i].input, kWhitespaceASCII, base::KEEP_WHITESPACE,
+ base::SPLIT_WANT_NONEMPTY);
ASSERT_EQ(data[i].expected_result_count, results.size());
if (data[i].expected_result_count > 0)
ASSERT_EQ(data[i].output1, results[0]);
diff --git a/base/strings/string_util.cc b/base/strings/string_util.cc
index 738d32e045..e8000abd40 100644
--- a/base/strings/string_util.cc
+++ b/base/strings/string_util.cc
@@ -8,6 +8,7 @@
#include <errno.h>
#include <math.h>
#include <stdarg.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -16,10 +17,11 @@
#include <wctype.h>
#include <algorithm>
+#include <limits>
#include <vector>
-#include "base/basictypes.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/singleton.h"
#include "base/strings/string_split.h"
#include "base/strings/utf_string_conversion_utils.h"
@@ -27,9 +29,7 @@
#include "base/third_party/icu/icu_utf.h"
#include "build/build_config.h"
-// Remove when this entire file is in the base namespace.
-using base::char16;
-using base::string16;
+namespace base {
namespace {
@@ -80,13 +80,13 @@ template<typename T> inline T* AlignToMachineWord(T* pointer) {
}
template<size_t size, typename CharacterType> struct NonASCIIMask;
-template<> struct NonASCIIMask<4, base::char16> {
+template<> struct NonASCIIMask<4, char16> {
static inline uint32_t value() { return 0xFF80FF80U; }
};
template<> struct NonASCIIMask<4, char> {
static inline uint32_t value() { return 0x80808080U; }
};
-template<> struct NonASCIIMask<8, base::char16> {
+template<> struct NonASCIIMask<8, char16> {
static inline uint64_t value() { return 0xFF80FF80FF80FF80ULL; }
};
template<> struct NonASCIIMask<8, char> {
@@ -103,8 +103,6 @@ template<> struct NonASCIIMask<8, wchar_t> {
} // namespace
-namespace base {
-
bool IsWprintfFormatPortable(const wchar_t* format) {
for (const wchar_t* position = format; *position != '\0'; ++position) {
if (*position == '%') {
@@ -140,6 +138,91 @@ bool IsWprintfFormatPortable(const wchar_t* format) {
return true;
}
+namespace {
+
+template<typename StringType>
+StringType ToLowerASCIIImpl(BasicStringPiece<StringType> str) {
+ StringType ret;
+ ret.reserve(str.size());
+ for (size_t i = 0; i < str.size(); i++)
+ ret.push_back(ToLowerASCII(str[i]));
+ return ret;
+}
+
+template<typename StringType>
+StringType ToUpperASCIIImpl(BasicStringPiece<StringType> str) {
+ StringType ret;
+ ret.reserve(str.size());
+ for (size_t i = 0; i < str.size(); i++)
+ ret.push_back(ToUpperASCII(str[i]));
+ return ret;
+}
+
+} // namespace
+
+std::string ToLowerASCII(StringPiece str) {
+ return ToLowerASCIIImpl<std::string>(str);
+}
+
+string16 ToLowerASCII(StringPiece16 str) {
+ return ToLowerASCIIImpl<string16>(str);
+}
+
+std::string ToUpperASCII(StringPiece str) {
+ return ToUpperASCIIImpl<std::string>(str);
+}
+
+string16 ToUpperASCII(StringPiece16 str) {
+ return ToUpperASCIIImpl<string16>(str);
+}
+
+template<class StringType>
+int CompareCaseInsensitiveASCIIT(BasicStringPiece<StringType> a,
+ BasicStringPiece<StringType> b) {
+ // Find the first characters that aren't equal and compare them. If the end
+ // of one of the strings is found before a nonequal character, the lengths
+ // of the strings are compared.
+ size_t i = 0;
+ while (i < a.length() && i < b.length()) {
+ typename StringType::value_type lower_a = ToLowerASCII(a[i]);
+ typename StringType::value_type lower_b = ToLowerASCII(b[i]);
+ if (lower_a < lower_b)
+ return -1;
+ if (lower_a > lower_b)
+ return 1;
+ i++;
+ }
+
+ // End of one string hit before finding a different character. Expect the
+ // common case to be "strings equal" at this point so check that first.
+ if (a.length() == b.length())
+ return 0;
+
+ if (a.length() < b.length())
+ return -1;
+ return 1;
+}
+
+int CompareCaseInsensitiveASCII(StringPiece a, StringPiece b) {
+ return CompareCaseInsensitiveASCIIT<std::string>(a, b);
+}
+
+int CompareCaseInsensitiveASCII(StringPiece16 a, StringPiece16 b) {
+ return CompareCaseInsensitiveASCIIT<string16>(a, b);
+}
+
+bool EqualsCaseInsensitiveASCII(StringPiece a, StringPiece b) {
+ if (a.length() != b.length())
+ return false;
+ return CompareCaseInsensitiveASCIIT<std::string>(a, b) == 0;
+}
+
+bool EqualsCaseInsensitiveASCII(StringPiece16 a, StringPiece16 b) {
+ if (a.length() != b.length())
+ return false;
+ return CompareCaseInsensitiveASCIIT<string16>(a, b) == 0;
+}
+
const std::string& EmptyString() {
return EmptyStrings::GetInstance()->s;
}
@@ -169,27 +252,27 @@ bool ReplaceCharsT(const STR& input,
}
bool ReplaceChars(const string16& input,
- const base::StringPiece16& replace_chars,
+ const StringPiece16& replace_chars,
const string16& replace_with,
string16* output) {
return ReplaceCharsT(input, replace_chars.as_string(), replace_with, output);
}
bool ReplaceChars(const std::string& input,
- const base::StringPiece& replace_chars,
+ const StringPiece& replace_chars,
const std::string& replace_with,
std::string* output) {
return ReplaceCharsT(input, replace_chars.as_string(), replace_with, output);
}
bool RemoveChars(const string16& input,
- const base::StringPiece16& remove_chars,
+ const StringPiece16& remove_chars,
string16* output) {
return ReplaceChars(input, remove_chars.as_string(), string16(), output);
}
bool RemoveChars(const std::string& input,
- const base::StringPiece& remove_chars,
+ const StringPiece& remove_chars,
std::string* output) {
return ReplaceChars(input, remove_chars.as_string(), std::string(), output);
}
@@ -231,13 +314,13 @@ TrimPositions TrimStringT(const Str& input,
}
bool TrimString(const string16& input,
- base::StringPiece16 trim_chars,
+ StringPiece16 trim_chars,
string16* output) {
return TrimStringT(input, trim_chars, TRIM_ALL, output) != TRIM_NONE;
}
bool TrimString(const std::string& input,
- base::StringPiece trim_chars,
+ StringPiece trim_chars,
std::string* output) {
return TrimStringT(input, trim_chars, TRIM_ALL, output) != TRIM_NONE;
}
@@ -254,13 +337,13 @@ BasicStringPiece<Str> TrimStringPieceT(BasicStringPiece<Str> input,
}
StringPiece16 TrimString(StringPiece16 input,
- const base::StringPiece16& trim_chars,
+ const StringPiece16& trim_chars,
TrimPositions positions) {
return TrimStringPieceT(input, trim_chars, positions);
}
StringPiece TrimString(StringPiece input,
- const base::StringPiece& trim_chars,
+ const StringPiece& trim_chars,
TrimPositions positions) {
return TrimStringPieceT(input, trim_chars, positions);
}
@@ -273,10 +356,11 @@ void TruncateUTF8ToByteSize(const std::string& input,
*output = input;
return;
}
- DCHECK_LE(byte_size, static_cast<uint32>(kint32max));
- // Note: This cast is necessary because CBU8_NEXT uses int32s.
- int32 truncation_length = static_cast<int32>(byte_size);
- int32 char_index = truncation_length - 1;
+ DCHECK_LE(byte_size,
+ static_cast<uint32_t>(std::numeric_limits<int32_t>::max()));
+ // Note: This cast is necessary because CBU8_NEXT uses int32_ts.
+ int32_t truncation_length = static_cast<int32_t>(byte_size);
+ int32_t char_index = truncation_length - 1;
const char* data = input.data();
// Using CBU8, we will move backwards from the truncation point
@@ -284,7 +368,7 @@ void TruncateUTF8ToByteSize(const std::string& input,
// 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;
+ int32_t prev = char_index;
base_icu::UChar32 code_point = 0;
CBU8_NEXT(data, char_index, truncation_length, code_point);
if (!IsValidCharacter(code_point) ||
@@ -307,18 +391,19 @@ TrimPositions TrimWhitespace(const string16& input,
return TrimStringT(input, StringPiece16(kWhitespaceUTF16), positions, output);
}
+StringPiece16 TrimWhitespace(StringPiece16 input,
+ TrimPositions positions) {
+ return TrimStringPieceT(input, StringPiece16(kWhitespaceUTF16), positions);
+}
+
TrimPositions TrimWhitespaceASCII(const std::string& input,
TrimPositions positions,
std::string* output) {
return TrimStringT(input, StringPiece(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);
+StringPiece TrimWhitespaceASCII(StringPiece input, TrimPositions positions) {
+ return TrimStringPieceT(input, StringPiece(kWhitespaceASCII), positions);
}
template<typename STR>
@@ -334,7 +419,7 @@ STR CollapseWhitespaceT(const STR& text,
int chars_written = 0;
for (typename STR::const_iterator i(text.begin()); i != text.end(); ++i) {
- if (IsWhitespace(*i)) {
+ if (IsUnicodeWhitespace(*i)) {
if (!in_whitespace) {
// Reduce all whitespace sequences to a single space.
in_whitespace = true;
@@ -433,11 +518,11 @@ bool IsStringASCII(const std::wstring& str) {
bool IsStringUTF8(const StringPiece& str) {
const char *src = str.data();
- int32 src_len = static_cast<int32>(str.length());
- int32 char_index = 0;
+ int32_t src_len = static_cast<int32_t>(str.length());
+ int32_t char_index = 0;
while (char_index < src_len) {
- int32 code_point;
+ int32_t code_point;
CBU8_NEXT(src, char_index, src_len, code_point);
if (!IsValidCharacter(code_point))
return false;
@@ -445,113 +530,141 @@ bool IsStringUTF8(const StringPiece& str) {
return true;
}
-template<typename Iter>
-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 || ToLowerASCII(*it) != *b)
+// Implementation note: Normally this function will be called with a hardcoded
+// constant for the lowercase_ascii parameter. Constructing a StringPiece from
+// a C constant requires running strlen, so the result will be two passes
+// through the buffers, one to file the length of lowercase_ascii, and one to
+// compare each letter.
+//
+// This function could have taken a const char* to avoid this and only do one
+// pass through the string. But the strlen is faster than the case-insensitive
+// compares and lets us early-exit in the case that the strings are different
+// lengths (will often be the case for non-matches). So whether one approach or
+// the other will be faster depends on the case.
+//
+// The hardcoded strings are typically very short so it doesn't matter, and the
+// string piece gives additional flexibility for the caller (doesn't have to be
+// null terminated) so we choose the StringPiece route.
+template<typename Str>
+static inline bool DoLowerCaseEqualsASCII(BasicStringPiece<Str> str,
+ StringPiece lowercase_ascii) {
+ if (str.size() != lowercase_ascii.size())
+ return false;
+ for (size_t i = 0; i < str.size(); i++) {
+ if (ToLowerASCII(str[i]) != lowercase_ascii[i])
return false;
}
- return *b == 0;
+ return true;
}
-// Front-ends for LowerCaseEqualsASCII.
-bool LowerCaseEqualsASCII(const std::string& a, const char* b) {
- return DoLowerCaseEqualsASCII(a.begin(), a.end(), b);
+bool LowerCaseEqualsASCII(StringPiece str, StringPiece lowercase_ascii) {
+ return DoLowerCaseEqualsASCII<std::string>(str, lowercase_ascii);
}
-bool LowerCaseEqualsASCII(const string16& a, const char* b) {
- return DoLowerCaseEqualsASCII(a.begin(), a.end(), b);
+bool LowerCaseEqualsASCII(StringPiece16 str, StringPiece lowercase_ascii) {
+ return DoLowerCaseEqualsASCII<string16>(str, lowercase_ascii);
}
-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 EqualsASCII(StringPiece16 str, StringPiece ascii) {
+ if (str.length() != ascii.length())
+ return false;
+ return std::equal(ascii.begin(), ascii.end(), str.begin());
}
-bool LowerCaseEqualsASCII(string16::const_iterator a_begin,
- string16::const_iterator a_end,
- const char* b) {
- return DoLowerCaseEqualsASCII(a_begin, a_end, b);
-}
+template<typename Str>
+bool StartsWithT(BasicStringPiece<Str> str,
+ BasicStringPiece<Str> search_for,
+ CompareCase case_sensitivity) {
+ if (search_for.size() > str.size())
+ return false;
-bool LowerCaseEqualsASCII(const char* a_begin,
- const char* a_end,
- const char* b) {
- return DoLowerCaseEqualsASCII(a_begin, a_end, b);
-}
+ BasicStringPiece<Str> source = str.substr(0, search_for.size());
+
+ switch (case_sensitivity) {
+ case CompareCase::SENSITIVE:
+ return source == search_for;
-bool LowerCaseEqualsASCII(const char* a_begin,
- const char* a_end,
- const char* b_begin,
- const char* b_end) {
- while (a_begin != a_end && b_begin != b_end &&
- ToLowerASCII(*a_begin) == *b_begin) {
- a_begin++;
- b_begin++;
+ case CompareCase::INSENSITIVE_ASCII:
+ return std::equal(
+ search_for.begin(), search_for.end(),
+ source.begin(),
+ CaseInsensitiveCompareASCII<typename Str::value_type>());
+
+ default:
+ NOTREACHED();
+ return false;
}
- return a_begin == a_end && b_begin == b_end;
}
-bool LowerCaseEqualsASCII(const char16* a_begin,
- const char16* a_end,
- const char* b) {
- return DoLowerCaseEqualsASCII(a_begin, a_end, b);
+bool StartsWith(StringPiece str,
+ StringPiece search_for,
+ CompareCase case_sensitivity) {
+ return StartsWithT<std::string>(str, search_for, case_sensitivity);
}
-bool EqualsASCII(const string16& a, const StringPiece& b) {
- if (a.length() != b.length())
- return false;
- return std::equal(b.begin(), b.end(), a.begin());
+bool StartsWith(StringPiece16 str,
+ StringPiece16 search_for,
+ CompareCase case_sensitivity) {
+ return StartsWithT<string16>(str, search_for, case_sensitivity);
}
-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 <typename Str>
+bool EndsWithT(BasicStringPiece<Str> str,
+ BasicStringPiece<Str> search_for,
+ CompareCase case_sensitivity) {
+ if (search_for.size() > str.size())
+ return false;
+
+ BasicStringPiece<Str> source = str.substr(str.size() - search_for.size(),
+ search_for.size());
+
+ switch (case_sensitivity) {
+ case CompareCase::SENSITIVE:
+ return source == search_for;
+
+ case CompareCase::INSENSITIVE_ASCII:
+ return std::equal(
+ source.begin(), source.end(),
+ search_for.begin(),
+ CaseInsensitiveCompareASCII<typename Str::value_type>());
-bool StartsWith(const string16& str,
- const string16& search,
- bool case_sensitive) {
- if (case_sensitive) {
- return str.compare(0, search.length(), search) == 0;
+ default:
+ NOTREACHED();
+ return false;
}
- if (search.size() > str.size())
- return false;
- return std::equal(search.begin(), search.end(), str.begin(),
- CaseInsensitiveCompare<char16>());
}
-template <typename STR>
-bool EndsWithT(const STR& str, const STR& search, bool case_sensitive) {
- size_t str_length = str.length();
- size_t 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;
- return std::equal(search.begin(), search.end(),
- str.begin() + (str_length - search_length),
- base::CaseInsensitiveCompare<typename STR::value_type>());
+bool EndsWith(StringPiece str,
+ StringPiece search_for,
+ CompareCase case_sensitivity) {
+ return EndsWithT<std::string>(str, search_for, case_sensitivity);
}
-bool EndsWith(const std::string& str, const std::string& search,
- bool case_sensitive) {
- return EndsWithT(str, search, case_sensitive);
+bool EndsWith(StringPiece16 str,
+ StringPiece16 search_for,
+ CompareCase case_sensitivity) {
+ return EndsWithT<string16>(str, search_for, case_sensitivity);
}
-bool EndsWith(const string16& str, const string16& search,
- bool case_sensitive) {
- return EndsWithT(str, search, case_sensitive);
+char HexDigitToInt(wchar_t c) {
+ DCHECK(IsHexDigit(c));
+ if (c >= '0' && c <= '9')
+ return static_cast<char>(c - '0');
+ if (c >= 'A' && c <= 'F')
+ return static_cast<char>(c - 'A' + 10);
+ if (c >= 'a' && c <= 'f')
+ return static_cast<char>(c - 'a' + 10);
+ return 0;
}
-} // namespace base
+bool IsUnicodeWhitespace(wchar_t c) {
+ // kWhitespaceWide is a NULL-terminated string
+ for (const wchar_t* cur = kWhitespaceWide; *cur; ++cur) {
+ if (*cur == c)
+ return true;
+ }
+ return false;
+}
static const char* const kByteStringsUnlocalized[] = {
" B",
@@ -562,7 +675,7 @@ static const char* const kByteStringsUnlocalized[] = {
" PB"
};
-string16 FormatBytesUnlocalized(int64 bytes) {
+string16 FormatBytesUnlocalized(int64_t bytes) {
double unit_amount = static_cast<double>(bytes);
size_t dimension = 0;
const int kKilo = 1024;
@@ -581,20 +694,20 @@ string16 FormatBytesUnlocalized(int64 bytes) {
kByteStringsUnlocalized[dimension]);
}
- return base::ASCIIToUTF16(buf);
+ return ASCIIToUTF16(buf);
}
// Runs in O(n) time in the length of |str|.
template<class StringType>
void DoReplaceSubstringsAfterOffset(StringType* str,
size_t offset,
- const StringType& find_this,
- const StringType& replace_with,
+ BasicStringPiece<StringType> find_this,
+ BasicStringPiece<StringType> replace_with,
bool replace_all) {
DCHECK(!find_this.empty());
// If the find string doesn't appear, there's nothing to do.
- offset = str->find(find_this, offset);
+ offset = str->find(find_this.data(), offset, find_this.size());
if (offset == StringType::npos)
return;
@@ -602,7 +715,7 @@ void DoReplaceSubstringsAfterOffset(StringType* str,
// complicated.
size_t find_length = find_this.length();
if (!replace_all) {
- str->replace(offset, find_length, replace_with);
+ str->replace(offset, find_length, replace_with.data(), replace_with.size());
return;
}
@@ -611,8 +724,10 @@ void DoReplaceSubstringsAfterOffset(StringType* str,
size_t replace_length = replace_with.length();
if (find_length == replace_length) {
do {
- str->replace(offset, find_length, replace_with);
- offset = str->find(find_this, offset + replace_length);
+ str->replace(offset, find_length,
+ replace_with.data(), replace_with.size());
+ offset = str->find(find_this.data(), offset + replace_length,
+ find_this.size());
} while (offset != StringType::npos);
return;
}
@@ -629,11 +744,14 @@ void DoReplaceSubstringsAfterOffset(StringType* str,
size_t write_offset = offset;
do {
if (replace_length) {
- str->replace(write_offset, replace_length, replace_with);
+ str->replace(write_offset, replace_length,
+ replace_with.data(), replace_with.size());
write_offset += replace_length;
}
size_t read_offset = offset + find_length;
- offset = std::min(str->find(find_this, read_offset), str_length);
+ offset = std::min(
+ str->find(find_this.data(), read_offset, find_this.size()),
+ str_length);
size_t length = offset - read_offset;
if (length) {
memmove(&(*str)[write_offset], &(*str)[read_offset],
@@ -662,13 +780,15 @@ void DoReplaceSubstringsAfterOffset(StringType* str,
// exit from the loop, |current_match| will point at the last instance of
// the find string, and we won't need to find() it again immediately.
current_match = offset;
- offset = str->find(find_this, offset + find_length);
+ offset = str->find(find_this.data(), offset + find_length,
+ find_this.size());
} while (offset != StringType::npos);
str->resize(final_length);
// Now do the replacement loop, working backwards through the string.
for (size_t prev_match = str_length, write_offset = final_length; ;
- current_match = str->rfind(find_this, current_match - 1)) {
+ current_match = str->rfind(find_this.data(), current_match - 1,
+ find_this.size())) {
size_t read_offset = current_match + find_length;
size_t length = prev_match - read_offset;
if (length) {
@@ -677,7 +797,8 @@ void DoReplaceSubstringsAfterOffset(StringType* str,
length * sizeof(typename StringType::value_type));
}
write_offset -= replace_length;
- str->replace(write_offset, replace_length, replace_with);
+ str->replace(write_offset, replace_length,
+ replace_with.data(), replace_with.size());
if (current_match == first_match)
return;
prev_match = current_match;
@@ -686,112 +807,97 @@ void DoReplaceSubstringsAfterOffset(StringType* str,
void ReplaceFirstSubstringAfterOffset(string16* str,
size_t start_offset,
- const string16& find_this,
- const string16& replace_with) {
- DoReplaceSubstringsAfterOffset(str, start_offset, find_this, replace_with,
- false); // replace first instance
+ StringPiece16 find_this,
+ StringPiece16 replace_with) {
+ DoReplaceSubstringsAfterOffset<string16>(
+ str, start_offset, find_this, replace_with, false); // Replace first.
}
void ReplaceFirstSubstringAfterOffset(std::string* str,
size_t start_offset,
- const std::string& find_this,
- const std::string& replace_with) {
- DoReplaceSubstringsAfterOffset(str, start_offset, find_this, replace_with,
- false); // replace first instance
+ StringPiece find_this,
+ StringPiece replace_with) {
+ DoReplaceSubstringsAfterOffset<std::string>(
+ str, start_offset, find_this, replace_with, false); // Replace first.
}
void ReplaceSubstringsAfterOffset(string16* str,
size_t start_offset,
- const string16& find_this,
- const string16& replace_with) {
- DoReplaceSubstringsAfterOffset(str, start_offset, find_this, replace_with,
- true); // replace all instances
+ StringPiece16 find_this,
+ StringPiece16 replace_with) {
+ DoReplaceSubstringsAfterOffset<string16>(
+ str, start_offset, find_this, replace_with, true); // Replace all.
}
void ReplaceSubstringsAfterOffset(std::string* str,
size_t start_offset,
- const std::string& find_this,
- const std::string& replace_with) {
- DoReplaceSubstringsAfterOffset(str, start_offset, find_this, replace_with,
- true); // replace all instances
+ StringPiece find_this,
+ StringPiece replace_with) {
+ DoReplaceSubstringsAfterOffset<std::string>(
+ str, start_offset, find_this, replace_with, true); // Replace all.
}
-size_t Tokenize(const base::string16& str,
- const base::string16& delimiters,
- std::vector<base::string16>* tokens) {
- *tokens = base::SplitString(
- str, delimiters, base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
- return tokens->size();
+template <class string_type>
+inline typename string_type::value_type* WriteIntoT(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]);
}
-size_t Tokenize(const std::string& str,
- const std::string& delimiters,
- std::vector<std::string>* tokens) {
- *tokens = base::SplitString(
- str, delimiters, base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
- return tokens->size();
+char* WriteInto(std::string* str, size_t length_with_null) {
+ return WriteIntoT(str, length_with_null);
}
-size_t Tokenize(const base::StringPiece& str,
- const base::StringPiece& delimiters,
- std::vector<base::StringPiece>* tokens) {
- *tokens = base::SplitStringPiece(
- str, delimiters, base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
- return tokens->size();
+char16* WriteInto(string16* str, size_t length_with_null) {
+ return WriteIntoT(str, length_with_null);
}
template<typename STR>
-static STR JoinStringT(const std::vector<STR>& parts, const STR& sep) {
+static STR JoinStringT(const std::vector<STR>& parts,
+ BasicStringPiece<STR> sep) {
if (parts.empty())
return STR();
STR result(parts[0]);
- typename std::vector<STR>::const_iterator iter = parts.begin();
+ auto iter = parts.begin();
++iter;
for (; iter != parts.end(); ++iter) {
- result += sep;
+ sep.AppendToString(&result);
result += *iter;
}
return result;
}
-std::string JoinString(const std::vector<std::string>& parts, char sep) {
- return JoinStringT(parts, std::string(1, sep));
-}
-
-string16 JoinString(const std::vector<string16>& parts, char16 sep) {
- return JoinStringT(parts, string16(1, sep));
-}
-
std::string JoinString(const std::vector<std::string>& parts,
- const std::string& separator) {
+ StringPiece separator) {
return JoinStringT(parts, separator);
}
string16 JoinString(const std::vector<string16>& parts,
- const string16& separator) {
+ StringPiece16 separator) {
return JoinStringT(parts, separator);
}
template<class FormatStringType, class OutStringType>
-OutStringType DoReplaceStringPlaceholders(const FormatStringType& format_string,
- const std::vector<OutStringType>& subst, std::vector<size_t>* offsets) {
+OutStringType DoReplaceStringPlaceholders(
+ const FormatStringType& format_string,
+ const std::vector<OutStringType>& subst,
+ std::vector<size_t>* offsets) {
size_t substitutions = subst.size();
size_t sub_length = 0;
- for (typename std::vector<OutStringType>::const_iterator iter = subst.begin();
- iter != subst.end(); ++iter) {
- sub_length += iter->length();
- }
+ for (const auto& cur : subst)
+ sub_length += cur.length();
OutStringType formatted;
formatted.reserve(format_string.length() + sub_length);
std::vector<ReplacementOffset> r_offsets;
- for (typename FormatStringType::const_iterator i = format_string.begin();
- i != format_string.end(); ++i) {
+ for (auto i = format_string.begin(); i != format_string.end(); ++i) {
if ('$' == *i) {
if (i + 1 != format_string.end()) {
++i;
@@ -829,10 +935,8 @@ OutStringType DoReplaceStringPlaceholders(const FormatStringType& format_string,
}
}
if (offsets) {
- for (std::vector<ReplacementOffset>::const_iterator i = r_offsets.begin();
- i != r_offsets.end(); ++i) {
- offsets->push_back(i->offset);
- }
+ for (const auto& cur : r_offsets)
+ offsets->push_back(cur.offset);
}
return formatted;
}
@@ -843,7 +947,7 @@ string16 ReplaceStringPlaceholders(const string16& format_string,
return DoReplaceStringPlaceholders(format_string, subst, offsets);
}
-std::string ReplaceStringPlaceholders(const base::StringPiece& format_string,
+std::string ReplaceStringPlaceholders(const StringPiece& format_string,
const std::vector<std::string>& subst,
std::vector<size_t>* offsets) {
return DoReplaceStringPlaceholders(format_string, subst, offsets);
@@ -863,161 +967,6 @@ string16 ReplaceStringPlaceholders(const string16& format_string,
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 <typename CHAR, typename NEXT>
-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 != CBU_SENTINEL) {
- *pattern = pattern_next;
- *string = string_next;
- } else {
- // Uh oh, 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 <typename CHAR, typename NEXT>
-static void EatWildcard(const CHAR** pattern, const CHAR* end, NEXT next) {
- while (*pattern != end) {
- if (!IsWildcard(**pattern))
- return;
- next(pattern, end);
- }
-}
-
-template <typename CHAR, typename NEXT>
-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
@@ -1042,9 +991,11 @@ size_t lcpyT(CHAR* dst, const CHAR* src, size_t dst_size) {
} // namespace
-size_t base::strlcpy(char* dst, const char* src, size_t dst_size) {
+size_t strlcpy(char* dst, const char* src, size_t dst_size) {
return lcpyT<char>(dst, src, dst_size);
}
-size_t base::wcslcpy(wchar_t* dst, const wchar_t* src, size_t dst_size) {
+size_t wcslcpy(wchar_t* dst, const wchar_t* src, size_t dst_size) {
return lcpyT<wchar_t>(dst, src, dst_size);
}
+
+} // namespace base
diff --git a/base/strings/string_util.h b/base/strings/string_util.h
index 027c6b675c..f1d708a2f3 100644
--- a/base/strings/string_util.h
+++ b/base/strings/string_util.h
@@ -9,15 +9,17 @@
#include <ctype.h>
#include <stdarg.h> // va_list
+#include <stddef.h>
+#include <stdint.h>
#include <string>
#include <vector>
#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.
+#include "build/build_config.h"
// On Android, bionic's stdio.h defines an snprintf macro when being built with
// clang. Undefine it here so it won't collide with base::snprintf().
@@ -25,23 +27,10 @@
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);
+// C standard-library functions that aren't cross-platform are provided as
+// "base::...", and their prototypes are listed below. These functions are
+// then implemented as inline calls to the platform-specific equivalents in the
+// platform-specific headers.
// Wrapper for vsnprintf that always null-terminates and always returns the
// number of characters that would be in an untruncated formatted
@@ -53,9 +42,14 @@ int vsnprintf(char* buffer, size_t size, const char* format, va_list arguments)
// 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, ...) {
+inline int snprintf(char* buffer,
+ size_t size,
+ _Printf_format_string_ const char* format,
+ ...) PRINTF_FORMAT(3, 4);
+inline int snprintf(char* buffer,
+ size_t size,
+ _Printf_format_string_ const char* format,
+ ...) {
va_list arguments;
va_start(arguments, format);
int result = vsnprintf(buffer, size, format, arguments);
@@ -97,27 +91,38 @@ 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 <class Char> inline Char ToLowerASCII(Char c) {
+inline char ToLowerASCII(char c) {
+ return (c >= 'A' && c <= 'Z') ? (c + ('a' - 'A')) : c;
+}
+inline char16 ToLowerASCII(char16 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 <class Char> inline Char ToUpperASCII(Char c) {
+inline char ToUpperASCII(char c) {
+ return (c >= 'a' && c <= 'z') ? (c + ('A' - 'a')) : c;
+}
+inline char16 ToUpperASCII(char16 c) {
return (c >= 'a' && c <= 'z') ? (c + ('A' - 'a')) : c;
}
-// Function objects to aid in comparing/searching strings.
+// Converts the given string to it's ASCII-lowercase equivalent.
+BASE_EXPORT std::string ToLowerASCII(StringPiece str);
+BASE_EXPORT string16 ToLowerASCII(StringPiece16 str);
-template<typename Char> 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);
- }
-};
+// Converts the given string to it's ASCII-uppercase equivalent.
+BASE_EXPORT std::string ToUpperASCII(StringPiece str);
+BASE_EXPORT string16 ToUpperASCII(StringPiece16 str);
+// Functor for case-insensitive ASCII comparisons for STL algorithms like
+// std::search.
+//
+// Note that a full Unicode version of this functor is not possible to write
+// because case mappings might change the number of characters, depend on
+// context (combining accents), and require handling UTF-16. If you need
+// proper Unicode support, use base::i18n::ToLower/FoldCase and then just
+// use a normal operator== on the result.
template<typename Char> struct CaseInsensitiveCompareASCII {
public:
bool operator()(Char x, Char y) const {
@@ -125,6 +130,22 @@ template<typename Char> struct CaseInsensitiveCompareASCII {
}
};
+// Like strcasecmp for case-insensitive ASCII characters only. Returns:
+// -1 (a < b)
+// 0 (a == b)
+// 1 (a > b)
+// (unlike strcasecmp which can return values greater or less than 1/-1). For
+// full Unicode support, use base::i18n::ToLower or base::i18h::FoldCase
+// and then just call the normal string operators on the result.
+BASE_EXPORT int CompareCaseInsensitiveASCII(StringPiece a, StringPiece b);
+BASE_EXPORT int CompareCaseInsensitiveASCII(StringPiece16 a, StringPiece16 b);
+
+// Equality for ASCII case-insensitive comparisons. For full Unicode support,
+// use base::i18n::ToLower or base::i18h::FoldCase and then compare with either
+// == or !=.
+BASE_EXPORT bool EqualsCaseInsensitiveASCII(StringPiece a, StringPiece b);
+BASE_EXPORT bool EqualsCaseInsensitiveASCII(StringPiece16 a, StringPiece16 b);
+
// These threadsafe functions return references to globally unique empty
// strings.
//
@@ -156,10 +177,10 @@ BASE_EXPORT extern const char kUtf8ByteOrderMark[];
// 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 base::StringPiece16& remove_chars,
+ const StringPiece16& remove_chars,
string16* output);
BASE_EXPORT bool RemoveChars(const std::string& input,
- const base::StringPiece& remove_chars,
+ const StringPiece& remove_chars,
std::string* output);
// Replaces characters in |replace_chars| from anywhere in |input| with
@@ -168,11 +189,11 @@ BASE_EXPORT bool RemoveChars(const std::string& input,
// |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 base::StringPiece16& replace_chars,
+ const StringPiece16& replace_chars,
const string16& replace_with,
string16* output);
BASE_EXPORT bool ReplaceChars(const std::string& input,
- const base::StringPiece& replace_chars,
+ const StringPiece& replace_chars,
const std::string& replace_with,
std::string* output);
@@ -189,19 +210,19 @@ enum TrimPositions {
// It is safe to use the same variable for both |input| and |output| (this is
// the normal usage to trim in-place).
BASE_EXPORT bool TrimString(const string16& input,
- base::StringPiece16 trim_chars,
+ StringPiece16 trim_chars,
string16* output);
BASE_EXPORT bool TrimString(const std::string& input,
- base::StringPiece trim_chars,
+ StringPiece trim_chars,
std::string* output);
// StringPiece versions of the above. The returned pieces refer to the original
// buffer.
BASE_EXPORT StringPiece16 TrimString(StringPiece16 input,
- const base::StringPiece16& trim_chars,
+ const StringPiece16& trim_chars,
TrimPositions positions);
BASE_EXPORT StringPiece TrimString(StringPiece input,
- const base::StringPiece& trim_chars,
+ const StringPiece& trim_chars,
TrimPositions positions);
// Truncates a string to the nearest UTF-8 character that will leave
@@ -210,25 +231,23 @@ 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.
+// Trims any whitespace from either end of the input string.
+//
+// The StringPiece versions return a substring referencing the input buffer.
+// The ASCII versions look only for ASCII whitespace.
+//
+// The std::string versions return where whitespace was found.
// NOTE: Safe to use the same variable for both input and output.
BASE_EXPORT TrimPositions TrimWhitespace(const string16& input,
TrimPositions positions,
- base::string16* output);
+ string16* output);
+BASE_EXPORT StringPiece16 TrimWhitespace(StringPiece16 input,
+ TrimPositions positions);
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);
+BASE_EXPORT StringPiece TrimWhitespaceASCII(StringPiece input,
+ TrimPositions positions);
// Searches for CR or LF characters. Removes all contiguous whitespace
// strings that contain them. This is useful when trying to deal with text
@@ -276,92 +295,43 @@ BASE_EXPORT bool IsStringASCII(const string16& str);
BASE_EXPORT bool IsStringASCII(const std::wstring& str);
#endif
-// Converts the elements of the given string. This version uses a pointer to
-// clearly differentiate it from the non-pointer variant.
-template <class str> inline void StringToLowerASCII(str* s) {
- for (typename str::iterator i = s->begin(); i != s->end(); ++i)
- *i = ToLowerASCII(*i);
-}
-
-template <class str> 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 <class str> inline void StringToUpperASCII(str* s) {
- for (typename str::iterator i = s->begin(); i != s->end(); ++i)
- *i = ToUpperASCII(*i);
-}
-
-template <class str> 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
+// previously-lower-cased ASCII string (typically a constant).
+BASE_EXPORT bool LowerCaseEqualsASCII(StringPiece str,
+ StringPiece lowecase_ascii);
+BASE_EXPORT bool LowerCaseEqualsASCII(StringPiece16 str,
+ StringPiece lowecase_ascii);
+
+// Performs a case-sensitive string compare of the given 16-bit string against
+// the given 8-bit ASCII string (typically a constant). The behavior is
+// undefined if the |ascii| string is not ASCII.
+BASE_EXPORT bool EqualsASCII(StringPiece16 str, StringPiece ascii);
+
+// Indicates case sensitivity of comparisons. Only ASCII case insensitivity
+// is supported. Full Unicode case-insensitive conversions would need to go in
+// base/i18n so it can use ICU.
//
-// 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 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(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 char* a_begin,
- const char* a_end,
- const char* b_begin,
- const char* b_end);
-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 StringPiece& b);
-
-// Returns true if str starts with search, or false otherwise.
-// TODO(brettw) the case sensitive flag makes callsites difficult to read.
-// Consider splitting this out in two variants (few callers want
-// case-insensitive compares) or use an enum that makes this more explicit.
-BASE_EXPORT bool StartsWithASCII(const std::string& str,
- const std::string& search,
- bool case_sensitive);
-BASE_EXPORT bool StartsWith(const base::string16& str,
- const base::string16& search,
- bool case_sensitive);
-
-// Returns true if str ends with search, or false otherwise.
-// TODO(brettw) case sensitive flag confusion, see StartsWith above.
-BASE_EXPORT bool EndsWith(const std::string& str,
- const std::string& search,
- bool case_sensitive);
-BASE_EXPORT bool EndsWith(const base::string16& str,
- const base::string16& search,
- bool case_sensitive);
-
-} // namespace base
+// If you need to do Unicode-aware case-insensitive StartsWith/EndsWith, it's
+// best to call base::i18n::ToLower() or base::i18n::FoldCase() (see
+// base/i18n/case_conversion.h for usage advice) on the arguments, and then use
+// the results to a case-sensitive comparison.
+enum class CompareCase {
+ SENSITIVE,
+ INSENSITIVE_ASCII,
+};
-#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
+BASE_EXPORT bool StartsWith(StringPiece str,
+ StringPiece search_for,
+ CompareCase case_sensitivity);
+BASE_EXPORT bool StartsWith(StringPiece16 str,
+ StringPiece16 search_for,
+ CompareCase case_sensitivity);
+BASE_EXPORT bool EndsWith(StringPiece str,
+ StringPiece search_for,
+ CompareCase case_sensitivity);
+BASE_EXPORT bool EndsWith(StringPiece16 str,
+ StringPiece16 search_for,
+ CompareCase case_sensitivity);
// Determines the type of ASCII character, independent of locale (the C
// library versions will change based on locale).
@@ -385,41 +355,34 @@ inline bool IsHexDigit(Char c) {
(c >= 'a' && c <= 'f');
}
-template <typename Char>
-inline char HexDigitToInt(Char c) {
- DCHECK(IsHexDigit(c));
- if (c >= '0' && c <= '9')
- return static_cast<char>(c - '0');
- if (c >= 'A' && c <= 'F')
- return static_cast<char>(c - 'A' + 10);
- if (c >= 'a' && c <= 'f')
- return static_cast<char>(c - 'a' + 10);
- return 0;
-}
+// Returns the integer corresponding to the given hex character. For example:
+// '4' -> 4
+// 'a' -> 10
+// 'B' -> 11
+// Assumes the input is a valid hex character. DCHECKs in debug builds if not.
+BASE_EXPORT char HexDigitToInt(wchar_t c);
-// Returns true if it's a whitespace character.
-inline bool IsWhitespace(wchar_t c) {
- return wcschr(base::kWhitespaceWide, c) != NULL;
-}
+// Returns true if it's a Unicode whitespace character.
+BASE_EXPORT bool IsUnicodeWhitespace(wchar_t c);
// 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 base::string16 FormatBytesUnlocalized(int64 bytes);
+BASE_EXPORT string16 FormatBytesUnlocalized(int64_t bytes);
// Starting at |start_offset| (usually 0), replace the first instance of
// |find_this| with |replace_with|.
BASE_EXPORT void ReplaceFirstSubstringAfterOffset(
base::string16* str,
size_t start_offset,
- const base::string16& find_this,
- const base::string16& replace_with);
+ StringPiece16 find_this,
+ StringPiece16 replace_with);
BASE_EXPORT void ReplaceFirstSubstringAfterOffset(
std::string* str,
size_t start_offset,
- const std::string& find_this,
- const std::string& replace_with);
+ StringPiece find_this,
+ StringPiece replace_with);
// Starting at |start_offset| (usually 0), look through |str| and replace all
// instances of |find_this| with |replace_with|.
@@ -428,14 +391,15 @@ BASE_EXPORT void ReplaceFirstSubstringAfterOffset(
// characters, for example:
// std::replace(str.begin(), str.end(), 'a', 'b');
BASE_EXPORT void ReplaceSubstringsAfterOffset(
- base::string16* str,
+ string16* str,
size_t start_offset,
- const base::string16& find_this,
- const base::string16& replace_with);
-BASE_EXPORT void ReplaceSubstringsAfterOffset(std::string* str,
- size_t start_offset,
- const std::string& find_this,
- const std::string& replace_with);
+ StringPiece16 find_this,
+ StringPiece16 replace_with);
+BASE_EXPORT void ReplaceSubstringsAfterOffset(
+ std::string* str,
+ size_t start_offset,
+ StringPiece find_this,
+ StringPiece 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
@@ -457,75 +421,45 @@ BASE_EXPORT void ReplaceSubstringsAfterOffset(std::string* str,
// 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 <class string_type>
-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.
-//
-// DEPRECATED. Use SplitStringUsingSet for new code (these just forward).
-// TODO(brettw) convert callers and delete these forwarders.
-BASE_EXPORT size_t Tokenize(const base::string16& str,
- const base::string16& delimiters,
- std::vector<base::string16>* tokens);
-BASE_EXPORT size_t Tokenize(const std::string& str,
- const std::string& delimiters,
- std::vector<std::string>* tokens);
-BASE_EXPORT size_t Tokenize(const base::StringPiece& str,
- const base::StringPiece& delimiters,
- std::vector<base::StringPiece>* tokens);
+BASE_EXPORT char* WriteInto(std::string* str, size_t length_with_null);
+BASE_EXPORT char16* WriteInto(string16* str, size_t length_with_null);
+#ifndef OS_WIN
+BASE_EXPORT wchar_t* WriteInto(std::wstring* str, size_t length_with_null);
+#endif
// Does the opposite of SplitString().
-BASE_EXPORT base::string16 JoinString(const std::vector<base::string16>& parts,
- base::char16 s);
-BASE_EXPORT std::string JoinString(
- const std::vector<std::string>& parts, char s);
-
-// Join |parts| using |separator|.
-BASE_EXPORT std::string JoinString(
- const std::vector<std::string>& parts,
- const std::string& separator);
-BASE_EXPORT base::string16 JoinString(
- const std::vector<base::string16>& parts,
- const base::string16& separator);
+BASE_EXPORT std::string JoinString(const std::vector<std::string>& parts,
+ StringPiece separator);
+BASE_EXPORT string16 JoinString(const std::vector<string16>& parts,
+ StringPiece16 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 base::string16 ReplaceStringPlaceholders(
- const base::string16& format_string,
- const std::vector<base::string16>& subst,
+BASE_EXPORT string16 ReplaceStringPlaceholders(
+ const string16& format_string,
+ const std::vector<string16>& subst,
std::vector<size_t>* offsets);
BASE_EXPORT std::string ReplaceStringPlaceholders(
- const base::StringPiece& format_string,
+ const StringPiece& format_string,
const std::vector<std::string>& subst,
std::vector<size_t>* offsets);
// Single-string shortcut for ReplaceStringHolders. |offset| may be NULL.
-BASE_EXPORT base::string16 ReplaceStringPlaceholders(
- const base::string16& format_string,
- const base::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 base::string16& string,
- const base::string16& pattern);
+BASE_EXPORT string16 ReplaceStringPlaceholders(const string16& format_string,
+ const string16& a,
+ size_t* offset);
+
+} // 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
#endif // BASE_STRINGS_STRING_UTIL_H_
diff --git a/base/strings/string_util_posix.h b/base/strings/string_util_posix.h
index f4009d4ae7..8299118e10 100644
--- a/base/strings/string_util_posix.h
+++ b/base/strings/string_util_posix.h
@@ -6,6 +6,7 @@
#define BASE_STRINGS_STRING_UTIL_POSIX_H_
#include <stdarg.h>
+#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <wchar.h>
@@ -20,27 +21,11 @@ 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));
diff --git a/base/strings/string_util_unittest.cc b/base/strings/string_util_unittest.cc
index fb0beada4b..79eed61d5c 100644
--- a/base/strings/string_util_unittest.cc
+++ b/base/strings/string_util_unittest.cc
@@ -6,10 +6,12 @@
#include <math.h>
#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
#include <algorithm>
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -250,7 +252,7 @@ TEST(StringUtilTest, TrimWhitespace) {
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));
+ TrimWhitespaceASCII(value.input, value.positions, &output_ascii));
EXPECT_EQ(value.output, output_ascii);
}
}
@@ -503,30 +505,30 @@ TEST(StringUtilTest, ConvertASCII) {
EXPECT_EQ(0, string_with_nul.compare(narrow_with_nul));
}
+TEST(StringUtilTest, ToLowerASCII) {
+ EXPECT_EQ('c', ToLowerASCII('C'));
+ EXPECT_EQ('c', ToLowerASCII('c'));
+ EXPECT_EQ('2', ToLowerASCII('2'));
+
+ EXPECT_EQ(static_cast<char16>('c'), ToLowerASCII(static_cast<char16>('C')));
+ EXPECT_EQ(static_cast<char16>('c'), ToLowerASCII(static_cast<char16>('c')));
+ EXPECT_EQ(static_cast<char16>('2'), ToLowerASCII(static_cast<char16>('2')));
+
+ EXPECT_EQ("cc2", ToLowerASCII("Cc2"));
+ EXPECT_EQ(ASCIIToUTF16("cc2"), ToLowerASCII(ASCIIToUTF16("Cc2")));
+}
+
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);
+ EXPECT_EQ(static_cast<char16>('C'), ToUpperASCII(static_cast<char16>('C')));
+ EXPECT_EQ(static_cast<char16>('C'), ToUpperASCII(static_cast<char16>('c')));
+ EXPECT_EQ(static_cast<char16>('2'), ToUpperASCII(static_cast<char16>('2')));
- std::wstring original_w(L"Cc2");
- std::wstring upper_w = StringToUpperASCII(original_w);
- EXPECT_EQ(L"CC2", upper_w);
+ EXPECT_EQ("CC2", ToUpperASCII("Cc2"));
+ EXPECT_EQ(ASCIIToUTF16("CC2"), ToUpperASCII(ASCIIToUTF16("Cc2")));
}
TEST(StringUtilTest, LowerCaseEqualsASCII) {
@@ -549,7 +551,7 @@ TEST(StringUtilTest, LowerCaseEqualsASCII) {
TEST(StringUtilTest, FormatBytesUnlocalized) {
static const struct {
- int64 bytes;
+ int64_t bytes;
const char* expected;
} cases[] = {
// Expected behavior: we show one post-decimal digit when we have
@@ -669,128 +671,7 @@ TEST(StringUtilTest, HexDigitToInt) {
EXPECT_EQ(15, HexDigitToInt('f'));
}
-// Test for Tokenize
-template <typename STR>
-void TokenizeTest() {
- std::vector<STR> 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<std::string>();
-}
-
-TEST(StringUtilTest, TokenizeStringPiece) {
- TokenizeTest<StringPiece>();
-}
-
-// Test for JoinString
TEST(StringUtilTest, JoinString) {
- std::vector<std::string> 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<std::string> parts;
EXPECT_EQ(std::string(), JoinString(parts, separator));
@@ -808,8 +689,7 @@ TEST(StringUtilTest, JoinStringWithString) {
EXPECT_EQ("a|b|c|| ", JoinString(parts, "|"));
}
-// Test for JoinString overloaded with string16 separator
-TEST(StringUtilTest, JoinStringWithString16) {
+TEST(StringUtilTest, JoinString16) {
string16 separator = ASCIIToUTF16(", ");
std::vector<string16> parts;
EXPECT_EQ(string16(), JoinString(parts, separator));
@@ -828,59 +708,83 @@ TEST(StringUtilTest, JoinStringWithString16) {
}
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("javascript:url", "javascript",
+ base::CompareCase::SENSITIVE));
+ EXPECT_FALSE(StartsWith("JavaScript:url", "javascript",
+ base::CompareCase::SENSITIVE));
+ EXPECT_TRUE(StartsWith("javascript:url", "javascript",
+ base::CompareCase::INSENSITIVE_ASCII));
+ EXPECT_TRUE(StartsWith("JavaScript:url", "javascript",
+ base::CompareCase::INSENSITIVE_ASCII));
+ EXPECT_FALSE(StartsWith("java", "javascript", base::CompareCase::SENSITIVE));
+ EXPECT_FALSE(StartsWith("java", "javascript",
+ base::CompareCase::INSENSITIVE_ASCII));
+ EXPECT_FALSE(StartsWith(std::string(), "javascript",
+ base::CompareCase::INSENSITIVE_ASCII));
+ EXPECT_FALSE(StartsWith(std::string(), "javascript",
+ base::CompareCase::SENSITIVE));
+ EXPECT_TRUE(StartsWith("java", std::string(),
+ base::CompareCase::INSENSITIVE_ASCII));
+ EXPECT_TRUE(StartsWith("java", std::string(), base::CompareCase::SENSITIVE));
EXPECT_TRUE(StartsWith(ASCIIToUTF16("javascript:url"),
- ASCIIToUTF16("javascript"), true));
+ ASCIIToUTF16("javascript"),
+ base::CompareCase::SENSITIVE));
EXPECT_FALSE(StartsWith(ASCIIToUTF16("JavaScript:url"),
- ASCIIToUTF16("javascript"), true));
+ ASCIIToUTF16("javascript"),
+ base::CompareCase::SENSITIVE));
EXPECT_TRUE(StartsWith(ASCIIToUTF16("javascript:url"),
- ASCIIToUTF16("javascript"), false));
+ ASCIIToUTF16("javascript"),
+ base::CompareCase::INSENSITIVE_ASCII));
EXPECT_TRUE(StartsWith(ASCIIToUTF16("JavaScript:url"),
- ASCIIToUTF16("javascript"), false));
- EXPECT_FALSE(StartsWith(ASCIIToUTF16("java"),
- ASCIIToUTF16("javascript"), true));
- EXPECT_FALSE(StartsWith(ASCIIToUTF16("java"),
- ASCIIToUTF16("javascript"), false));
- EXPECT_FALSE(StartsWith(string16(), ASCIIToUTF16("javascript"), false));
- EXPECT_FALSE(StartsWith(string16(), ASCIIToUTF16("javascript"), true));
- EXPECT_TRUE(StartsWith(ASCIIToUTF16("java"), string16(), false));
- EXPECT_TRUE(StartsWith(ASCIIToUTF16("java"), string16(), true));
+ ASCIIToUTF16("javascript"),
+ base::CompareCase::INSENSITIVE_ASCII));
+ EXPECT_FALSE(StartsWith(ASCIIToUTF16("java"), ASCIIToUTF16("javascript"),
+ base::CompareCase::SENSITIVE));
+ EXPECT_FALSE(StartsWith(ASCIIToUTF16("java"), ASCIIToUTF16("javascript"),
+ base::CompareCase::INSENSITIVE_ASCII));
+ EXPECT_FALSE(StartsWith(string16(), ASCIIToUTF16("javascript"),
+ base::CompareCase::INSENSITIVE_ASCII));
+ EXPECT_FALSE(StartsWith(string16(), ASCIIToUTF16("javascript"),
+ base::CompareCase::SENSITIVE));
+ EXPECT_TRUE(StartsWith(ASCIIToUTF16("java"), string16(),
+ base::CompareCase::INSENSITIVE_ASCII));
+ EXPECT_TRUE(StartsWith(ASCIIToUTF16("java"), string16(),
+ base::CompareCase::SENSITIVE));
}
TEST(StringUtilTest, EndsWith) {
- EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.plugin"),
- ASCIIToUTF16(".plugin"), true));
- EXPECT_FALSE(EndsWith(ASCIIToUTF16("Foo.Plugin"),
- ASCIIToUTF16(".plugin"), true));
- EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.plugin"),
- ASCIIToUTF16(".plugin"), false));
- EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.Plugin"),
- ASCIIToUTF16(".plugin"), false));
- EXPECT_FALSE(EndsWith(ASCIIToUTF16(".plug"), ASCIIToUTF16(".plugin"), true));
- EXPECT_FALSE(EndsWith(ASCIIToUTF16(".plug"), ASCIIToUTF16(".plugin"), false));
- EXPECT_FALSE(EndsWith(ASCIIToUTF16("Foo.plugin Bar"),
- ASCIIToUTF16(".plugin"), true));
- EXPECT_FALSE(EndsWith(ASCIIToUTF16("Foo.plugin Bar"),
- ASCIIToUTF16(".plugin"), false));
- EXPECT_FALSE(EndsWith(string16(), ASCIIToUTF16(".plugin"), false));
- EXPECT_FALSE(EndsWith(string16(), ASCIIToUTF16(".plugin"), true));
- EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.plugin"), string16(), false));
- EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.plugin"), string16(), true));
- EXPECT_TRUE(EndsWith(ASCIIToUTF16(".plugin"),
- ASCIIToUTF16(".plugin"), false));
- EXPECT_TRUE(EndsWith(ASCIIToUTF16(".plugin"), ASCIIToUTF16(".plugin"), true));
- EXPECT_TRUE(EndsWith(string16(), string16(), false));
- EXPECT_TRUE(EndsWith(string16(), string16(), true));
+ EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.plugin"), ASCIIToUTF16(".plugin"),
+ base::CompareCase::SENSITIVE));
+ EXPECT_FALSE(EndsWith(ASCIIToUTF16("Foo.Plugin"), ASCIIToUTF16(".plugin"),
+ base::CompareCase::SENSITIVE));
+ EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.plugin"), ASCIIToUTF16(".plugin"),
+ base::CompareCase::INSENSITIVE_ASCII));
+ EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.Plugin"), ASCIIToUTF16(".plugin"),
+ base::CompareCase::INSENSITIVE_ASCII));
+ EXPECT_FALSE(EndsWith(ASCIIToUTF16(".plug"), ASCIIToUTF16(".plugin"),
+ base::CompareCase::SENSITIVE));
+ EXPECT_FALSE(EndsWith(ASCIIToUTF16(".plug"), ASCIIToUTF16(".plugin"),
+ base::CompareCase::INSENSITIVE_ASCII));
+ EXPECT_FALSE(EndsWith(ASCIIToUTF16("Foo.plugin Bar"), ASCIIToUTF16(".plugin"),
+ base::CompareCase::SENSITIVE));
+ EXPECT_FALSE(EndsWith(ASCIIToUTF16("Foo.plugin Bar"), ASCIIToUTF16(".plugin"),
+ base::CompareCase::INSENSITIVE_ASCII));
+ EXPECT_FALSE(EndsWith(string16(), ASCIIToUTF16(".plugin"),
+ base::CompareCase::INSENSITIVE_ASCII));
+ EXPECT_FALSE(EndsWith(string16(), ASCIIToUTF16(".plugin"),
+ base::CompareCase::SENSITIVE));
+ EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.plugin"), string16(),
+ base::CompareCase::INSENSITIVE_ASCII));
+ EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.plugin"), string16(),
+ base::CompareCase::SENSITIVE));
+ EXPECT_TRUE(EndsWith(ASCIIToUTF16(".plugin"), ASCIIToUTF16(".plugin"),
+ base::CompareCase::INSENSITIVE_ASCII));
+ EXPECT_TRUE(EndsWith(ASCIIToUTF16(".plugin"), ASCIIToUTF16(".plugin"),
+ base::CompareCase::SENSITIVE));
+ EXPECT_TRUE(
+ EndsWith(string16(), string16(), base::CompareCase::INSENSITIVE_ASCII));
+ EXPECT_TRUE(EndsWith(string16(), string16(), base::CompareCase::SENSITIVE));
}
TEST(StringUtilTest, GetStringFWithOffsets) {
@@ -994,45 +898,6 @@ TEST(StringUtilTest, ReplaceStringPlaceholdersConsecutiveDollarSigns) {
"$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.
{
@@ -1197,6 +1062,46 @@ TEST(StringUtilTest, ContainsOnlyChars) {
kWhitespaceUTF16));
}
+TEST(StringUtilTest, CompareCaseInsensitiveASCII) {
+ EXPECT_EQ(0, CompareCaseInsensitiveASCII("", ""));
+ EXPECT_EQ(0, CompareCaseInsensitiveASCII("Asdf", "aSDf"));
+
+ // Differing lengths.
+ EXPECT_EQ(-1, CompareCaseInsensitiveASCII("Asdf", "aSDfA"));
+ EXPECT_EQ(1, CompareCaseInsensitiveASCII("AsdfA", "aSDf"));
+
+ // Differing values.
+ EXPECT_EQ(-1, CompareCaseInsensitiveASCII("AsdfA", "aSDfb"));
+ EXPECT_EQ(1, CompareCaseInsensitiveASCII("Asdfb", "aSDfA"));
+}
+
+TEST(StringUtilTest, EqualsCaseInsensitiveASCII) {
+ EXPECT_TRUE(EqualsCaseInsensitiveASCII("", ""));
+ EXPECT_TRUE(EqualsCaseInsensitiveASCII("Asdf", "aSDF"));
+ EXPECT_FALSE(EqualsCaseInsensitiveASCII("bsdf", "aSDF"));
+ EXPECT_FALSE(EqualsCaseInsensitiveASCII("Asdf", "aSDFz"));
+}
+
+TEST(StringUtilTest, IsUnicodeWhitespace) {
+ // NOT unicode white space.
+ EXPECT_FALSE(IsUnicodeWhitespace(L'\0'));
+ EXPECT_FALSE(IsUnicodeWhitespace(L'A'));
+ EXPECT_FALSE(IsUnicodeWhitespace(L'0'));
+ EXPECT_FALSE(IsUnicodeWhitespace(L'.'));
+ EXPECT_FALSE(IsUnicodeWhitespace(L';'));
+ EXPECT_FALSE(IsUnicodeWhitespace(L'\x4100'));
+
+ // Actual unicode whitespace.
+ EXPECT_TRUE(IsUnicodeWhitespace(L' '));
+ EXPECT_TRUE(IsUnicodeWhitespace(L'\xa0'));
+ EXPECT_TRUE(IsUnicodeWhitespace(L'\x3000'));
+ EXPECT_TRUE(IsUnicodeWhitespace(L'\t'));
+ EXPECT_TRUE(IsUnicodeWhitespace(L'\r'));
+ EXPECT_TRUE(IsUnicodeWhitespace(L'\v'));
+ EXPECT_TRUE(IsUnicodeWhitespace(L'\f'));
+ EXPECT_TRUE(IsUnicodeWhitespace(L'\n'));
+}
+
class WriteIntoTest : public testing::Test {
protected:
static void WritesCorrectly(size_t num_chars) {
diff --git a/base/strings/string_util_win.h b/base/strings/string_util_win.h
index 61eda2009d..7f260bfc8b 100644
--- a/base/strings/string_util_win.h
+++ b/base/strings/string_util_win.h
@@ -6,6 +6,7 @@
#define BASE_STRINGS_STRING_UTIL_WIN_H_
#include <stdarg.h>
+#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <wchar.h>
@@ -20,18 +21,6 @@ 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 = vsnprintf_s(buffer, size, size - 1, format, arguments);
diff --git a/base/strings/stringprintf.cc b/base/strings/stringprintf.cc
index 537873d71c..415845d616 100644
--- a/base/strings/stringprintf.cc
+++ b/base/strings/stringprintf.cc
@@ -5,12 +5,15 @@
#include "base/strings/stringprintf.h"
#include <errno.h>
+#include <stddef.h>
#include <vector>
+#include "base/macros.h"
#include "base/scoped_clear_errno.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
namespace base {
diff --git a/base/strings/stringprintf.h b/base/strings/stringprintf.h
index 523f7ee55b..7a75d89e10 100644
--- a/base/strings/stringprintf.h
+++ b/base/strings/stringprintf.h
@@ -11,15 +11,18 @@
#include "base/base_export.h"
#include "base/compiler_specific.h"
+#include "build/build_config.h"
namespace base {
// Return a C++ string given printf-like input.
-BASE_EXPORT std::string StringPrintf(const char* format, ...)
+BASE_EXPORT std::string StringPrintf(_Printf_format_string_ const char* format,
+ ...)
PRINTF_FORMAT(1, 2) WARN_UNUSED_RESULT;
#if defined(OS_WIN)
-BASE_EXPORT std::wstring StringPrintf(const wchar_t* format, ...)
- WPRINTF_FORMAT(1, 2) WARN_UNUSED_RESULT;
+BASE_EXPORT std::wstring StringPrintf(
+ _Printf_format_string_ const wchar_t* format,
+ ...) WPRINTF_FORMAT(1, 2) WARN_UNUSED_RESULT;
#endif
// Return a C++ string given vprintf-like input.
@@ -27,21 +30,25 @@ BASE_EXPORT std::string StringPrintV(const char* format, va_list ap)
PRINTF_FORMAT(1, 0) WARN_UNUSED_RESULT;
// 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);
+BASE_EXPORT const std::string& SStringPrintf(
+ std::string* dst,
+ _Printf_format_string_ const char* format,
+ ...) PRINTF_FORMAT(2, 3);
#if defined(OS_WIN)
-BASE_EXPORT const std::wstring& SStringPrintf(std::wstring* dst,
- const wchar_t* format, ...)
- WPRINTF_FORMAT(2, 3);
+BASE_EXPORT const std::wstring& SStringPrintf(
+ std::wstring* dst,
+ _Printf_format_string_ 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);
+BASE_EXPORT void StringAppendF(std::string* dst,
+ _Printf_format_string_ const char* format,
+ ...) PRINTF_FORMAT(2, 3);
#if defined(OS_WIN)
-BASE_EXPORT void StringAppendF(std::wstring* dst, const wchar_t* format, ...)
- WPRINTF_FORMAT(2, 3);
+BASE_EXPORT void StringAppendF(std::wstring* dst,
+ _Printf_format_string_ const wchar_t* format,
+ ...) WPRINTF_FORMAT(2, 3);
#endif
// Lower-level routine that takes a va_list and appends to a specified
diff --git a/base/strings/stringprintf_unittest.cc b/base/strings/stringprintf_unittest.cc
index c49637c23f..e2d3a90ffd 100644
--- a/base/strings/stringprintf_unittest.cc
+++ b/base/strings/stringprintf_unittest.cc
@@ -5,8 +5,10 @@
#include "base/strings/stringprintf.h"
#include <errno.h>
+#include <stddef.h>
-#include "base/basictypes.h"
+#include "base/macros.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
@@ -148,10 +150,10 @@ TEST(StringPrintfTest, GrowBoundary) {
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.
+// vswprintf in Visual Studio 2013 fails when given U+FFFF. This tests that the
+// failure case is gracefuly handled. In Visual Studio 2015 the bad character
+// is passed through.
TEST(StringPrintfTest, Invalid) {
wchar_t invalid[2];
invalid[0] = 0xffff;
@@ -159,7 +161,11 @@ TEST(StringPrintfTest, Invalid) {
std::wstring out;
SStringPrintf(&out, L"%ls", invalid);
+#if _MSC_VER >= 1900
+ EXPECT_STREQ(invalid, out.c_str());
+#else
EXPECT_STREQ(L"", out.c_str());
+#endif
}
#endif
diff --git a/base/strings/sys_string_conversions.h b/base/strings/sys_string_conversions.h
index 42f2389a8b..b41a2288ca 100644
--- a/base/strings/sys_string_conversions.h
+++ b/base/strings/sys_string_conversions.h
@@ -9,12 +9,14 @@
// 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 <stdint.h>
+
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/strings/string16.h"
#include "base/strings/string_piece.h"
+#include "build/build_config.h"
#if defined(OS_MACOSX)
#include <CoreFoundation/CoreFoundation.h>
@@ -46,9 +48,9 @@ BASE_EXPORT std::wstring SysNativeMBToWide(const StringPiece& native_mb);
// code page identifier is one accepted by the Windows function
// MultiByteToWideChar().
BASE_EXPORT std::wstring SysMultiByteToWide(const StringPiece& mb,
- uint32 code_page);
+ uint32_t code_page);
BASE_EXPORT std::string SysWideToMultiByte(const std::wstring& wide,
- uint32 code_page);
+ uint32_t code_page);
#endif // defined(OS_WIN)
diff --git a/base/strings/sys_string_conversions_mac.mm b/base/strings/sys_string_conversions_mac.mm
index 9479e787c0..32fe89cc36 100644
--- a/base/strings/sys_string_conversions_mac.mm
+++ b/base/strings/sys_string_conversions_mac.mm
@@ -5,6 +5,7 @@
#include "base/strings/sys_string_conversions.h"
#import <Foundation/Foundation.h>
+#include <stddef.h>
#include <vector>
diff --git a/base/strings/sys_string_conversions_posix.cc b/base/strings/sys_string_conversions_posix.cc
index 3b1845622f..a8dcfd0a90 100644
--- a/base/strings/sys_string_conversions_posix.cc
+++ b/base/strings/sys_string_conversions_posix.cc
@@ -4,10 +4,12 @@
#include "base/strings/sys_string_conversions.h"
+#include <stddef.h>
#include <wchar.h>
#include "base/strings/string_piece.h"
#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
namespace base {
diff --git a/base/strings/sys_string_conversions_unittest.cc b/base/strings/sys_string_conversions_unittest.cc
index 90c4767e25..f5ffaec17b 100644
--- a/base/strings/sys_string_conversions_unittest.cc
+++ b/base/strings/sys_string_conversions_unittest.cc
@@ -2,13 +2,16 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stddef.h>
+
#include <string>
-#include "base/basictypes.h"
+#include "base/macros.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 "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#ifdef WCHAR_T_IS_UTF32
diff --git a/base/strings/utf_string_conversion_utils.cc b/base/strings/utf_string_conversion_utils.cc
index 1a3a1c30ea..807e22db6e 100644
--- a/base/strings/utf_string_conversion_utils.cc
+++ b/base/strings/utf_string_conversion_utils.cc
@@ -11,15 +11,15 @@ namespace base {
// ReadUnicodeCharacter --------------------------------------------------------
bool ReadUnicodeCharacter(const char* src,
- int32 src_len,
- int32* char_index,
- uint32* code_point_out) {
+ int32_t src_len,
+ int32_t* char_index,
+ uint32_t* 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;
+ int32_t code_point;
CBU8_NEXT(src, *char_index, src_len, code_point);
- *code_point_out = static_cast<uint32>(code_point);
+ *code_point_out = static_cast<uint32_t>(code_point);
// The ICU macro above moves to the next char, we want to point to the last
// char consumed.
@@ -30,9 +30,9 @@ bool ReadUnicodeCharacter(const char* src,
}
bool ReadUnicodeCharacter(const char16* src,
- int32 src_len,
- int32* char_index,
- uint32* code_point) {
+ int32_t src_len,
+ int32_t* char_index,
+ uint32_t* code_point) {
if (CBU16_IS_SURROGATE(src[*char_index])) {
if (!CBU16_IS_SURROGATE_LEAD(src[*char_index]) ||
*char_index + 1 >= src_len ||
@@ -55,9 +55,9 @@ bool ReadUnicodeCharacter(const char16* src,
#if defined(WCHAR_T_IS_UTF32)
bool ReadUnicodeCharacter(const wchar_t* src,
- int32 /* src_len */,
- int32* char_index,
- uint32* code_point) {
+ int32_t /* src_len */,
+ int32_t* char_index,
+ uint32_t* code_point) {
// Conversion is easy since the source is 32-bit.
*code_point = src[*char_index];
@@ -68,7 +68,7 @@ bool ReadUnicodeCharacter(const wchar_t* src,
// WriteUnicodeCharacter -------------------------------------------------------
-size_t WriteUnicodeCharacter(uint32 code_point, std::string* output) {
+size_t WriteUnicodeCharacter(uint32_t code_point, std::string* output) {
if (code_point <= 0x7f) {
// Fast path the common case of one byte.
output->push_back(static_cast<char>(code_point));
@@ -89,7 +89,7 @@ size_t WriteUnicodeCharacter(uint32 code_point, std::string* output) {
return char_offset - original_char_offset;
}
-size_t WriteUnicodeCharacter(uint32 code_point, string16* output) {
+size_t WriteUnicodeCharacter(uint32_t 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<char16>(code_point));
diff --git a/base/strings/utf_string_conversion_utils.h b/base/strings/utf_string_conversion_utils.h
index 22abbbc9e7..c716404539 100644
--- a/base/strings/utf_string_conversion_utils.h
+++ b/base/strings/utf_string_conversion_utils.h
@@ -7,12 +7,15 @@
// This should only be used by the various UTF string conversion files.
+#include <stddef.h>
+#include <stdint.h>
+
#include "base/base_export.h"
#include "base/strings/string16.h"
namespace base {
-inline bool IsValidCodepoint(uint32 code_point) {
+inline bool IsValidCodepoint(uint32_t 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.
@@ -20,7 +23,7 @@ inline bool IsValidCodepoint(uint32 code_point) {
(code_point >= 0xE000u && code_point <= 0x10FFFFu);
}
-inline bool IsValidCharacter(uint32 code_point) {
+inline bool IsValidCharacter(uint32_t 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 &&
@@ -38,40 +41,39 @@ inline bool IsValidCharacter(uint32 code_point) {
//
// 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);
+ int32_t src_len,
+ int32_t* char_index,
+ uint32_t* 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);
+ int32_t src_len,
+ int32_t* char_index,
+ uint32_t* 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);
+ int32_t src_len,
+ int32_t* char_index,
+ uint32_t* 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,
+BASE_EXPORT size_t WriteUnicodeCharacter(uint32_t 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);
+BASE_EXPORT size_t WriteUnicodeCharacter(uint32_t 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) {
+inline size_t WriteUnicodeCharacter(uint32_t code_point, std::wstring* output) {
// This is the easy case, just append the character.
output->push_back(code_point);
return 1;
diff --git a/base/strings/utf_string_conversions.cc b/base/strings/utf_string_conversions.cc
index 1480d48086..6b17eacd6c 100644
--- a/base/strings/utf_string_conversions.cc
+++ b/base/strings/utf_string_conversions.cc
@@ -4,9 +4,12 @@
#include "base/strings/utf_string_conversions.h"
+#include <stdint.h>
+
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversion_utils.h"
+#include "build/build_config.h"
namespace base {
@@ -24,9 +27,9 @@ bool ConvertUnicode(const SRC_CHAR* src,
DEST_STRING* output) {
// ICU requires 32-bit numbers.
bool success = true;
- int32 src_len32 = static_cast<int32>(src_len);
- for (int32 i = 0; i < src_len32; i++) {
- uint32 code_point;
+ int32_t src_len32 = static_cast<int32_t>(src_len);
+ for (int32_t i = 0; i < src_len32; i++) {
+ uint32_t code_point;
if (ReadUnicodeCharacter(src, src_len32, &i, &code_point)) {
WriteUnicodeCharacter(code_point, output);
} else {
@@ -73,7 +76,7 @@ bool UTF8ToWide(const char* src, size_t src_len, std::wstring* output) {
}
}
-std::wstring UTF8ToWide(const StringPiece& utf8) {
+std::wstring UTF8ToWide(StringPiece utf8) {
if (IsStringASCII(utf8)) {
return std::wstring(utf8.begin(), utf8.end());
}
@@ -153,7 +156,7 @@ bool UTF8ToUTF16(const char* src, size_t src_len, string16* output) {
}
}
-string16 UTF8ToUTF16(const StringPiece& utf8) {
+string16 UTF8ToUTF16(StringPiece utf8) {
if (IsStringASCII(utf8)) {
return string16(utf8.begin(), utf8.end());
}
@@ -176,7 +179,7 @@ bool UTF16ToUTF8(const char16* src, size_t src_len, std::string* output) {
}
}
-std::string UTF16ToUTF8(const string16& utf16) {
+std::string UTF16ToUTF8(StringPiece16 utf16) {
if (IsStringASCII(utf16)) {
return std::string(utf16.begin(), utf16.end());
}
@@ -195,7 +198,7 @@ bool UTF8ToUTF16(const char* src, size_t src_len, string16* output) {
return UTF8ToWide(src, src_len, output);
}
-string16 UTF8ToUTF16(const StringPiece& utf8) {
+string16 UTF8ToUTF16(StringPiece utf8) {
return UTF8ToWide(utf8);
}
@@ -203,18 +206,24 @@ 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);
+std::string UTF16ToUTF8(StringPiece16 utf16) {
+ if (IsStringASCII(utf16))
+ return std::string(utf16.data(), utf16.data() + utf16.length());
+
+ std::string ret;
+ PrepareForUTF8Output(utf16.data(), utf16.length(), &ret);
+ ConvertUnicode(utf16.data(), utf16.length(), &ret);
+ return ret;
}
#endif
-string16 ASCIIToUTF16(const StringPiece& ascii) {
+string16 ASCIIToUTF16(StringPiece ascii) {
DCHECK(IsStringASCII(ascii)) << ascii;
return string16(ascii.begin(), ascii.end());
}
-std::string UTF16ToASCII(const string16& utf16) {
+std::string UTF16ToASCII(StringPiece16 utf16) {
DCHECK(IsStringASCII(utf16)) << UTF16ToUTF8(utf16);
return std::string(utf16.begin(), utf16.end());
}
diff --git a/base/strings/utf_string_conversions.h b/base/strings/utf_string_conversions.h
index 06a3bc6476..2995f4cbcf 100644
--- a/base/strings/utf_string_conversions.h
+++ b/base/strings/utf_string_conversions.h
@@ -5,6 +5,8 @@
#ifndef BASE_STRINGS_UTF_STRING_CONVERSIONS_H_
#define BASE_STRINGS_UTF_STRING_CONVERSIONS_H_
+#include <stddef.h>
+
#include <string>
#include "base/base_export.h"
@@ -24,7 +26,7 @@ BASE_EXPORT bool WideToUTF8(const wchar_t* src, size_t src_len,
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 std::wstring UTF8ToWide(StringPiece utf8);
BASE_EXPORT bool WideToUTF16(const wchar_t* src, size_t src_len,
string16* output);
@@ -34,18 +36,18 @@ BASE_EXPORT bool UTF16ToWide(const char16* src, size_t src_len,
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 string16 UTF8ToUTF16(StringPiece utf8);
BASE_EXPORT bool UTF16ToUTF8(const char16* src, size_t src_len,
std::string* output);
-BASE_EXPORT std::string UTF16ToUTF8(const string16& utf16);
+BASE_EXPORT std::string UTF16ToUTF8(StringPiece16 utf16);
// This converts an ASCII string, typically a hardcoded constant, to a UTF16
// string.
-BASE_EXPORT string16 ASCIIToUTF16(const StringPiece& ascii);
+BASE_EXPORT string16 ASCIIToUTF16(StringPiece ascii);
// Converts to 7-bit ASCII by truncating. The result must be known to be ASCII
// beforehand.
-BASE_EXPORT std::string UTF16ToASCII(const string16& utf16);
+BASE_EXPORT std::string UTF16ToASCII(StringPiece16 utf16);
} // namespace base
diff --git a/base/strings/utf_string_conversions_unittest.cc b/base/strings/utf_string_conversions_unittest.cc
index a7b12ffe0e..810771357a 100644
--- a/base/strings/utf_string_conversions_unittest.cc
+++ b/base/strings/utf_string_conversions_unittest.cc
@@ -2,11 +2,14 @@
// 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 <stddef.h>
+
#include "base/logging.h"
+#include "base/macros.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
@@ -139,13 +142,11 @@ TEST(UTFStringConversionsTest, ConvertUTF16ToUTF8) {
{L"\x597d\xd800", "\xe5\xa5\xbd\xef\xbf\xbd", false},
};
- for (int i = 0; i < arraysize(convert_cases); i++) {
+ for (const auto& test : convert_cases) {
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(test.success,
+ WideToUTF8(test.utf16, wcslen(test.utf16), &converted));
+ std::string expected(test.utf8);
EXPECT_EQ(expected, converted);
}
}
@@ -172,24 +173,22 @@ TEST(UTFStringConversionsTest, ConvertUTF32ToUTF8) {
{L"\xdc01Hello", "\xef\xbf\xbdHello", false},
};
- for (size_t i = 0; i < arraysize(convert_cases); i++) {
+ for (const auto& test : convert_cases) {
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(test.success,
+ WideToUTF8(test.utf32, wcslen(test.utf32), &converted));
+ std::string expected(test.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 char16 multi16[] = {
+ 'f', 'o', 'o', '\0',
+ 'b', 'a', 'r', '\0',
+ 'b', 'a', 'z', '\0',
+ '\0'
};
static char multi[] = {
'f', 'o', 'o', '\0',
@@ -197,13 +196,14 @@ TEST(UTFStringConversionsTest, ConvertMultiString) {
'b', 'a', 'z', '\0',
'\0'
};
- std::wstring wmultistring;
- memcpy(WriteInto(&wmultistring, arraysize(wmulti)), wmulti, sizeof(wmulti));
- EXPECT_EQ(arraysize(wmulti) - 1, wmultistring.length());
+ string16 multistring16;
+ memcpy(WriteInto(&multistring16, arraysize(multi16)), multi16,
+ sizeof(multi16));
+ EXPECT_EQ(arraysize(multi16) - 1, multistring16.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);
+ const std::string& converted = UTF16ToUTF8(multistring16);
EXPECT_EQ(arraysize(multi) - 1, converted.length());
EXPECT_EQ(expected, converted);
}
diff --git a/base/sync_socket.h b/base/sync_socket.h
index 36d6bc1f59..fcf4155047 100644
--- a/base/sync_socket.h
+++ b/base/sync_socket.h
@@ -9,17 +9,20 @@
// 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 <windows.h>
-#endif
-#include <sys/types.h>
+#include <stddef.h>
#include "base/base_export.h"
#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "base/process/process_handle.h"
#include "base/synchronization/waitable_event.h"
#include "base/time/time.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+#include <sys/types.h>
#if defined(OS_POSIX)
#include "base/file_descriptor_posix.h"
@@ -83,10 +86,8 @@ class BASE_EXPORT SyncSocket {
TimeDelta timeout);
// 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();
+ // not block when called.
+ virtual size_t Peek();
// Extracts the contained handle. Used for transferring between
// processes.
diff --git a/base/sync_socket_posix.cc b/base/sync_socket_posix.cc
index 47196f4b5a..34fa5cdad4 100644
--- a/base/sync_socket_posix.cc
+++ b/base/sync_socket_posix.cc
@@ -7,6 +7,7 @@
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
+#include <stddef.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
@@ -19,6 +20,7 @@
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/threading/thread_restrictions.h"
+#include "build/build_config.h"
namespace base {
diff --git a/base/sync_socket_unittest.cc b/base/sync_socket_unittest.cc
index 7c8c97cbc1..97a1aec47d 100644
--- a/base/sync_socket_unittest.cc
+++ b/base/sync_socket_unittest.cc
@@ -2,7 +2,7 @@
// 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/macros.h"
#include "base/sync_socket.h"
#include "base/threading/simple_thread.h"
#include "base/time/time.h"
@@ -49,7 +49,7 @@ class HangingReceiveThread : public base::DelegateSimpleThread::Delegate {
void SendReceivePeek(base::SyncSocket* socket_a, base::SyncSocket* socket_b) {
int received = 0;
const int kSending = 123;
- COMPILE_ASSERT(sizeof(kSending) == sizeof(received), Invalid_Data_Size);
+ static_assert(sizeof(kSending) == sizeof(received), "invalid data size");
ASSERT_EQ(0u, socket_a->Peek());
ASSERT_EQ(0u, socket_b->Peek());
diff --git a/base/synchronization/cancellation_flag.h b/base/synchronization/cancellation_flag.h
index 0f0f08ee8f..f2f83f47da 100644
--- a/base/synchronization/cancellation_flag.h
+++ b/base/synchronization/cancellation_flag.h
@@ -5,8 +5,9 @@
#ifndef BASE_SYNCHRONIZATION_CANCELLATION_FLAG_H_
#define BASE_SYNCHRONIZATION_CANCELLATION_FLAG_H_
-#include "base/base_export.h"
#include "base/atomicops.h"
+#include "base/base_export.h"
+#include "base/macros.h"
#include "base/threading/platform_thread.h"
namespace base {
diff --git a/base/synchronization/condition_variable.h b/base/synchronization/condition_variable.h
index 5d8507d437..a41b2ba5a7 100644
--- a/base/synchronization/condition_variable.h
+++ b/base/synchronization/condition_variable.h
@@ -65,16 +65,16 @@
#ifndef BASE_SYNCHRONIZATION_CONDITION_VARIABLE_H_
#define BASE_SYNCHRONIZATION_CONDITION_VARIABLE_H_
+#include "base/base_export.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/synchronization/lock.h"
#include "build/build_config.h"
#if defined(OS_POSIX)
#include <pthread.h>
#endif
-#include "base/base_export.h"
-#include "base/basictypes.h"
-#include "base/synchronization/lock.h"
-
namespace base {
class ConditionVarImpl;
@@ -104,7 +104,7 @@ class BASE_EXPORT ConditionVariable {
#elif defined(OS_POSIX)
pthread_cond_t condition_;
pthread_mutex_t* user_mutex_;
-#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+#if DCHECK_IS_ON()
base::Lock* user_lock_; // Needed to adjust shadow lock state on wait.
#endif
diff --git a/base/synchronization/condition_variable_posix.cc b/base/synchronization/condition_variable_posix.cc
index 013284c888..d86fd180ec 100644
--- a/base/synchronization/condition_variable_posix.cc
+++ b/base/synchronization/condition_variable_posix.cc
@@ -5,18 +5,19 @@
#include "base/synchronization/condition_variable.h"
#include <errno.h>
+#include <stdint.h>
#include <sys/time.h>
-#include "base/logging.h"
#include "base/synchronization/lock.h"
#include "base/threading/thread_restrictions.h"
#include "base/time/time.h"
+#include "build/build_config.h"
namespace base {
ConditionVariable::ConditionVariable(Lock* user_lock)
: user_mutex_(user_lock->lock_.native_handle())
-#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+#if DCHECK_IS_ON()
, user_lock_(user_lock)
#endif
{
@@ -42,31 +43,45 @@ ConditionVariable::ConditionVariable(Lock* user_lock)
}
ConditionVariable::~ConditionVariable() {
+#if defined(OS_MACOSX)
+ // This hack is necessary to avoid a fatal pthreads subsystem bug in the
+ // Darwin kernel. http://crbug.com/517681.
+ {
+ base::Lock lock;
+ base::AutoLock l(lock);
+ struct timespec ts;
+ ts.tv_sec = 0;
+ ts.tv_nsec = 1;
+ pthread_cond_timedwait_relative_np(&condition_, lock.lock_.native_handle(),
+ &ts);
+ }
+#endif
+
int rv = pthread_cond_destroy(&condition_);
DCHECK_EQ(0, rv);
}
void ConditionVariable::Wait() {
base::ThreadRestrictions::AssertWaitAllowed();
-#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+#if DCHECK_IS_ON()
user_lock_->CheckHeldAndUnmark();
#endif
int rv = pthread_cond_wait(&condition_, user_mutex_);
DCHECK_EQ(0, rv);
-#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+#if DCHECK_IS_ON()
user_lock_->CheckUnheldAndMark();
#endif
}
void ConditionVariable::TimedWait(const TimeDelta& max_time) {
base::ThreadRestrictions::AssertWaitAllowed();
- int64 usecs = max_time.InMicroseconds();
+ int64_t usecs = max_time.InMicroseconds();
struct timespec relative_time;
relative_time.tv_sec = usecs / Time::kMicrosecondsPerSecond;
relative_time.tv_nsec =
(usecs % Time::kMicrosecondsPerSecond) * Time::kNanosecondsPerMicrosecond;
-#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+#if DCHECK_IS_ON()
user_lock_->CheckHeldAndUnmark();
#endif
@@ -104,7 +119,7 @@ void ConditionVariable::TimedWait(const TimeDelta& max_time) {
#endif // OS_MACOSX
DCHECK(rv == 0 || rv == ETIMEDOUT);
-#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+#if DCHECK_IS_ON()
user_lock_->CheckUnheldAndMark();
#endif
}
diff --git a/base/synchronization/condition_variable_unittest.cc b/base/synchronization/condition_variable_unittest.cc
index e63a723d00..4503922ece 100644
--- a/base/synchronization/condition_variable_unittest.cc
+++ b/base/synchronization/condition_variable_unittest.cc
@@ -20,6 +20,7 @@
#include "base/threading/thread.h"
#include "base/threading/thread_collision_warner.h"
#include "base/time/time.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
diff --git a/base/synchronization/lock.cc b/base/synchronization/lock.cc
index b1576c50c7..03297ada52 100644
--- a/base/synchronization/lock.cc
+++ b/base/synchronization/lock.cc
@@ -6,10 +6,9 @@
// is functionally a wrapper around the LockImpl class, so the only
// real intelligence in the class is in the debugging logic.
-#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
-
#include "base/synchronization/lock.h"
-#include "base/logging.h"
+
+#if DCHECK_IS_ON()
namespace base {
@@ -36,4 +35,4 @@ void Lock::CheckUnheldAndMark() {
} // namespace base
-#endif // !NDEBUG || DCHECK_ALWAYS_ON
+#endif // DCHECK_IS_ON()
diff --git a/base/synchronization/lock.h b/base/synchronization/lock.h
index f384e41472..f7dd35dccb 100644
--- a/base/synchronization/lock.h
+++ b/base/synchronization/lock.h
@@ -6,8 +6,11 @@
#define BASE_SYNCHRONIZATION_LOCK_H_
#include "base/base_export.h"
+#include "base/logging.h"
+#include "base/macros.h"
#include "base/synchronization/lock_impl.h"
#include "base/threading/platform_thread.h"
+#include "build/build_config.h"
namespace base {
@@ -16,7 +19,7 @@ namespace base {
// AssertAcquired() method.
class BASE_EXPORT Lock {
public:
-#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
+#if !DCHECK_IS_ON()
// Optimized wrapper implementation
Lock() : lock_() {}
~Lock() {}
@@ -56,7 +59,7 @@ class BASE_EXPORT Lock {
}
void AssertAcquired() const;
-#endif // NDEBUG && !DCHECK_ALWAYS_ON
+#endif // DCHECK_IS_ON()
#if defined(OS_POSIX)
// The posix implementation of ConditionVariable needs to be able
@@ -70,7 +73,7 @@ class BASE_EXPORT Lock {
#endif
private:
-#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+#if DCHECK_IS_ON()
// 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
@@ -82,7 +85,7 @@ class BASE_EXPORT Lock {
// All private data is implicitly protected by lock_.
// Be VERY careful to only access members under that lock.
base::PlatformThreadRef owning_thread_ref_;
-#endif // !NDEBUG || DCHECK_ALWAYS_ON
+#endif // DCHECK_IS_ON()
// Platform specific underlying lock implementation.
internal::LockImpl lock_;
diff --git a/base/synchronization/lock_impl.h b/base/synchronization/lock_impl.h
index 42e2f99068..ed85987b39 100644
--- a/base/synchronization/lock_impl.h
+++ b/base/synchronization/lock_impl.h
@@ -5,6 +5,8 @@
#ifndef BASE_SYNCHRONIZATION_LOCK_IMPL_H_
#define BASE_SYNCHRONIZATION_LOCK_IMPL_H_
+#include "base/base_export.h"
+#include "base/macros.h"
#include "build/build_config.h"
#if defined(OS_WIN)
@@ -13,9 +15,6 @@
#include <pthread.h>
#endif
-#include "base/base_export.h"
-#include "base/basictypes.h"
-
namespace base {
namespace internal {
diff --git a/base/synchronization/lock_unittest.cc b/base/synchronization/lock_unittest.cc
index 967efb8e92..27f335e2cc 100644
--- a/base/synchronization/lock_unittest.cc
+++ b/base/synchronization/lock_unittest.cc
@@ -7,6 +7,7 @@
#include <stdlib.h>
#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "base/threading/platform_thread.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/base/synchronization/waitable_event.h b/base/synchronization/waitable_event.h
index c35af5467f..b5d91d00b5 100644
--- a/base/synchronization/waitable_event.h
+++ b/base/synchronization/waitable_event.h
@@ -5,8 +5,11 @@
#ifndef BASE_SYNCHRONIZATION_WAITABLE_EVENT_H_
#define BASE_SYNCHRONIZATION_WAITABLE_EVENT_H_
+#include <stddef.h>
+
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
+#include "build/build_config.h"
#if defined(OS_WIN)
#include "base/win/scoped_handle.h"
diff --git a/base/synchronization/waitable_event_posix.cc b/base/synchronization/waitable_event_posix.cc
index 696ffc7a02..64d4376fe5 100644
--- a/base/synchronization/waitable_event_posix.cc
+++ b/base/synchronization/waitable_event_posix.cc
@@ -2,13 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stddef.h>
+
#include <algorithm>
#include <vector>
#include "base/logging.h"
-#include "base/synchronization/waitable_event.h"
#include "base/synchronization/condition_variable.h"
#include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event.h"
#include "base/threading/thread_restrictions.h"
// -----------------------------------------------------------------------------
diff --git a/base/synchronization/waitable_event_unittest.cc b/base/synchronization/waitable_event_unittest.cc
index be56cf171a..2930409b59 100644
--- a/base/synchronization/waitable_event_unittest.cc
+++ b/base/synchronization/waitable_event_unittest.cc
@@ -4,9 +4,12 @@
#include "base/synchronization/waitable_event.h"
+#include <stddef.h>
+
#include "base/compiler_specific.h"
#include "base/threading/platform_thread.h"
#include "base/time/time.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
diff --git a/base/sys_byteorder.h b/base/sys_byteorder.h
index 704ed568b0..ddb3f5bcda 100644
--- a/base/sys_byteorder.h
+++ b/base/sys_byteorder.h
@@ -11,28 +11,23 @@
#ifndef BASE_SYS_BYTEORDER_H_
#define BASE_SYS_BYTEORDER_H_
-#include "base/basictypes.h"
-#include "build/build_config.h"
+#include <stdint.h>
-#if defined(OS_WIN)
-#include <winsock2.h>
-#else
-#include <arpa/inet.h>
-#endif
+#include "build/build_config.h"
namespace base {
// Returns a value with all bytes in |x| swapped, i.e. reverses the endianness.
-inline uint16 ByteSwap(uint16 x) {
+inline uint16_t ByteSwap(uint16_t x) {
return ((x & 0x00ff) << 8) | ((x & 0xff00) >> 8);
}
-inline uint32 ByteSwap(uint32 x) {
+inline uint32_t ByteSwap(uint32_t x) {
return ((x & 0x000000fful) << 24) | ((x & 0x0000ff00ul) << 8) |
((x & 0x00ff0000ul) >> 8) | ((x & 0xff000000ul) >> 24);
}
-inline uint64 ByteSwap(uint64 x) {
+inline uint64_t ByteSwap(uint64_t x) {
return ((x & 0x00000000000000ffull) << 56) |
((x & 0x000000000000ff00ull) << 40) |
((x & 0x0000000000ff0000ull) << 24) |
@@ -45,21 +40,21 @@ inline uint64 ByteSwap(uint64 x) {
// Converts the bytes in |x| from host order (endianness) to little endian, and
// returns the result.
-inline uint16 ByteSwapToLE16(uint16 x) {
+inline uint16_t ByteSwapToLE16(uint16_t x) {
#if defined(ARCH_CPU_LITTLE_ENDIAN)
return x;
#else
return ByteSwap(x);
#endif
}
-inline uint32 ByteSwapToLE32(uint32 x) {
+inline uint32_t ByteSwapToLE32(uint32_t x) {
#if defined(ARCH_CPU_LITTLE_ENDIAN)
return x;
#else
return ByteSwap(x);
#endif
}
-inline uint64 ByteSwapToLE64(uint64 x) {
+inline uint64_t ByteSwapToLE64(uint64_t x) {
#if defined(ARCH_CPU_LITTLE_ENDIAN)
return x;
#else
@@ -69,21 +64,21 @@ inline uint64 ByteSwapToLE64(uint64 x) {
// Converts the bytes in |x| from network to host order (endianness), and
// returns the result.
-inline uint16 NetToHost16(uint16 x) {
+inline uint16_t NetToHost16(uint16_t x) {
#if defined(ARCH_CPU_LITTLE_ENDIAN)
return ByteSwap(x);
#else
return x;
#endif
}
-inline uint32 NetToHost32(uint32 x) {
+inline uint32_t NetToHost32(uint32_t x) {
#if defined(ARCH_CPU_LITTLE_ENDIAN)
return ByteSwap(x);
#else
return x;
#endif
}
-inline uint64 NetToHost64(uint64 x) {
+inline uint64_t NetToHost64(uint64_t x) {
#if defined(ARCH_CPU_LITTLE_ENDIAN)
return ByteSwap(x);
#else
@@ -93,21 +88,21 @@ inline uint64 NetToHost64(uint64 x) {
// Converts the bytes in |x| from host to network order (endianness), and
// returns the result.
-inline uint16 HostToNet16(uint16 x) {
+inline uint16_t HostToNet16(uint16_t x) {
#if defined(ARCH_CPU_LITTLE_ENDIAN)
return ByteSwap(x);
#else
return x;
#endif
}
-inline uint32 HostToNet32(uint32 x) {
+inline uint32_t HostToNet32(uint32_t x) {
#if defined(ARCH_CPU_LITTLE_ENDIAN)
return ByteSwap(x);
#else
return x;
#endif
}
-inline uint64 HostToNet64(uint64 x) {
+inline uint64_t HostToNet64(uint64_t x) {
#if defined(ARCH_CPU_LITTLE_ENDIAN)
return ByteSwap(x);
#else
diff --git a/base/sys_info.cc b/base/sys_info.cc
index 8640dc14ed..cebb363009 100644
--- a/base/sys_info.cc
+++ b/base/sys_info.cc
@@ -12,6 +12,7 @@
#include "base/strings/string_util.h"
#include "base/sys_info_internal.h"
#include "base/time/time.h"
+#include "build/build_config.h"
namespace base {
@@ -41,26 +42,26 @@ bool SysInfo::IsLowEndDevice() {
// Low End Device Mode will be enabled if this client is assigned to
// one of those EnabledXXX groups.
- if (StartsWithASCII(group_name, "Enabled", true))
+ if (StartsWith(group_name, "Enabled", CompareCase::SENSITIVE))
return true;
return g_lazy_low_end_device.Get().value();
}
#endif
-#if !defined(OS_MACOSX) || defined(OS_IOS)
+#if (!defined(OS_MACOSX) || defined(OS_IOS)) && !defined(OS_ANDROID)
std::string SysInfo::HardwareModelName() {
return std::string();
}
#endif
// static
-int64 SysInfo::Uptime() {
+base::TimeDelta 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;
+ int64_t uptime_in_microseconds = TimeTicks::Now().ToInternalValue();
+ return base::TimeDelta::FromMicroseconds(uptime_in_microseconds);
}
} // namespace base
diff --git a/base/sys_info.h b/base/sys_info.h
index 654d6945a3..5686dcbb49 100644
--- a/base/sys_info.h
+++ b/base/sys_info.h
@@ -5,11 +5,13 @@
#ifndef BASE_SYS_INFO_H_
#define BASE_SYS_INFO_H_
+#include <stddef.h>
+#include <stdint.h>
+
#include <map>
#include <string>
#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"
@@ -22,16 +24,16 @@ class BASE_EXPORT SysInfo {
static int NumberOfProcessors();
// Return the number of bytes of physical memory on the current machine.
- static int64 AmountOfPhysicalMemory();
+ static int64_t AmountOfPhysicalMemory();
// Return the number of bytes of current available physical memory on the
// machine.
- static int64 AmountOfAvailablePhysicalMemory();
+ static int64_t AmountOfAvailablePhysicalMemory();
// Return the number of bytes of virtual memory of this process. A return
// value of zero means that there is no limit on the available virtual
// memory.
- static int64 AmountOfVirtualMemory();
+ static int64_t AmountOfVirtualMemory();
// Return the number of megabytes of physical memory on the current machine.
static int AmountOfPhysicalMemoryMB() {
@@ -46,15 +48,15 @@ class BASE_EXPORT SysInfo {
// Return the available disk space in bytes on the volume containing |path|,
// or -1 on failure.
- static int64 AmountOfFreeDiskSpace(const FilePath& path);
+ static int64_t AmountOfFreeDiskSpace(const FilePath& path);
- // Returns system uptime in milliseconds.
- static int64 Uptime();
+ // Returns system uptime.
+ static TimeDelta Uptime();
// Returns a descriptive string for the current machine model or an empty
- // string if machime model is unknown or an error occured.
- // e.g. MacPro1,1 on Mac.
- // Only implemented on OS X, will return an empty string on other platforms.
+ // string if the machine model is unknown or an error occured.
+ // e.g. "MacPro1,1" on Mac, or "Nexus 5" on Android. Only implemented on OS X,
+ // Android, and Chrome OS. This returns an empty string on other platforms.
static std::string HardwareModelName();
// Returns the name of the host operating system.
@@ -71,9 +73,9 @@ class BASE_EXPORT SysInfo {
// 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);
+ static void OperatingSystemVersionNumbers(int32_t* major_version,
+ int32_t* minor_version,
+ int32_t* bugfix_version);
// Returns the architecture of the running operating system.
// Exact return value may differ across platforms.
@@ -94,7 +96,7 @@ class BASE_EXPORT SysInfo {
#if defined(OS_POSIX) && !defined(OS_MACOSX)
// Returns the maximum SysV shared memory segment size, or zero if there is no
// limit.
- static uint64 MaxSharedMemorySize();
+ static uint64_t MaxSharedMemorySize();
#endif // defined(OS_POSIX) && !defined(OS_MACOSX)
#if defined(OS_CHROMEOS)
@@ -129,9 +131,6 @@ class BASE_EXPORT SysInfo {
// 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)
diff --git a/base/sys_info_chromeos.cc b/base/sys_info_chromeos.cc
index 9915055996..e35bd0a590 100644
--- a/base/sys_info_chromeos.cc
+++ b/base/sys_info_chromeos.cc
@@ -4,12 +4,15 @@
#include "base/sys_info.h"
-#include "base/basictypes.h"
+#include <stddef.h>
+#include <stdint.h>
+
#include "base/environment.h"
#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/lazy_instance.h"
+#include "base/macros.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_split.h"
@@ -90,9 +93,9 @@ class ChromeOSVersionInfo {
return true;
}
- void GetVersionNumbers(int32* major_version,
- int32* minor_version,
- int32* bugfix_version) {
+ void GetVersionNumbers(int32_t* major_version,
+ int32_t* minor_version,
+ int32_t* bugfix_version) {
*major_version = major_version_;
*minor_version = minor_version_;
*bugfix_version = bugfix_version_;
@@ -154,9 +157,9 @@ class ChromeOSVersionInfo {
Time lsb_release_time_;
SysInfo::LsbReleaseMap lsb_release_map_;
- int32 major_version_;
- int32 minor_version_;
- int32 bugfix_version_;
+ int32_t major_version_;
+ int32_t minor_version_;
+ int32_t bugfix_version_;
bool is_running_on_chromeos_;
};
@@ -170,9 +173,9 @@ ChromeOSVersionInfo& GetChromeOSVersionInfo() {
} // namespace
// static
-void SysInfo::OperatingSystemVersionNumbers(int32* major_version,
- int32* minor_version,
- int32* bugfix_version) {
+void SysInfo::OperatingSystemVersionNumbers(int32_t* major_version,
+ int32_t* minor_version,
+ int32_t* bugfix_version) {
return GetChromeOSVersionInfo().GetVersionNumbers(
major_version, minor_version, bugfix_version);
}
diff --git a/base/sys_info_internal.h b/base/sys_info_internal.h
index e7674d5c09..a1792191f5 100644
--- a/base/sys_info_internal.h
+++ b/base/sys_info_internal.h
@@ -5,7 +5,7 @@
#ifndef BASE_SYS_INFO_INTERNAL_H_
#define BASE_SYS_INFO_INTERNAL_H_
-#include "base/basictypes.h"
+#include "base/macros.h"
namespace base {
diff --git a/base/sys_info_linux.cc b/base/sys_info_linux.cc
index 1bbfe9c604..8e1f533bed 100644
--- a/base/sys_info_linux.cc
+++ b/base/sys_info_linux.cc
@@ -4,6 +4,9 @@
#include "base/sys_info.h"
+#include <stddef.h>
+#include <stdint.h>
+
#include <limits>
#include "base/files/file_util.h"
@@ -12,24 +15,25 @@
#include "base/numerics/safe_conversions.h"
#include "base/strings/string_number_conversions.h"
#include "base/sys_info_internal.h"
+#include "build/build_config.h"
namespace {
-int64 AmountOfMemory(int pages_name) {
+int64_t 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<int64>(pages) * page_size;
+ return static_cast<int64_t>(pages) * page_size;
}
-int64 AmountOfPhysicalMemory() {
+int64_t AmountOfPhysicalMemory() {
return AmountOfMemory(_SC_PHYS_PAGES);
}
-uint64 MaxSharedMemorySize() {
+uint64_t MaxSharedMemorySize() {
std::string contents;
base::ReadFileToString(base::FilePath("/proc/sys/kernel/shmmax"), &contents);
DCHECK(!contents.empty());
@@ -37,7 +41,7 @@ uint64 MaxSharedMemorySize() {
contents.erase(contents.length() - 1);
}
- uint64 limit;
+ uint64_t limit;
if (!base::StringToUint64(contents, &limit)) {
limit = 0;
}
@@ -46,10 +50,10 @@ uint64 MaxSharedMemorySize() {
}
base::LazyInstance<
- base::internal::LazySysInfoValue<int64, AmountOfPhysicalMemory> >::Leaky
+ base::internal::LazySysInfoValue<int64_t, AmountOfPhysicalMemory>>::Leaky
g_lazy_physical_memory = LAZY_INSTANCE_INITIALIZER;
base::LazyInstance<
- base::internal::LazySysInfoValue<uint64, MaxSharedMemorySize> >::Leaky
+ base::internal::LazySysInfoValue<uint64_t, MaxSharedMemorySize>>::Leaky
g_lazy_max_shared_memory = LAZY_INSTANCE_INITIALIZER;
} // namespace
@@ -57,17 +61,17 @@ base::LazyInstance<
namespace base {
// static
-int64 SysInfo::AmountOfAvailablePhysicalMemory() {
+int64_t SysInfo::AmountOfAvailablePhysicalMemory() {
return AmountOfMemory(_SC_AVPHYS_PAGES);
}
// static
-int64 SysInfo::AmountOfPhysicalMemory() {
+int64_t SysInfo::AmountOfPhysicalMemory() {
return g_lazy_physical_memory.Get().value();
}
// static
-uint64 SysInfo::MaxSharedMemorySize() {
+uint64_t SysInfo::MaxSharedMemorySize() {
return g_lazy_max_shared_memory.Get().value();
}
diff --git a/base/sys_info_mac.cc b/base/sys_info_mac.cc
index 18df62482e..ff1ec5c1e6 100644
--- a/base/sys_info_mac.cc
+++ b/base/sys_info_mac.cc
@@ -8,11 +8,14 @@
#include <CoreServices/CoreServices.h>
#include <mach/mach_host.h>
#include <mach/mach_init.h>
+#include <stddef.h>
+#include <stdint.h>
#include <sys/sysctl.h>
#include <sys/types.h>
#include "base/logging.h"
#include "base/mac/scoped_mach_port.h"
+#include "base/macros.h"
#include "base/strings/stringprintf.h"
namespace base {
@@ -24,15 +27,15 @@ std::string SysInfo::OperatingSystemName() {
// static
std::string SysInfo::OperatingSystemVersion() {
- int32 major, minor, bugfix;
+ int32_t 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) {
+void SysInfo::OperatingSystemVersionNumbers(int32_t* major_version,
+ int32_t* minor_version,
+ int32_t* bugfix_version) {
Gestalt(gestaltSystemVersionMajor,
reinterpret_cast<SInt32*>(major_version));
Gestalt(gestaltSystemVersionMinor,
@@ -42,11 +45,11 @@ void SysInfo::OperatingSystemVersionNumbers(int32* major_version,
}
// static
-int64 SysInfo::AmountOfPhysicalMemory() {
+int64_t SysInfo::AmountOfPhysicalMemory() {
struct host_basic_info hostinfo;
mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT;
base::mac::ScopedMachSendRight host(mach_host_self());
- int result = host_info(host,
+ int result = host_info(host.get(),
HOST_BASIC_INFO,
reinterpret_cast<host_info_t>(&hostinfo),
&count);
@@ -55,11 +58,11 @@ int64 SysInfo::AmountOfPhysicalMemory() {
return 0;
}
DCHECK_EQ(HOST_BASIC_INFO_COUNT, count);
- return static_cast<int64>(hostinfo.max_mem);
+ return static_cast<int64_t>(hostinfo.max_mem);
}
// static
-int64 SysInfo::AmountOfAvailablePhysicalMemory() {
+int64_t SysInfo::AmountOfAvailablePhysicalMemory() {
base::mac::ScopedMachSendRight host(mach_host_self());
vm_statistics_data_t vm_info;
mach_msg_type_number_t count = HOST_VM_INFO_COUNT;
@@ -72,8 +75,8 @@ int64 SysInfo::AmountOfAvailablePhysicalMemory() {
return 0;
}
- return static_cast<int64>(
- vm_info.free_count - vm_info.speculative_count) * PAGE_SIZE;
+ return static_cast<int64_t>(vm_info.free_count - vm_info.speculative_count) *
+ PAGE_SIZE;
}
// static
diff --git a/base/sys_info_posix.cc b/base/sys_info_posix.cc
index 3d49bf94da..85ae039118 100644
--- a/base/sys_info_posix.cc
+++ b/base/sys_info_posix.cc
@@ -5,19 +5,21 @@
#include "base/sys_info.h"
#include <errno.h>
+#include <stddef.h>
+#include <stdint.h>
#include <string.h>
#include <sys/param.h>
#include <sys/resource.h>
#include <sys/utsname.h>
#include <unistd.h>
-#include "base/basictypes.h"
#include "base/files/file_util.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
#include "base/sys_info_internal.h"
#include "base/threading/thread_restrictions.h"
+#include "build/build_config.h"
#if defined(OS_ANDROID)
#include <sys/vfs.h>
@@ -57,7 +59,7 @@ base::LazyInstance<
g_lazy_number_of_processors = LAZY_INSTANCE_INITIALIZER;
#endif
-int64 AmountOfVirtualMemory() {
+int64_t AmountOfVirtualMemory() {
struct rlimit limit;
int result = getrlimit(RLIMIT_DATA, &limit);
if (result != 0) {
@@ -68,7 +70,7 @@ int64 AmountOfVirtualMemory() {
}
base::LazyInstance<
- base::internal::LazySysInfoValue<int64, AmountOfVirtualMemory> >::Leaky
+ base::internal::LazySysInfoValue<int64_t, AmountOfVirtualMemory>>::Leaky
g_lazy_virtual_memory = LAZY_INSTANCE_INITIALIZER;
} // namespace
@@ -82,18 +84,18 @@ int SysInfo::NumberOfProcessors() {
#endif
// static
-int64 SysInfo::AmountOfVirtualMemory() {
+int64_t SysInfo::AmountOfVirtualMemory() {
return g_lazy_virtual_memory.Get().value();
}
// static
-int64 SysInfo::AmountOfFreeDiskSpace(const FilePath& path) {
+int64_t 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<int64>(stats.f_bavail) * stats.f_frsize;
+ return static_cast<int64_t>(stats.f_bavail) * stats.f_frsize;
}
#if !defined(OS_MACOSX) && !defined(OS_ANDROID)
diff --git a/base/sys_info_unittest.cc b/base/sys_info_unittest.cc
index 15ae0989b1..3f284ba868 100644
--- a/base/sys_info_unittest.cc
+++ b/base/sys_info_unittest.cc
@@ -2,11 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stdint.h>
+
#include "base/environment.h"
#include "base/files/file_util.h"
#include "base/sys_info.h"
#include "base/threading/platform_thread.h"
#include "base/time/time.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
@@ -43,9 +46,9 @@ TEST_F(SysInfoTest, AmountOfFreeDiskSpace) {
#if defined(OS_WIN) || defined(OS_MACOSX)
TEST_F(SysInfoTest, OperatingSystemVersionNumbers) {
- int32 os_major_version = -1;
- int32 os_minor_version = -1;
- int32 os_bugfix_version = -1;
+ int32_t os_major_version = -1;
+ int32_t os_minor_version = -1;
+ int32_t os_bugfix_version = -1;
base::SysInfo::OperatingSystemVersionNumbers(&os_major_version,
&os_minor_version,
&os_bugfix_version);
@@ -56,13 +59,13 @@ TEST_F(SysInfoTest, OperatingSystemVersionNumbers) {
#endif
TEST_F(SysInfoTest, Uptime) {
- int64 up_time_1 = base::SysInfo::Uptime();
+ base::TimeDelta 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);
+ base::TimeDelta up_time_2 = base::SysInfo::Uptime();
+ EXPECT_GT(up_time_1.InMicroseconds(), 0);
+ EXPECT_GT(up_time_2.InMicroseconds(), up_time_1.InMicroseconds());
}
#if defined(OS_MACOSX) && !defined(OS_IOS)
@@ -75,9 +78,9 @@ TEST_F(SysInfoTest, HardwareModelName) {
#if defined(OS_CHROMEOS)
TEST_F(SysInfoTest, GoogleChromeOSVersionNumbers) {
- int32 os_major_version = -1;
- int32 os_minor_version = -1;
- int32 os_bugfix_version = -1;
+ int32_t os_major_version = -1;
+ int32_t os_minor_version = -1;
+ int32_t os_bugfix_version = -1;
const char kLsbRelease[] =
"FOO=1234123.34.5\n"
"CHROMEOS_RELEASE_VERSION=1.2.3.4\n";
@@ -91,9 +94,9 @@ TEST_F(SysInfoTest, GoogleChromeOSVersionNumbers) {
}
TEST_F(SysInfoTest, GoogleChromeOSVersionNumbersFirst) {
- int32 os_major_version = -1;
- int32 os_minor_version = -1;
- int32 os_bugfix_version = -1;
+ int32_t os_major_version = -1;
+ int32_t os_minor_version = -1;
+ int32_t os_bugfix_version = -1;
const char kLsbRelease[] =
"CHROMEOS_RELEASE_VERSION=1.2.3.4\n"
"FOO=1234123.34.5\n";
@@ -107,9 +110,9 @@ TEST_F(SysInfoTest, GoogleChromeOSVersionNumbersFirst) {
}
TEST_F(SysInfoTest, GoogleChromeOSNoVersionNumbers) {
- int32 os_major_version = -1;
- int32 os_minor_version = -1;
- int32 os_bugfix_version = -1;
+ int32_t os_major_version = -1;
+ int32_t os_minor_version = -1;
+ int32_t os_bugfix_version = -1;
const char kLsbRelease[] = "FOO=1234123.34.5\n";
base::SysInfo::SetChromeOSVersionInfoForTest(kLsbRelease, base::Time());
base::SysInfo::OperatingSystemVersionNumbers(&os_major_version,
diff --git a/base/task/cancelable_task_tracker.cc b/base/task/cancelable_task_tracker.cc
index 96aadc74c6..375ff8b63a 100644
--- a/base/task/cancelable_task_tracker.cc
+++ b/base/task/cancelable_task_tracker.cc
@@ -4,6 +4,8 @@
#include "base/task/cancelable_task_tracker.h"
+#include <stddef.h>
+
#include <utility>
#include "base/bind.h"
@@ -92,7 +94,7 @@ CancelableTaskTracker::TaskId CancelableTaskTracker::PostTaskAndReply(
CancellationFlag* flag = new CancellationFlag();
TaskId id = next_id_;
- next_id_++; // int64 is big enough that we ignore the potential overflow.
+ next_id_++; // int64_t is big enough that we ignore the potential overflow.
const Closure& untrack_closure =
Bind(&CancelableTaskTracker::Untrack, weak_factory_.GetWeakPtr(), id);
@@ -117,7 +119,7 @@ CancelableTaskTracker::TaskId CancelableTaskTracker::NewTrackedTaskId(
DCHECK(base::ThreadTaskRunnerHandle::IsSet());
TaskId id = next_id_;
- next_id_++; // int64 is big enough that we ignore the potential overflow.
+ next_id_++; // int64_t is big enough that we ignore the potential overflow.
// Will be deleted by |untrack_and_delete_flag| after Untrack().
CancellationFlag* flag = new CancellationFlag();
diff --git a/base/task/cancelable_task_tracker.h b/base/task/cancelable_task_tracker.h
index b8a8b70e33..86b5a45845 100644
--- a/base/task/cancelable_task_tracker.h
+++ b/base/task/cancelable_task_tracker.h
@@ -36,10 +36,12 @@
#ifndef BASE_TASK_CANCELABLE_TASK_TRACKER_H_
#define BASE_TASK_CANCELABLE_TASK_TRACKER_H_
+#include <stdint.h>
+
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/callback.h"
#include "base/containers/hash_tables.h"
+#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/task_runner_util.h"
#include "base/threading/thread_checker.h"
@@ -56,7 +58,7 @@ class TaskRunner;
class BASE_EXPORT CancelableTaskTracker {
public:
// All values except kBadTaskId are valid.
- typedef int64 TaskId;
+ typedef int64_t TaskId;
static const TaskId kBadTaskId;
typedef base::Callback<bool()> IsCanceledCallback;
diff --git a/base/task_runner.h b/base/task_runner.h
index 7d07b8ceb0..6dd82ccaca 100644
--- a/base/task_runner.h
+++ b/base/task_runner.h
@@ -5,8 +5,9 @@
#ifndef BASE_TASK_RUNNER_H_
#define BASE_TASK_RUNNER_H_
+#include <stddef.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"
@@ -104,7 +105,7 @@ class BASE_EXPORT TaskRunner
// public:
// void GetData() {
// scoped_refptr<DataBuffer> buffer = new DataBuffer();
- // target_thread_.message_loop_proxy()->PostTaskAndReply(
+ // target_thread_.task_runner()->PostTaskAndReply(
// FROM_HERE,
// base::Bind(&DataBuffer::AddData, buffer),
// base::Bind(&DataLoader::OnDataReceived, AsWeakPtr(), buffer));
diff --git a/base/task_runner_util.h b/base/task_runner_util.h
index b6dd0f36d6..da088db2a2 100644
--- a/base/task_runner_util.h
+++ b/base/task_runner_util.h
@@ -47,7 +47,7 @@ void ReplyAdapter(const Callback<void(ReplyArgType)>& callback,
// PostTaskAndReplyWithResult as in this example:
//
// PostTaskAndReplyWithResult(
-// target_thread_.message_loop_proxy(),
+// target_thread_.task_runner(),
// FROM_HERE,
// Bind(&DoWorkAndReturn),
// Bind(&Callback));
diff --git a/base/task_runner_util_unittest.cc b/base/task_runner_util_unittest.cc
index 8245cfcdc5..0a4f22e5ae 100644
--- a/base/task_runner_util_unittest.cc
+++ b/base/task_runner_util_unittest.cc
@@ -4,6 +4,8 @@
#include "base/task_runner_util.h"
+#include <utility>
+
#include "base/bind.h"
#include "base/location.h"
#include "base/run_loop.h"
@@ -40,7 +42,7 @@ scoped_ptr<Foo> CreateFoo() {
void ExpectFoo(scoped_ptr<Foo> foo) {
EXPECT_TRUE(foo.get());
- scoped_ptr<Foo> local_foo(foo.Pass());
+ scoped_ptr<Foo> local_foo(std::move(foo));
EXPECT_TRUE(local_foo.get());
EXPECT_FALSE(foo.get());
}
@@ -58,7 +60,7 @@ scoped_ptr<Foo, FooDeleter> CreateScopedFoo() {
void ExpectScopedFoo(scoped_ptr<Foo, FooDeleter> foo) {
EXPECT_TRUE(foo.get());
- scoped_ptr<Foo, FooDeleter> local_foo(foo.Pass());
+ scoped_ptr<Foo, FooDeleter> local_foo(std::move(foo));
EXPECT_TRUE(local_foo.get());
EXPECT_FALSE(foo.get());
}
diff --git a/base/template_util.h b/base/template_util.h
index 83fa322a67..d58807a77c 100644
--- a/base/template_util.h
+++ b/base/template_util.h
@@ -5,7 +5,7 @@
#ifndef BASE_TEMPLATE_UTIL_H_
#define BASE_TEMPLATE_UTIL_H_
-#include <cstddef> // For size_t.
+#include <stddef.h>
#include "build/build_config.h"
@@ -117,12 +117,6 @@ struct is_class
sizeof(internal::YesType)> {
};
-template<bool B, class T = void>
-struct enable_if {};
-
-template<class T>
-struct enable_if<true, T> { typedef T type; };
-
} // namespace base
#endif // BASE_TEMPLATE_UTIL_H_
diff --git a/base/template_util_unittest.cc b/base/template_util_unittest.cc
index 3ec3887154..b960ab1cea 100644
--- a/base/template_util_unittest.cc
+++ b/base/template_util_unittest.cc
@@ -4,7 +4,6 @@
#include "base/template_util.h"
-#include "base/basictypes.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
@@ -18,23 +17,24 @@ class Parent {};
class Child : public Parent {};
// is_pointer<Type>
-COMPILE_ASSERT(!is_pointer<int>::value, IsPointer);
-COMPILE_ASSERT(!is_pointer<int&>::value, IsPointer);
-COMPILE_ASSERT(is_pointer<int*>::value, IsPointer);
-COMPILE_ASSERT(is_pointer<const int*>::value, IsPointer);
+static_assert(!is_pointer<int>::value, "IsPointer");
+static_assert(!is_pointer<int&>::value, "IsPointer");
+static_assert(is_pointer<int*>::value, "IsPointer");
+static_assert(is_pointer<const int*>::value, "IsPointer");
// is_array<Type>
-COMPILE_ASSERT(!is_array<int>::value, IsArray);
-COMPILE_ASSERT(!is_array<int*>::value, IsArray);
-COMPILE_ASSERT(!is_array<int(*)[3]>::value, IsArray);
-COMPILE_ASSERT(is_array<int[]>::value, IsArray);
-COMPILE_ASSERT(is_array<const int[]>::value, IsArray);
-COMPILE_ASSERT(is_array<int[3]>::value, IsArray);
+static_assert(!is_array<int>::value, "IsArray");
+static_assert(!is_array<int*>::value, "IsArray");
+static_assert(!is_array<int (*)[3]>::value, "IsArray");
+static_assert(is_array<int[]>::value, "IsArray");
+static_assert(is_array<const int[]>::value, "IsArray");
+static_assert(is_array<int[3]>::value, "IsArray");
// is_non_const_reference<Type>
-COMPILE_ASSERT(!is_non_const_reference<int>::value, IsNonConstReference);
-COMPILE_ASSERT(!is_non_const_reference<const int&>::value, IsNonConstReference);
-COMPILE_ASSERT(is_non_const_reference<int&>::value, IsNonConstReference);
+static_assert(!is_non_const_reference<int>::value, "IsNonConstReference");
+static_assert(!is_non_const_reference<const int&>::value,
+ "IsNonConstReference");
+static_assert(is_non_const_reference<int&>::value, "IsNonConstReference");
// is_convertible<From, To>
@@ -44,66 +44,64 @@ COMPILE_ASSERT(is_non_const_reference<int&>::value, IsNonConstReference);
// (is_convertible < Child), (Parent > ::value)
//
// Silly C++.
-COMPILE_ASSERT( (is_convertible<Child, Parent>::value), IsConvertible);
-COMPILE_ASSERT(!(is_convertible<Parent, Child>::value), IsConvertible);
-COMPILE_ASSERT(!(is_convertible<Parent, AStruct>::value), IsConvertible);
-COMPILE_ASSERT( (is_convertible<int, double>::value), IsConvertible);
-COMPILE_ASSERT( (is_convertible<int*, void*>::value), IsConvertible);
-COMPILE_ASSERT(!(is_convertible<void*, int*>::value), IsConvertible);
+static_assert((is_convertible<Child, Parent>::value), "IsConvertible");
+static_assert(!(is_convertible<Parent, Child>::value), "IsConvertible");
+static_assert(!(is_convertible<Parent, AStruct>::value), "IsConvertible");
+static_assert((is_convertible<int, double>::value), "IsConvertible");
+static_assert((is_convertible<int*, void*>::value), "IsConvertible");
+static_assert(!(is_convertible<void*, int*>::value), "IsConvertible");
// Array types are an easy corner case. Make sure to test that
// it does indeed compile.
-COMPILE_ASSERT(!(is_convertible<int[10], double>::value), IsConvertible);
-COMPILE_ASSERT(!(is_convertible<double, int[10]>::value), IsConvertible);
-COMPILE_ASSERT( (is_convertible<int[10], int*>::value), IsConvertible);
+static_assert(!(is_convertible<int[10], double>::value), "IsConvertible");
+static_assert(!(is_convertible<double, int[10]>::value), "IsConvertible");
+static_assert((is_convertible<int[10], int*>::value), "IsConvertible");
// is_same<Type1, Type2>
-COMPILE_ASSERT(!(is_same<Child, Parent>::value), IsSame);
-COMPILE_ASSERT(!(is_same<Parent, Child>::value), IsSame);
-COMPILE_ASSERT( (is_same<Parent, Parent>::value), IsSame);
-COMPILE_ASSERT( (is_same<int*, int*>::value), IsSame);
-COMPILE_ASSERT( (is_same<int, int>::value), IsSame);
-COMPILE_ASSERT( (is_same<void, void>::value), IsSame);
-COMPILE_ASSERT(!(is_same<int, double>::value), IsSame);
-
+static_assert(!(is_same<Child, Parent>::value), "IsSame");
+static_assert(!(is_same<Parent, Child>::value), "IsSame");
+static_assert((is_same<Parent, Parent>::value), "IsSame");
+static_assert((is_same<int*, int*>::value), "IsSame");
+static_assert((is_same<int, int>::value), "IsSame");
+static_assert((is_same<void, void>::value), "IsSame");
+static_assert(!(is_same<int, double>::value), "IsSame");
// is_class<Type>
-COMPILE_ASSERT(is_class<AStruct>::value, IsClass);
-COMPILE_ASSERT(is_class<AClass>::value, IsClass);
-COMPILE_ASSERT(!is_class<AnEnum>::value, IsClass);
-COMPILE_ASSERT(!is_class<int>::value, IsClass);
-COMPILE_ASSERT(!is_class<char*>::value, IsClass);
-COMPILE_ASSERT(!is_class<int&>::value, IsClass);
-COMPILE_ASSERT(!is_class<char[3]>::value, IsClass);
-
-
-COMPILE_ASSERT(!is_member_function_pointer<int>::value,
- IsMemberFunctionPointer);
-COMPILE_ASSERT(!is_member_function_pointer<int*>::value,
- IsMemberFunctionPointer);
-COMPILE_ASSERT(!is_member_function_pointer<void*>::value,
- IsMemberFunctionPointer);
-COMPILE_ASSERT(!is_member_function_pointer<AStruct>::value,
- IsMemberFunctionPointer);
-COMPILE_ASSERT(!is_member_function_pointer<AStruct*>::value,
- IsMemberFunctionPointer);
-COMPILE_ASSERT(!is_member_function_pointer<void(*)()>::value,
- IsMemberFunctionPointer);
-COMPILE_ASSERT(!is_member_function_pointer<int(*)(int)>::value,
- IsMemberFunctionPointer);
-COMPILE_ASSERT(!is_member_function_pointer<int(*)(int, int)>::value,
- IsMemberFunctionPointer);
-
-COMPILE_ASSERT(is_member_function_pointer<void (AStruct::*)()>::value,
- IsMemberFunctionPointer);
-COMPILE_ASSERT(is_member_function_pointer<void (AStruct::*)(int)>::value,
- IsMemberFunctionPointer);
-COMPILE_ASSERT(is_member_function_pointer<int (AStruct::*)(int)>::value,
- IsMemberFunctionPointer);
-COMPILE_ASSERT(is_member_function_pointer<int (AStruct::*)(int) const>::value,
- IsMemberFunctionPointer);
-COMPILE_ASSERT(is_member_function_pointer<int (AStruct::*)(int, int)>::value,
- IsMemberFunctionPointer);
+static_assert(is_class<AStruct>::value, "IsClass");
+static_assert(is_class<AClass>::value, "IsClass");
+static_assert(!is_class<AnEnum>::value, "IsClass");
+static_assert(!is_class<int>::value, "IsClass");
+static_assert(!is_class<char*>::value, "IsClass");
+static_assert(!is_class<int&>::value, "IsClass");
+static_assert(!is_class<char[3]>::value, "IsClass");
+
+static_assert(!is_member_function_pointer<int>::value,
+ "IsMemberFunctionPointer");
+static_assert(!is_member_function_pointer<int*>::value,
+ "IsMemberFunctionPointer");
+static_assert(!is_member_function_pointer<void*>::value,
+ "IsMemberFunctionPointer");
+static_assert(!is_member_function_pointer<AStruct>::value,
+ "IsMemberFunctionPointer");
+static_assert(!is_member_function_pointer<AStruct*>::value,
+ "IsMemberFunctionPointer");
+static_assert(!is_member_function_pointer<void (*)()>::value,
+ "IsMemberFunctionPointer");
+static_assert(!is_member_function_pointer<int (*)(int)>::value,
+ "IsMemberFunctionPointer");
+static_assert(!is_member_function_pointer<int (*)(int, int)>::value,
+ "IsMemberFunctionPointer");
+
+static_assert(is_member_function_pointer<void (AStruct::*)()>::value,
+ "IsMemberFunctionPointer");
+static_assert(is_member_function_pointer<void (AStruct::*)(int)>::value,
+ "IsMemberFunctionPointer");
+static_assert(is_member_function_pointer<int (AStruct::*)(int)>::value,
+ "IsMemberFunctionPointer");
+static_assert(is_member_function_pointer<int (AStruct::*)(int) const>::value,
+ "IsMemberFunctionPointer");
+static_assert(is_member_function_pointer<int (AStruct::*)(int, int)>::value,
+ "IsMemberFunctionPointer");
} // namespace
} // namespace base
diff --git a/base/test/BUILD.gn b/base/test/BUILD.gn
index a8ae0cfb73..463f343707 100644
--- a/base/test/BUILD.gn
+++ b/base/test/BUILD.gn
@@ -3,6 +3,7 @@
# found in the LICENSE file.
import("//build/config/ui.gni")
+import("//build/config/nacl/config.gni")
if (is_android) {
import("//build/config/android/rules.gni")
@@ -27,10 +28,6 @@ source_set("test_support") {
# TODO http://crbug.com/412064 enable this flag all the time.
testonly = !is_component_build
sources = [
- "expectations/expectation.cc",
- "expectations/expectation.h",
- "expectations/parser.cc",
- "expectations/parser.h",
"gtest_util.cc",
"gtest_util.h",
"gtest_xml_unittest_result_printer.cc",
@@ -39,15 +36,12 @@ source_set("test_support") {
"gtest_xml_util.h",
"histogram_tester.cc",
"histogram_tester.h",
- "launcher/test_launcher.cc",
- "launcher/test_launcher.h",
+ "ios/wait_util.h",
+ "ios/wait_util.mm",
"launcher/test_result.cc",
"launcher/test_result.h",
- "launcher/test_results_tracker.cc",
"launcher/test_results_tracker.h",
- "launcher/unit_test_launcher.cc",
"launcher/unit_test_launcher.h",
- "launcher/unit_test_launcher_ios.cc",
"mock_chrome_application_mac.h",
"mock_chrome_application_mac.mm",
"mock_devices_changed_observer.cc",
@@ -56,9 +50,7 @@ source_set("test_support") {
"mock_entropy_provider.h",
"mock_log.cc",
"mock_log.h",
- "multiprocess_test.cc",
"multiprocess_test.h",
- "multiprocess_test_android.cc",
"null_task_runner.cc",
"null_task_runner.h",
"opaque_ref_counted.cc",
@@ -128,18 +120,39 @@ source_set("test_support") {
"values_test_util.h",
]
+ if (is_ios) {
+ sources += [ "launcher/unit_test_launcher_ios.cc" ]
+ } else if (!is_nacl_nonsfi) {
+ sources += [
+ "launcher/test_launcher.cc",
+ "launcher/test_launcher.h",
+ "launcher/test_results_tracker.cc",
+ "launcher/unit_test_launcher.cc",
+ "multiprocess_test.cc",
+ "multiprocess_test_android.cc",
+ ]
+ }
+
+ configs += [ "//build/config:precompiled_headers" ]
+
+ data = [
+ # The isolate needs this script for setting up the test. It's not actually
+ # needed to run this target locally.
+ "//testing/test_env.py",
+ ]
+
public_deps = [
":test_config",
"//base",
- "//base:i18n",
"//base:base_static",
+ "//base:i18n",
]
deps = [
"//base/third_party/dynamic_annotations",
"//testing/gmock",
"//testing/gtest",
- "//third_party/libxml",
"//third_party/icu:icuuc",
+ "//third_party/libxml",
]
if (!is_posix) {
@@ -148,19 +161,47 @@ source_set("test_support") {
"scoped_locale.h",
]
}
- if (is_ios) {
- # iOS uses its own unit test launcher.
- sources -= [ "launcher/unit_test_launcher.cc" ]
- # Pull in specific Mac files for iOS (which have been filtered out
- # by file name rules).
+ if (is_ios) {
set_sources_assignment_filter([])
sources += [ "test_file_util_mac.cc" ]
+ set_sources_assignment_filter(sources_assignment_filter)
}
if (is_android) {
deps += [ ":base_unittests_jni_headers" ]
}
+
+ if (is_nacl_nonsfi) {
+ sources += [
+ "launcher/test_launcher.h",
+ "launcher/test_result.h",
+ "launcher/unit_test_launcher.h",
+ "launcher/unit_test_launcher_nacl_nonsfi.cc",
+ ]
+ sources -= [
+ "gtest_xml_util.cc",
+ "gtest_xml_util.h",
+ "perf_test_suite.cc",
+ "perf_test_suite.h",
+ "scoped_path_override.cc",
+ "scoped_path_override.h",
+ "test_discardable_memory_allocator.cc",
+ "test_discardable_memory_allocator.h",
+ "test_file_util.cc",
+ "test_file_util.h",
+ "test_file_util_posix.cc",
+ "test_suite.cc",
+ "test_suite.h",
+ "trace_to_file.cc",
+ "trace_to_file.h",
+ ]
+ public_deps -= [ "//base:i18n" ]
+ deps -= [
+ "//third_party/icu:icuuc",
+ "//third_party/libxml",
+ ]
+ }
}
config("perf_test_config") {
@@ -181,6 +222,17 @@ source_set("test_support_perf") {
public_configs = [ ":perf_test_config" ]
}
+source_set("test_launcher_nacl_nonsfi") {
+ testonly = true
+ sources = [
+ "launcher/test_launcher_nacl_nonsfi.cc",
+ "launcher/test_launcher_nacl_nonsfi.h",
+ ]
+ deps = [
+ ":test_support",
+ ]
+}
+
source_set("run_all_unittests") {
testonly = true
sources = [
@@ -199,6 +251,7 @@ if (is_linux) {
]
deps = [
"//base",
+ "//build/config/sanitizers:deps",
]
}
}
diff --git a/base/test/android/OWNERS b/base/test/android/OWNERS
deleted file mode 100644
index 3c9067cf06..0000000000
--- a/base/test/android/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-feng@chromium.org
-nyquist@chromium.org
-yfriedman@chromium.org
diff --git a/base/test/android/java/src/org/chromium/base/ContentUriTestUtils.java b/base/test/android/java/src/org/chromium/base/ContentUriTestUtils.java
deleted file mode 100644
index 4a1613b4f6..0000000000
--- a/base/test/android/java/src/org/chromium/base/ContentUriTestUtils.java
+++ /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.
-
-package org.chromium.base;
-
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.Cursor;
-import android.net.Uri;
-import android.provider.MediaStore;
-
-/**
- * Utilities for testing operations on content URI.
- */
-public class ContentUriTestUtils {
- /**
- * Insert an image into the MediaStore, and return the content URI. If the
- * image already exists in the MediaStore, just retrieve the URI.
- *
- * @param context Application context.
- * @param path Path to the image file.
- * @return Content URI of the image.
- */
- @CalledByNative
- private static String insertImageIntoMediaStore(Context context, String path) {
- // Check whether the content URI exists.
- Cursor c = context.getContentResolver().query(
- MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
- new String[] { MediaStore.Video.VideoColumns._ID },
- MediaStore.Images.Media.DATA + " LIKE ?",
- new String[] { path },
- null);
- if (c != null && c.getCount() > 0) {
- c.moveToFirst();
- int id = c.getInt(0);
- return Uri.withAppendedPath(
- MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "" + id).toString();
- }
-
- // Insert the content URI into MediaStore.
- ContentValues values = new ContentValues();
- values.put(MediaStore.MediaColumns.DATA, path);
- Uri uri = context.getContentResolver().insert(
- MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
- return uri.toString();
- }
-}
diff --git a/base/test/android/java/src/org/chromium/base/TestUiThread.java b/base/test/android/java/src/org/chromium/base/TestUiThread.java
deleted file mode 100644
index 77f96606ad..0000000000
--- a/base/test/android/java/src/org/chromium/base/TestUiThread.java
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2015 The Chromium 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.Looper;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import javax.annotation.concurrent.ThreadSafe;
-
-/**
- * Set up a thread as the Chromium UI Thread, and run its looper. This is is intended for C++ unit
- * tests (e.g. the net unit tests) that don't run with the UI thread as their main looper, but test
- * code that, on Android, uses UI thread events, so need a running UI thread.
- */
-@ThreadSafe
-public class TestUiThread {
- private static final AtomicBoolean sStarted = new AtomicBoolean(false);
- private static final String TAG = Log.makeTag("TestUiThread");
-
- @CalledByNative
- private static void loop() {
- // @{link ThreadUtils#setUiThread(Looper)} can only be called once in a test run, so do this
- // once, and leave it running.
- if (sStarted.getAndSet(true)) return;
-
- final CountDownLatch startLatch = new CountDownLatch(1);
- new Thread(new Runnable() {
-
- @Override
- public void run() {
- Looper.prepare();
- ThreadUtils.setUiThread(Looper.myLooper());
- startLatch.countDown();
- Looper.loop();
- }
-
- }).start();
-
- try {
- startLatch.await();
- } catch (InterruptedException e) {
- Log.e(TAG, "Failed to set UI Thread");
- }
- }
-}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/BaseActivityInstrumentationTestCase.java b/base/test/android/javatests/src/org/chromium/base/test/BaseActivityInstrumentationTestCase.java
deleted file mode 100644
index 53dee4ab14..0000000000
--- a/base/test/android/javatests/src/org/chromium/base/test/BaseActivityInstrumentationTestCase.java
+++ /dev/null
@@ -1,118 +0,0 @@
-// Copyright 2015 The Chromium 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;
-
-import android.app.Activity;
-import android.content.Context;
-import android.os.SystemClock;
-import android.test.ActivityInstrumentationTestCase2;
-import android.util.Log;
-
-import org.chromium.base.BaseChromiumApplication;
-import org.chromium.base.CommandLine;
-import org.chromium.base.test.util.CommandLineFlags;
-
-import java.lang.reflect.AnnotatedElement;
-import java.lang.reflect.Method;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * Base class for all Activity-based Instrumentation tests.
- *
- * @param <T> The Activity type.
- */
-public class BaseActivityInstrumentationTestCase<T extends Activity>
- extends ActivityInstrumentationTestCase2<T> {
-
- private static final String TAG = "BaseActivityInstrumentationTestCase";
-
- private static final int SLEEP_INTERVAL = 50; // milliseconds
- private static final int WAIT_DURATION = 5000; // milliseconds
-
- /**
- * Creates a instance for running tests against an Activity of the given class.
- *
- * @param activityClass The type of activity that will be tested.
- */
- public BaseActivityInstrumentationTestCase(Class<T> activityClass) {
- super(activityClass);
- }
-
- /**
- * Sets up the CommandLine with the appropriate flags.
- *
- * This will add the difference of the sets of flags specified by {@link CommandLineFlags.Add}
- * and {@link CommandLineFlags.Remove} to the {@link org.chromium.base.CommandLine}. Note that
- * trying to remove a flag set externally, i.e. by the command-line flags file, will not work.
- */
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
- CommandLine.reset();
- Context targetContext = getTargetContext();
- assertNotNull("Unable to get a non-null target context.", targetContext);
-
- BaseChromiumApplication.initCommandLine(targetContext);
- Set<String> flags = getFlags(getClass().getMethod(getName()));
- for (String flag : flags) {
- CommandLine.getInstance().appendSwitch(flag);
- }
- }
-
- /**
- * Gets the target context.
- *
- * On older versions of Android, getTargetContext() may initially return null, so we have to
- * wait for it to become available.
- *
- * @return The target {@link android.content.Context} if available; null otherwise.
- */
- private Context getTargetContext() {
- Context targetContext = getInstrumentation().getTargetContext();
- try {
- long startTime = SystemClock.uptimeMillis();
- // TODO(jbudorick): Convert this to CriteriaHelper once that moves to base/.
- while (targetContext == null
- && SystemClock.uptimeMillis() - startTime < WAIT_DURATION) {
- Thread.sleep(SLEEP_INTERVAL);
- targetContext = getInstrumentation().getTargetContext();
- }
- } catch (InterruptedException e) {
- Log.e(TAG, "Interrupted while attempting to initialize the command line.");
- }
- return targetContext;
- }
-
- private static Set<String> getFlags(AnnotatedElement element) {
- AnnotatedElement parent = (element instanceof Method)
- ? ((Method) element).getDeclaringClass()
- : ((Class) element).getSuperclass();
- Set<String> flags = (parent == null) ? new HashSet<String>() : getFlags(parent);
-
- if (element.isAnnotationPresent(CommandLineFlags.Add.class)) {
- flags.addAll(
- Arrays.asList(element.getAnnotation(CommandLineFlags.Add.class).value()));
- }
-
- if (element.isAnnotationPresent(CommandLineFlags.Remove.class)) {
- List<String> flagsToRemove =
- Arrays.asList(element.getAnnotation(CommandLineFlags.Remove.class).value());
- for (String flagToRemove : flagsToRemove) {
- // If your test fails here, you have tried to remove a command-line flag via
- // CommandLineFlags.Remove that was loaded into CommandLine via something other
- // than CommandLineFlags.Add (probably the command-line flag file).
- assertFalse("Unable to remove command-line flag \"" + flagToRemove + "\".",
- CommandLine.getInstance().hasSwitch(flagToRemove));
- }
- flags.removeAll(flagsToRemove);
- }
-
- return flags;
- }
-}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/BaseInstrumentationTestRunner.java b/base/test/android/javatests/src/org/chromium/base/test/BaseInstrumentationTestRunner.java
deleted file mode 100644
index 8a3395ad7d..0000000000
--- a/base/test/android/javatests/src/org/chromium/base/test/BaseInstrumentationTestRunner.java
+++ /dev/null
@@ -1,133 +0,0 @@
-// Copyright 2014 The Chromium 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;
-
-import android.os.Build;
-import android.os.Bundle;
-import android.test.AndroidTestRunner;
-import android.test.InstrumentationTestRunner;
-import android.util.Log;
-
-import junit.framework.TestCase;
-import junit.framework.TestResult;
-
-import org.chromium.base.test.util.MinAndroidSdkLevel;
-import org.chromium.test.reporter.TestStatusListener;
-
-import java.util.ArrayList;
-import java.util.List;
-
-// TODO(jbudorick): Add support for on-device handling of timeouts.
-/**
- * An Instrumentation test runner that checks SDK level for tests with specific requirements.
- */
-public class BaseInstrumentationTestRunner extends InstrumentationTestRunner {
-
- private static final String TAG = "BaseInstrumentationTestRunner";
-
- /**
- * An interface for classes that check whether a test case should be skipped.
- */
- public interface SkipCheck {
- /**
- * Checks whether the given test case should be skipped.
- *
- * @param testCase The test case to check.
- * @return Whether the test case should be skipped.
- */
- public boolean shouldSkip(TestCase testCase);
- }
-
- /**
- * A test result that can skip tests.
- */
- public class SkippingTestResult extends TestResult {
-
- private final List<SkipCheck> mSkipChecks;
-
- /**
- * Creates an instance of SkippingTestResult.
- */
- public SkippingTestResult() {
- mSkipChecks = new ArrayList<SkipCheck>();
- }
-
- /**
- * Adds a check for whether a test should run.
- *
- * @param skipCheck The check to add.
- */
- public void addSkipCheck(SkipCheck skipCheck) {
- mSkipChecks.add(skipCheck);
- }
-
- private boolean shouldSkip(final TestCase test) {
- for (SkipCheck s : mSkipChecks) {
- if (s.shouldSkip(test)) return true;
- }
- return false;
- }
-
- @Override
- protected void run(final TestCase test) {
- if (shouldSkip(test)) {
- startTest(test);
-
- Bundle skipResult = new Bundle();
- skipResult.putString("class", test.getClass().getName());
- skipResult.putString("test", test.getName());
- skipResult.putBoolean("test_skipped", true);
- sendStatus(0, skipResult);
-
- endTest(test);
- } else {
- super.run(test);
- }
- }
- }
-
- @Override
- protected AndroidTestRunner getAndroidTestRunner() {
- AndroidTestRunner runner = new AndroidTestRunner() {
- @Override
- protected TestResult createTestResult() {
- SkippingTestResult r = new SkippingTestResult();
- r.addSkipCheck(new MinAndroidSdkLevelSkipCheck());
- return r;
- }
- };
- runner.addTestListener(new TestStatusListener(getContext()));
- return runner;
- }
-
- /**
- * Checks the device's SDK level against any specified minimum requirement.
- */
- public static class MinAndroidSdkLevelSkipCheck implements SkipCheck {
-
- /**
- * If {@link org.chromium.base.test.util.MinAndroidSdkLevel} is present, checks its value
- * against the device's SDK level.
- *
- * @param testCase The test to check.
- * @return true if the device's SDK level is below the specified minimum.
- */
- @Override
- public boolean shouldSkip(TestCase testCase) {
- Class<?> testClass = testCase.getClass();
- if (testClass.isAnnotationPresent(MinAndroidSdkLevel.class)) {
- MinAndroidSdkLevel v = testClass.getAnnotation(MinAndroidSdkLevel.class);
- if (Build.VERSION.SDK_INT < v.value()) {
- Log.i(TAG, "Test " + testClass.getName() + "#" + testCase.getName()
- + " is not enabled at SDK level " + Build.VERSION.SDK_INT
- + ".");
- return true;
- }
- }
- return false;
- }
- }
-
-}
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 c8117f7fad..0000000000
--- a/base/test/android/javatests/src/org/chromium/base/test/util/AdvancedMockContext.java
+++ /dev/null
@@ -1,118 +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.test.util;
-
-import android.content.ComponentCallbacks;
-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<String, SharedPreferences> mSharedPreferences =
- new HashMap<String, SharedPreferences>();
-
- private final Map<String, Boolean> mFlags = new HashMap<String, Boolean>();
-
- 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);
- }
- }
-
- @Override
- public void registerComponentCallbacks(ComponentCallbacks callback) {
- getBaseContext().registerComponentCallbacks(callback);
- }
-
- @Override
- public void unregisterComponentCallbacks(ComponentCallbacks callback) {
- getBaseContext().unregisterComponentCallbacks(callback);
- }
-
- public void addSharedPreferences(String name, Map<String, Object> data) {
- synchronized (mSharedPreferences) {
- mSharedPreferences.put(name, new InMemorySharedPreferences(data));
- }
- }
-
- public void setFlag(String key) {
- mFlags.put(key, true);
- }
-
- public void clearFlag(String key) {
- mFlags.remove(key);
- }
-
- public boolean isFlagSet(String key) {
- return mFlags.containsKey(key) && mFlags.get(key);
- }
-
- /**
- * Builder for maps of type Map<String, Object> to be used with
- * {@link #addSharedPreferences(String, java.util.Map)}.
- */
- public static class MapBuilder {
-
- private final Map<String, Object> mData = new HashMap<String, Object>();
-
- public static MapBuilder create() {
- return new MapBuilder();
- }
-
- public MapBuilder add(String key, Object value) {
- mData.put(key, value);
- return this;
- }
-
- public Map<String, Object> build() {
- return mData;
- }
-
- }
-}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/CommandLineFlags.java b/base/test/android/javatests/src/org/chromium/base/test/util/CommandLineFlags.java
deleted file mode 100644
index 2feb83d35c..0000000000
--- a/base/test/android/javatests/src/org/chromium/base/test/util/CommandLineFlags.java
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2015 The Chromium 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.Inherited;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Provides annotations related to command-line flag handling.
- *
- * Uses of these annotations on a derived class will take precedence over uses on its base classes,
- * so a derived class can add a command-line flag that a base class has removed (or vice versa).
- * Similarly, uses of these annotations on a test method will take precedence over uses on the
- * containing class.
- *
- * Note that this class should never be instantiated.
- */
-public final class CommandLineFlags {
-
- /**
- * Adds command-line flags to the {@link org.chromium.base.CommandLine} for this test.
- */
- @Inherited
- @Retention(RetentionPolicy.RUNTIME)
- @Target({ElementType.METHOD, ElementType.TYPE})
- public @interface Add {
- String[] value();
- }
-
- /**
- * Removes command-line flags from the {@link org.chromium.base.CommandLine} from this test.
- *
- * Note that this can only remove flags added via {@link Add} above.
- */
- @Inherited
- @Retention(RetentionPolicy.RUNTIME)
- @Target({ElementType.METHOD, ElementType.TYPE})
- public @interface Remove {
- String[] value();
- }
-
- private CommandLineFlags() {}
-}
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 0dfb4be856..0000000000
--- a/base/test/android/javatests/src/org/chromium/base/test/util/DisabledTest.java
+++ /dev/null
@@ -1,21 +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.
-
-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.
- * <p>
- * 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 af483ec3f9..0000000000
--- a/base/test/android/javatests/src/org/chromium/base/test/util/EnormousTest.java
+++ /dev/null
@@ -1,24 +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.
-
-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.
- * <p>
- * Examples of enormous tests are tests that depend on external web sites or
- * tests that are long running.
- * <p>
- * 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 1bc9226441..0000000000
--- a/base/test/android/javatests/src/org/chromium/base/test/util/Feature.java
+++ /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.
-
-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/HostDrivenTest.java b/base/test/android/javatests/src/org/chromium/base/test/util/HostDrivenTest.java
deleted file mode 100644
index b52fb2c279..0000000000
--- a/base/test/android/javatests/src/org/chromium/base/test/util/HostDrivenTest.java
+++ /dev/null
@@ -1,22 +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.
-
-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 host-driven tests.
- * <p>
- * Tests with these annotations are run explicitly by HostDrivenTestCase-derived
- * python tests on the host and are excluded from regular instrumentation test runs.
- * <p>
- */
-@Target(ElementType.METHOD)
-@Retention(RetentionPolicy.RUNTIME)
-public @interface HostDrivenTest {
-}
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 2587d724a5..0000000000
--- a/base/test/android/javatests/src/org/chromium/base/test/util/InMemorySharedPreferences.java
+++ /dev/null
@@ -1,238 +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.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.
- * <p/>
- * 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<String, Object> mData;
-
- public InMemorySharedPreferences() {
- mData = new HashMap<String, Object>();
- }
-
- public InMemorySharedPreferences(Map<String, Object> data) {
- mData = data;
- }
-
- @Override
- public Map<String, ?> 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<String> getStringSet(String key, Set<String> defValues) {
- synchronized (mData) {
- if (mData.containsKey(key)) {
- return Collections.unmodifiableSet((Set<String>) 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<String, Object> mChanges = new HashMap<String, Object>();
-
- @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<String> 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<String, Object> 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 20cfd9d620..0000000000
--- a/base/test/android/javatests/src/org/chromium/base/test/util/InstrumentationUtils.java
+++ /dev/null
@@ -1,32 +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.
-
-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> R runOnMainSyncAndGetResult(Instrumentation instrumentation,
- Callable<R> callable) throws Throwable {
- FutureTask<R> task = new FutureTask<R>(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/IntegrationTest.java b/base/test/android/javatests/src/org/chromium/base/test/util/IntegrationTest.java
deleted file mode 100644
index 8b6550d62d..0000000000
--- a/base/test/android/javatests/src/org/chromium/base/test/util/IntegrationTest.java
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2014 The Chromium 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 integration tests.
- * <p>
- * Examples of integration tests are tests that rely on real instances of the
- * application's services and components (e.g. Search) to test the system as
- * a whole. These tests may use additional command-line flags to configure the
- * existing backends to use.
- * <p>
- * 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 IntegrationTest {
-} \ No newline at end of file
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/Manual.java b/base/test/android/javatests/src/org/chromium/base/test/util/Manual.java
deleted file mode 100644
index 31f3977bef..0000000000
--- a/base/test/android/javatests/src/org/chromium/base/test/util/Manual.java
+++ /dev/null
@@ -1,21 +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.
-
-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 mark a test that should only be run manually.
- * <p>
- * Tests with this annotation will not be run on bots, because they take too long
- * or need manual monitoring.
- */
-@Target(ElementType.METHOD)
-@Retention(RetentionPolicy.RUNTIME)
-public @interface Manual {
-}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/MetricsUtils.java b/base/test/android/javatests/src/org/chromium/base/test/util/MetricsUtils.java
deleted file mode 100644
index c4664d68b0..0000000000
--- a/base/test/android/javatests/src/org/chromium/base/test/util/MetricsUtils.java
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2014 The Chromium 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.metrics.RecordHistogram;
-
-/**
- * Helpers for testing UMA metrics.
- */
-public class MetricsUtils {
- /**
- * Helper class that snapshots the given bucket of the given UMA histogram on its creation,
- * allowing to inspect the number of samples recorded during its lifetime.
- */
- public static class HistogramDelta {
- private final String mHistogram;
- private final int mSampleValue;
-
- private final int mInitialCount;
-
- private int get() {
- return RecordHistogram.getHistogramValueCountForTesting(mHistogram, mSampleValue);
- }
-
- /**
- * Snapshots the given bucket of the given histogram.
- * @param histogram name of the histogram to snapshot
- * @param sampleValue the bucket that contains this value will be snapshot
- */
- public HistogramDelta(String histogram, int sampleValue) {
- mHistogram = histogram;
- mSampleValue = sampleValue;
- mInitialCount = get();
- }
-
- /** Returns the number of samples of the snapshot bucket recorded since creation */
- public int getDelta() {
- return get() - mInitialCount;
- }
- }
-}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/MinAndroidSdkLevel.java b/base/test/android/javatests/src/org/chromium/base/test/util/MinAndroidSdkLevel.java
deleted file mode 100644
index d7c45e7e5a..0000000000
--- a/base/test/android/javatests/src/org/chromium/base/test/util/MinAndroidSdkLevel.java
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2014 The Chromium 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.Inherited;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-@Inherited
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.TYPE})
-public @interface MinAndroidSdkLevel {
- int value() default 0;
-}
-
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/PerfTest.java b/base/test/android/javatests/src/org/chromium/base/test/util/PerfTest.java
deleted file mode 100644
index 9b3495ccf5..0000000000
--- a/base/test/android/javatests/src/org/chromium/base/test/util/PerfTest.java
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright 2014 The Chromium 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 tells the test harness that this method will be used in a performance test.
- * This means that the test harness will use the parameters here to figure out which trace calls
- * to track specifically for this test.
- * <p>
- * Each of the lists ({@link #traceNames()}, {@link #graphNames()},
- * and {@link #seriesNames()}) should have the same number of
- * elements.
- * <p>
- * To write a performance test, you need to do the following:
- * <p><ol>
- * <li>Add TraceEvent calls to the code that you want to track.
- * <ul>
- * <li> For FPS, add a TraceEvent.instant call where you want to time and detect calls.
- * <li> For code segment timing, add {@link org.chromium.base.TraceEvent#begin()}/
- * {@link org.chromium.base.TraceEvent#end()} calls around the code
- * segment (does not have to be in the same method).
- * </ul>
- * <li> Write a Java Automated UI Test that instruments this code.
- * <li> Add this PerfTest annotation to the test method.
- * <ul>
- * <li> traceNames must be a list of the names of all of the TraceEvent calls you want to track.
- * <li> graphNames must be a list, one for each traceName, of which graph the trace data should be
- * placed in (does not have to be unique).
- * <li> seriesNames must be a list, one for each traceName, of what the series should be called
- * for this trace data (has to be unique per graphName).
- * <li> When checked in, the buildbots will automatically run this test and the results will show up
- * under the Java Automation UI Performance graph, where there will be tabs for each graphName
- * specified.
- * <li> To test your performance test, run the following command and you should see the performance
- * numbers printed to the console.
- * </ol>
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.METHOD})
-public @interface PerfTest {
- /**
- * @return A list of the trace calls to track.
- */
- public String[] traceNames();
-
- /**
- * @return A list, one for each traceName, that represents which graph this trace call should
- * be output on. This does not have to be unique if there are multiple series per
- * graph.
- */
- public String[] graphNames();
-
- /**
- * @return A list, one for each traceName, that represents the series this trace call should be
- * on the corresponding graph. This should be unique.
- */
- public String[] seriesNames();
-
- /**
- * @return Whether or not we should automatically start and stop tracing for the test. This
- * makes it easier to run some tests where tracing is started and stopped at the
- * beginning and end of that particular test.
- */
- public boolean autoTrace() default false;
-
- /**
- * @return Whether this performance test should track memory usage in addition to time. If
- * true, this will track memory usage when tracking time deltas or instants. With each
- * graph defined in the annotation for tracking time, this will add an additional graph
- * suffixed with a memory identifier containing the same series as those tracking the
- * timing performance but instead will be tracking memory consumption.
- */
- public boolean traceMemory() default true;
-
- /**
- * @return Whether this performance test should track time or (optionally) only memory. If
- * false, this will not automatically track time deltas or instants when logging
- * memory info.
- */
- public boolean traceTiming() default true;
-}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/Restriction.java b/base/test/android/javatests/src/org/chromium/base/test/util/Restriction.java
deleted file mode 100644
index 11026efab9..0000000000
--- a/base/test/android/javatests/src/org/chromium/base/test/util/Restriction.java
+++ /dev/null
@@ -1,37 +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.test.util;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * An annotation for listing restrictions for a test method. For example, if a test method is only
- * applicable on a phone with small memory:
- * @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_SMALL_MEMORY})
- * Test classes are free to define restrictions and enforce them using reflection at runtime.
- */
-@Target(ElementType.METHOD)
-@Retention(RetentionPolicy.RUNTIME)
-public @interface Restriction {
- /** Specifies the test is only valid on phone form factors. */
- public static final String RESTRICTION_TYPE_PHONE = "Phone";
-
- /** Specifies the test is only valid on tablet form factors. */
- public static final String RESTRICTION_TYPE_TABLET = "Tablet";
-
- /** Specifies the test is only valid on low end devices that have less memory. */
- public static final String RESTRICTION_TYPE_LOW_END_DEVICE = "Low_End_Device";
-
- /** Specifies the test is only valid on non-low end devices. */
- public static final String RESTRICTION_TYPE_NON_LOW_END_DEVICE = "Non_Low_End_Device";
-
- /**
- * @return A list of restrictions.
- */
- public String[] value();
-} \ No newline at end of file
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 c21bff9bca..0000000000
--- a/base/test/android/javatests/src/org/chromium/base/test/util/ScalableTimeout.java
+++ /dev/null
@@ -1,28 +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.
-
-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/TestFileUtil.java b/base/test/android/javatests/src/org/chromium/base/test/util/TestFileUtil.java
deleted file mode 100644
index 8765def895..0000000000
--- a/base/test/android/javatests/src/org/chromium/base/test/util/TestFileUtil.java
+++ /dev/null
@@ -1,78 +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.
-
-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("<html><meta charset=\"UTF-8\" />"
- + " <head><title>" + title + "</title></head>"
- + " <body>"
- + (body != null ? body : "")
- + " </body>"
- + " </html>");
- } finally {
- if (writer != null) {
- writer.close();
- }
- }
- }
-
- public static void deleteFile(String name) {
- File file = new File(name);
- boolean deleted = file.delete();
- assert (deleted || !file.exists());
- }
-
- /**
- * @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 93c23f79d8..0000000000
--- a/base/test/android/javatests/src/org/chromium/base/test/util/TestThread.java
+++ /dev/null
@@ -1,143 +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.
-
-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 5aee05e73a..0000000000
--- a/base/test/android/javatests/src/org/chromium/base/test/util/TimeoutScale.java
+++ /dev/null
@@ -1,22 +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.
-
-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 797585f459..0000000000
--- a/base/test/android/javatests/src/org/chromium/base/test/util/UrlUtils.java
+++ /dev/null
@@ -1,73 +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.
-
-package org.chromium.base.test.util;
-
-import junit.framework.Assert;
-
-import org.chromium.base.PathUtils;
-
-/**
- * Collection of URL utilities.
- */
-public class UrlUtils {
- private static final String DATA_DIR = "/chrome/test/data/";
-
- /**
- * Construct the full path of a test data file.
- * @param path Pathname relative to external/chrome/test/data
- */
- public static String getTestFilePath(String path) {
- // TODO(jbudorick): Remove DATA_DIR once everything has been isolated. crbug/400499
- return PathUtils.getExternalStorageDirectory() + DATA_DIR + path;
- }
-
- // TODO(jbudorick): Remove this function once everything has been isolated and switched back
- // to getTestFilePath. crbug/400499
- /**
- * Construct the full path of a test data file.
- * @param path Pathname relative to external/
- */
- public static String getIsolatedTestFilePath(String path) {
- return PathUtils.getExternalStorageDirectory() + "/" + path;
- }
-
- /**
- * Construct a suitable URL for loading a test data file.
- * @param path Pathname relative to external/chrome/test/data
- */
- public static String getTestFileUrl(String path) {
- return "file://" + getTestFilePath(path);
- }
-
- // TODO(jbudorick): Remove this function once everything has been isolated and switched back
- // to getTestFileUrl. crbug/400499
- /**
- * Construct a suitable URL for loading a test data file.
- * @param path Pathname relative to external/
- */
- public static String getIsolatedTestFileUrl(String path) {
- return "file://" + getIsolatedTestFilePath(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/pe_image/pe_image_test_32.dll b/base/test/data/pe_image/pe_image_test_32.dll
index 118ce11475..539d631c1d 100755
--- a/base/test/data/pe_image/pe_image_test_32.dll
+++ b/base/test/data/pe_image/pe_image_test_32.dll
Binary files differ
diff --git a/base/test/data/pe_image/pe_image_test_64.dll b/base/test/data/pe_image/pe_image_test_64.dll
index 70f8ea451b..8801e23821 100755
--- a/base/test/data/pe_image/pe_image_test_64.dll
+++ b/base/test/data/pe_image/pe_image_test_64.dll
Binary files differ
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/multiprocess_test.cc b/base/test/multiprocess_test.cc
index 2cd6d8ca03..6a1b7b4864 100644
--- a/base/test/multiprocess_test.cc
+++ b/base/test/multiprocess_test.cc
@@ -8,10 +8,11 @@
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
+#include "build/build_config.h"
namespace base {
-#if !defined(OS_ANDROID)
+#if !defined(OS_ANDROID) && !defined(__ANDROID__) && !defined(__ANDROID_HOST__)
Process SpawnMultiProcessTestChild(
const std::string& procname,
const CommandLine& base_command_line,
diff --git a/base/test/multiprocess_test.h b/base/test/multiprocess_test.h
index b1c73dff79..ab1d0ca4c0 100644
--- a/base/test/multiprocess_test.h
+++ b/base/test/multiprocess_test.h
@@ -7,7 +7,7 @@
#include <string>
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/process/launch.h"
#include "base/process/process.h"
#include "build/build_config.h"
diff --git a/base/test/scoped_locale.h b/base/test/scoped_locale.h
index a9f9348830..ef64e98f8e 100644
--- a/base/test/scoped_locale.h
+++ b/base/test/scoped_locale.h
@@ -7,7 +7,7 @@
#include <string>
-#include "base/basictypes.h"
+#include "base/macros.h"
namespace base {
diff --git a/base/test/sequenced_worker_pool_owner.cc b/base/test/sequenced_worker_pool_owner.cc
index b0d8b7a1ad..37bad2b29d 100644
--- a/base/test/sequenced_worker_pool_owner.cc
+++ b/base/test/sequenced_worker_pool_owner.cc
@@ -18,8 +18,11 @@ SequencedWorkerPoolOwner::SequencedWorkerPoolOwner(
has_work_call_count_(0) {}
SequencedWorkerPoolOwner::~SequencedWorkerPoolOwner() {
+ pool_->Shutdown();
pool_ = NULL;
- MessageLoop::current()->Run();
+
+ // Spin the current message loop until SWP destruction verified in OnDestruct.
+ exit_loop_.Run();
}
const scoped_refptr<SequencedWorkerPool>& SequencedWorkerPoolOwner::pool() {
@@ -51,8 +54,7 @@ void SequencedWorkerPoolOwner::WillWaitForShutdown() {
}
void SequencedWorkerPoolOwner::OnDestruct() {
- constructor_message_loop_->task_runner()->PostTask(
- FROM_HERE, constructor_message_loop_->QuitWhenIdleClosure());
+ constructor_message_loop_->PostTask(FROM_HERE, exit_loop_.QuitClosure());
}
} // namespace base
diff --git a/base/test/sequenced_worker_pool_owner.h b/base/test/sequenced_worker_pool_owner.h
index bf5f2f766e..05fc7505fb 100644
--- a/base/test/sequenced_worker_pool_owner.h
+++ b/base/test/sequenced_worker_pool_owner.h
@@ -5,13 +5,16 @@
#ifndef BASE_TEST_SEQUENCED_WORKER_POOL_OWNER_H_
#define BASE_TEST_SEQUENCED_WORKER_POOL_OWNER_H_
+#include <stddef.h>
+
#include <cstddef>
#include <string>
-#include "base/basictypes.h"
#include "base/callback.h"
#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "base/run_loop.h"
#include "base/synchronization/lock.h"
#include "base/threading/sequenced_worker_pool.h"
@@ -25,6 +28,9 @@ class MessageLoop;
// strange races with other tests that touch global stuff (like histograms and
// logging). However, this requires that nothing else on this thread holds a
// ref to the pool when the SequencedWorkerPoolOwner is destroyed.
+//
+// This class calls Shutdown on the owned SequencedWorkerPool in the destructor.
+// Tests may themselves call Shutdown earlier to test shutdown behavior.
class SequencedWorkerPoolOwner : public SequencedWorkerPool::TestingObserver {
public:
SequencedWorkerPoolOwner(size_t max_threads,
@@ -46,7 +52,11 @@ class SequencedWorkerPoolOwner : public SequencedWorkerPool::TestingObserver {
void WillWaitForShutdown() override;
void OnDestruct() override;
+ // Used to run the current thread's message loop until the
+ // SequencedWorkerPool's destruction has been verified.
+ base::RunLoop exit_loop_;
MessageLoop* const constructor_message_loop_;
+
scoped_refptr<SequencedWorkerPool> pool_;
Closure will_wait_for_shutdown_callback_;
diff --git a/base/test/test_file_util.h b/base/test/test_file_util.h
index 27197f2d3a..7042e48484 100644
--- a/base/test/test_file_util.h
+++ b/base/test/test_file_util.h
@@ -7,14 +7,17 @@
// File utility functions used only by tests.
+#include <stddef.h>
+
#include <string>
#include "base/compiler_specific.h"
#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "build/build_config.h"
#if defined(OS_ANDROID)
#include <jni.h>
-#include "base/basictypes.h"
#endif
namespace base {
diff --git a/base/test/test_file_util_posix.cc b/base/test/test_file_util_posix.cc
index 12b892c826..b81728318c 100644
--- a/base/test/test_file_util_posix.cc
+++ b/base/test/test_file_util_posix.cc
@@ -6,6 +6,7 @@
#include <errno.h>
#include <fcntl.h>
+#include <stddef.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -16,6 +17,7 @@
#include "base/logging.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
namespace base {
diff --git a/base/test/test_simple_task_runner.h b/base/test/test_simple_task_runner.h
index 7481b6deda..338c634c8d 100644
--- a/base/test/test_simple_task_runner.h
+++ b/base/test/test_simple_task_runner.h
@@ -7,8 +7,8 @@
#include <deque>
-#include "base/basictypes.h"
#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "base/single_thread_task_runner.h"
#include "base/test/test_pending_task.h"
#include "base/threading/thread_checker.h"
diff --git a/base/test/test_switches.cc b/base/test/test_switches.cc
index 84aa53c474..40f20d7b7d 100644
--- a/base/test/test_switches.cc
+++ b/base/test/test_switches.cc
@@ -18,6 +18,11 @@ const char switches::kTestLauncherBotMode[] =
const char switches::kTestLauncherDebugLauncher[] =
"test-launcher-debug-launcher";
+// Force running all requested tests and retries even if too many test errors
+// occur.
+const char switches::kTestLauncherForceRunBrokenTests[] =
+ "test-launcher-force-run-broken-tests";
+
// Path to file containing test filter (one pattern per line).
const char switches::kTestLauncherFilterFile[] = "test-launcher-filter-file";
diff --git a/base/test/test_switches.h b/base/test/test_switches.h
index f145f1efc9..419b755541 100644
--- a/base/test/test_switches.h
+++ b/base/test/test_switches.h
@@ -12,6 +12,7 @@ namespace switches {
extern const char kTestLauncherBatchLimit[];
extern const char kTestLauncherBotMode[];
extern const char kTestLauncherDebugLauncher[];
+extern const char kTestLauncherForceRunBrokenTests[];
extern const char kTestLauncherFilterFile[];
extern const char kTestLauncherJobs[];
extern const char kTestLauncherListTests[];
diff --git a/base/test/test_timeouts.cc b/base/test/test_timeouts.cc
index b30d6c34aa..55e9a79861 100644
--- a/base/test/test_timeouts.cc
+++ b/base/test/test_timeouts.cc
@@ -11,6 +11,7 @@
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "base/test/test_switches.h"
+#include "build/build_config.h"
namespace {
diff --git a/base/test/test_timeouts.h b/base/test/test_timeouts.h
index 2819e4a1c1..ddaf05b5e0 100644
--- a/base/test/test_timeouts.h
+++ b/base/test/test_timeouts.h
@@ -5,8 +5,8 @@
#ifndef BASE_TEST_TEST_TIMEOUTS_H_
#define BASE_TEST_TEST_TIMEOUTS_H_
-#include "base/basictypes.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/time/time.h"
// Returns common timeouts to use in tests. Makes it possible to adjust
diff --git a/base/test/trace_event_analyzer.cc b/base/test/trace_event_analyzer.cc
index e46c2a5170..2046355664 100644
--- a/base/test/trace_event_analyzer.cc
+++ b/base/test/trace_event_analyzer.cc
@@ -4,12 +4,14 @@
#include "base/test/trace_event_analyzer.h"
-#include <algorithm>
#include <math.h>
+
+#include <algorithm>
#include <set>
#include "base/json/json_reader.h"
#include "base/memory/scoped_ptr.h"
+#include "base/strings/pattern.h"
#include "base/values.h"
namespace trace_analyzer {
@@ -218,11 +220,11 @@ Query Query::Double(double num) {
return Query(num);
}
-Query Query::Int(int32 num) {
+Query Query::Int(int32_t num) {
return Query(static_cast<double>(num));
}
-Query Query::Uint(uint32 num) {
+Query Query::Uint(uint32_t num) {
return Query(static_cast<double>(num));
}
@@ -321,17 +323,17 @@ bool Query::CompareAsString(const TraceEvent& event, bool* result) const {
switch (operator_) {
case OP_EQ:
if (right().is_pattern_)
- *result = MatchPattern(lhs, rhs);
+ *result = base::MatchPattern(lhs, rhs);
else if (left().is_pattern_)
- *result = MatchPattern(rhs, lhs);
+ *result = base::MatchPattern(rhs, lhs);
else
*result = (lhs == rhs);
return true;
case OP_NE:
if (right().is_pattern_)
- *result = !MatchPattern(lhs, rhs);
+ *result = !base::MatchPattern(lhs, rhs);
else if (left().is_pattern_)
- *result = !MatchPattern(rhs, lhs);
+ *result = !base::MatchPattern(rhs, lhs);
else
*result = (lhs != rhs);
return true;
@@ -379,8 +381,8 @@ bool Query::EvaluateArithmeticOperator(const TraceEvent& event,
*num = lhs / rhs;
return true;
case OP_MOD:
- *num = static_cast<double>(static_cast<int64>(lhs) %
- static_cast<int64>(rhs));
+ *num = static_cast<double>(static_cast<int64_t>(lhs) %
+ static_cast<int64_t>(rhs));
return true;
case OP_NEGATE:
*num = -lhs;
@@ -647,8 +649,7 @@ size_t FindMatchingEvents(const std::vector<TraceEvent>& events,
bool ParseEventsFromJson(const std::string& json,
std::vector<TraceEvent>* output) {
- scoped_ptr<base::Value> root;
- root.reset(base::JSONReader::DeprecatedRead(json));
+ scoped_ptr<base::Value> root = base::JSONReader::Read(json);
base::ListValue* root_list = NULL;
if (!root.get() || !root->GetAsList(&root_list))
diff --git a/base/test/trace_event_analyzer.h b/base/test/trace_event_analyzer.h
index 57ff2b571c..f67445aceb 100644
--- a/base/test/trace_event_analyzer.h
+++ b/base/test/trace_event_analyzer.h
@@ -76,8 +76,12 @@
#ifndef BASE_TEST_TRACE_EVENT_ANALYZER_H_
#define BASE_TEST_TRACE_EVENT_ANALYZER_H_
+#include <stddef.h>
+#include <stdint.h>
+
#include <map>
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/trace_event/trace_event.h"
@@ -183,8 +187,8 @@ class Query {
// Compare with the given number.
static Query Double(double num);
- static Query Int(int32 num);
- static Query Uint(uint32 num);
+ static Query Int(int32_t num);
+ static Query Uint(uint32_t num);
// Compare with the given bool.
static Query Bool(bool boolean);
@@ -406,7 +410,7 @@ class Query {
Query operator*(const Query& rhs) const;
Query operator/(const Query& rhs) const;
Query operator-() const;
- // Mod operates on int64 args (doubles are casted to int64 beforehand):
+ // Mod operates on int64_t args (doubles are casted to int64_t beforehand):
Query operator%(const Query& rhs) const;
// Return true if the given event matches this query tree.
diff --git a/base/test/trace_event_analyzer_unittest.cc b/base/test/trace_event_analyzer_unittest.cc
index 278709fd97..700b920765 100644
--- a/base/test/trace_event_analyzer_unittest.cc
+++ b/base/test/trace_event_analyzer_unittest.cc
@@ -2,10 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stddef.h>
+#include <stdint.h>
+
#include "base/bind.h"
#include "base/synchronization/waitable_event.h"
#include "base/test/trace_event_analyzer.h"
#include "base/threading/platform_thread.h"
+#include "base/trace_event/trace_buffer.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -398,7 +402,7 @@ TEST_F(TraceEventAnalyzerTest, BeginEndDuration) {
const base::TimeDelta kSleepTime = base::TimeDelta::FromMilliseconds(200);
// We will search for events that have a duration of greater than 90% of the
// sleep time, so that there is no flakiness.
- int64 duration_cutoff_us = (kSleepTime.InMicroseconds() * 9) / 10;
+ int64_t duration_cutoff_us = (kSleepTime.InMicroseconds() * 9) / 10;
BeginTracing();
{
@@ -444,7 +448,7 @@ TEST_F(TraceEventAnalyzerTest, CompleteDuration) {
const base::TimeDelta kSleepTime = base::TimeDelta::FromMilliseconds(200);
// We will search for events that have a duration of greater than 90% of the
// sleep time, so that there is no flakiness.
- int64 duration_cutoff_us = (kSleepTime.InMicroseconds() * 9) / 10;
+ int64_t duration_cutoff_us = (kSleepTime.InMicroseconds() * 9) / 10;
BeginTracing();
{
diff --git a/base/third_party/icu/icu_utf.cc b/base/third_party/icu/icu_utf.cc
index b47c8ac3c1..2b67c5d9c2 100644
--- a/base/third_party/icu/icu_utf.cc
+++ b/base/third_party/icu/icu_utf.cc
@@ -74,32 +74,28 @@ namespace base_icu {
* lead bytes above 0xf4 are illegal.
* We keep them in this table for skipping long ISO 10646-UTF-8 sequences.
*/
-const uint8
-utf8_countTrailBytes[256]={
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 3, 3, 3, 3, 3,
- 3, 3, 3, /* illegal in Unicode */
- 4, 4, 4, 4, /* illegal in Unicode */
- 5, 5, /* illegal in Unicode */
- 0, 0 /* illegal bytes 0xfe and 0xff */
+const uint8_t utf8_countTrailBytes[256] =
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3,
+ 3, 3, /* illegal in Unicode */
+ 4, 4, 4, 4, /* illegal in Unicode */
+ 5, 5, /* illegal in Unicode */
+ 0, 0 /* illegal bytes 0xfe and 0xff */
};
static const UChar32
@@ -133,12 +129,15 @@ utf8_errorValue[6]={
*
* Note that a UBool is the same as an int8_t.
*/
-UChar32
-utf8_nextCharSafeBody(const uint8 *s, int32 *pi, int32 length, UChar32 c, UBool strict) {
- int32 i=*pi;
- uint8 count=CBU8_COUNT_TRAIL_BYTES(c);
+UChar32 utf8_nextCharSafeBody(const uint8_t* s,
+ int32_t* pi,
+ int32_t length,
+ UChar32 c,
+ UBool strict) {
+ int32_t i = *pi;
+ uint8_t count = CBU8_COUNT_TRAIL_BYTES(c);
if((i)+count<=(length)) {
- uint8 trail, illegal=0;
+ uint8_t trail, illegal = 0;
CBU8_MASK_LEAD_BYTE((c), count);
/* count==0 for illegally leading trail bytes and the illegal bytes 0xfe and 0xff */
@@ -192,7 +191,7 @@ utf8_nextCharSafeBody(const uint8 *s, int32 *pi, int32 length, UChar32 c, UBool
/* illegal is also set if count>=4 */
if(illegal || (c)<utf8_minLegal[count] || (CBU_IS_SURROGATE(c) && strict!=-2)) {
/* error handling */
- uint8 errorCount=count;
+ uint8_t errorCount = count;
/* don't go beyond this sequence */
i=*pi;
while(count>0 && CBU8_IS_TRAIL(s[i])) {
@@ -210,7 +209,7 @@ utf8_nextCharSafeBody(const uint8 *s, int32 *pi, int32 length, UChar32 c, UBool
}
} else /* too few bytes left */ {
/* error handling */
- int32 i0=i;
+ int32_t i0 = i;
/* don't just set (i)=(length) in case there is an illegal sequence */
while((i)<(length) && CBU8_IS_TRAIL(s[i])) {
++(i);
diff --git a/base/third_party/icu/icu_utf.h b/base/third_party/icu/icu_utf.h
index 2b993b099f..4370fdec15 100644
--- a/base/third_party/icu/icu_utf.h
+++ b/base/third_party/icu/icu_utf.h
@@ -17,13 +17,13 @@
#ifndef BASE_THIRD_PARTY_ICU_ICU_UTF_H_
#define BASE_THIRD_PARTY_ICU_ICU_UTF_H_
-#include "base/basictypes.h"
+#include <stdint.h>
namespace base_icu {
-typedef int32 UChar32;
-typedef uint16 UChar;
-typedef int8 UBool;
+typedef int32_t UChar32;
+typedef uint16_t UChar;
+typedef int8_t UBool;
// General ---------------------------------------------------------------------
// from utf.h
@@ -54,10 +54,9 @@ typedef int8 UBool;
* @return TRUE or FALSE
* @stable ICU 2.4
*/
-#define CBU_IS_UNICODE_NONCHAR(c) \
- ((c)>=0xfdd0 && \
- ((uint32)(c)<=0xfdef || ((c)&0xfffe)==0xfffe) && \
- (uint32)(c)<=0x10ffff)
+#define CBU_IS_UNICODE_NONCHAR(c) \
+ ((c) >= 0xfdd0 && ((uint32_t)(c) <= 0xfdef || ((c)&0xfffe) == 0xfffe) && \
+ (uint32_t)(c) <= 0x10ffff)
/**
* Is c a Unicode code point value (0..U+10ffff)
@@ -76,11 +75,10 @@ typedef int8 UBool;
* @return TRUE or FALSE
* @stable ICU 2.4
*/
-#define CBU_IS_UNICODE_CHAR(c) \
- ((uint32)(c)<0xd800 || \
- ((uint32)(c)>0xdfff && \
- (uint32)(c)<=0x10ffff && \
- !CBU_IS_UNICODE_NONCHAR(c)))
+#define CBU_IS_UNICODE_CHAR(c) \
+ ((uint32_t)(c) < 0xd800 || \
+ ((uint32_t)(c) > 0xdfff && (uint32_t)(c) <= 0x10ffff && \
+ !CBU_IS_UNICODE_NONCHAR(c)))
/**
* Is this code point a surrogate (U+d800..U+dfff)?
@@ -103,13 +101,14 @@ typedef int8 UBool;
// UTF-8 macros ----------------------------------------------------------------
// from utf8.h
-extern const uint8 utf8_countTrailBytes[256];
+extern const uint8_t utf8_countTrailBytes[256];
/**
* Count the trail bytes for a UTF-8 lead byte.
* @internal
*/
-#define CBU8_COUNT_TRAIL_BYTES(leadByte) (base_icu::utf8_countTrailBytes[(uint8)leadByte])
+#define CBU8_COUNT_TRAIL_BYTES(leadByte) \
+ (base_icu::utf8_countTrailBytes[(uint8_t)leadByte])
/**
* Mask a UTF-8 lead byte, leave only the lower bits that form part of the code point value.
@@ -131,7 +130,7 @@ extern const uint8 utf8_countTrailBytes[256];
* @return TRUE or FALSE
* @stable ICU 2.4
*/
-#define CBU8_IS_LEAD(c) ((uint8)((c)-0xc0)<0x3e)
+#define CBU8_IS_LEAD(c) ((uint8_t)((c)-0xc0) < 0x3e)
/**
* Is this code unit (byte) a UTF-8 trail byte?
@@ -148,16 +147,16 @@ extern const uint8 utf8_countTrailBytes[256];
* @return 1..4, or 0 if c is a surrogate or not a Unicode code point
* @stable ICU 2.4
*/
-#define CBU8_LENGTH(c) \
- ((uint32)(c)<=0x7f ? 1 : \
- ((uint32)(c)<=0x7ff ? 2 : \
- ((uint32)(c)<=0xd7ff ? 3 : \
- ((uint32)(c)<=0xdfff || (uint32)(c)>0x10ffff ? 0 : \
- ((uint32)(c)<=0xffff ? 3 : 4)\
- ) \
- ) \
- ) \
- )
+#define CBU8_LENGTH(c) \
+ ((uint32_t)(c) <= 0x7f \
+ ? 1 \
+ : ((uint32_t)(c) <= 0x7ff \
+ ? 2 \
+ : ((uint32_t)(c) <= 0xd7ff \
+ ? 3 \
+ : ((uint32_t)(c) <= 0xdfff || (uint32_t)(c) > 0x10ffff \
+ ? 0 \
+ : ((uint32_t)(c) <= 0xffff ? 3 : 4)))))
/**
* The maximum number of UTF-8 code units (bytes) per Unicode code point (U+0000..U+10ffff).
@@ -170,7 +169,11 @@ extern const uint8 utf8_countTrailBytes[256];
* Function for handling "next code point" with error-checking.
* @internal
*/
-UChar32 utf8_nextCharSafeBody(const uint8 *s, int32 *pi, int32 length, UChar32 c, UBool strict);
+UChar32 utf8_nextCharSafeBody(const uint8_t* s,
+ int32_t* pi,
+ int32_t length,
+ UChar32 c,
+ UBool strict);
/**
* Get a code point from a string at a code point boundary offset,
@@ -183,55 +186,59 @@ UChar32 utf8_nextCharSafeBody(const uint8 *s, int32 *pi, int32 length, UChar32 c
* If the offset points to a trail byte or an illegal UTF-8 sequence, then
* c is set to a negative value.
*
- * @param s const uint8 * string
+ * @param s const uint8_t * string
* @param i string offset, i<length
* @param length string length
* @param c output UChar32 variable, set to <0 in case of an error
* @see CBU8_NEXT_UNSAFE
* @stable ICU 2.4
*/
-#define CBU8_NEXT(s, i, length, c) { \
- (c)=(s)[(i)++]; \
- if(((uint8)(c))>=0x80) { \
- if(CBU8_IS_LEAD(c)) { \
- (c)=base_icu::utf8_nextCharSafeBody((const uint8 *)s, &(i), (int32)(length), c, -1); \
- } else { \
- (c)=CBU_SENTINEL; \
- } \
- } \
-}
+#define CBU8_NEXT(s, i, length, c) \
+ { \
+ (c) = (s)[(i)++]; \
+ if (((uint8_t)(c)) >= 0x80) { \
+ if (CBU8_IS_LEAD(c)) { \
+ (c) = base_icu::utf8_nextCharSafeBody((const uint8_t*)s, &(i), \
+ (int32_t)(length), c, -1); \
+ } else { \
+ (c) = CBU_SENTINEL; \
+ } \
+ } \
+ }
/**
* Append a code point to a string, overwriting 1 to 4 bytes.
* The offset points to the current end of the string contents
* and is advanced (post-increment).
- * "Unsafe" macro, assumes a valid code point and sufficient space in the string.
+ * "Unsafe" macro, assumes a valid code point and sufficient space in the
+ * string.
* Otherwise, the result is undefined.
*
- * @param s const uint8 * string buffer
+ * @param s const uint8_t * string buffer
* @param i string offset
* @param c code point to append
* @see CBU8_APPEND
* @stable ICU 2.4
*/
-#define CBU8_APPEND_UNSAFE(s, i, c) { \
- if((uint32)(c)<=0x7f) { \
- (s)[(i)++]=(uint8)(c); \
- } else { \
- if((uint32)(c)<=0x7ff) { \
- (s)[(i)++]=(uint8)(((c)>>6)|0xc0); \
- } else { \
- if((uint32)(c)<=0xffff) { \
- (s)[(i)++]=(uint8)(((c)>>12)|0xe0); \
- } else { \
- (s)[(i)++]=(uint8)(((c)>>18)|0xf0); \
- (s)[(i)++]=(uint8)((((c)>>12)&0x3f)|0x80); \
- } \
- (s)[(i)++]=(uint8)((((c)>>6)&0x3f)|0x80); \
- } \
- (s)[(i)++]=(uint8)(((c)&0x3f)|0x80); \
- } \
-}
+#define CBU8_APPEND_UNSAFE(s, i, c) \
+ { \
+ if ((uint32_t)(c) <= 0x7f) { \
+ (s)[(i)++] = (uint8_t)(c); \
+ } else { \
+ if ((uint32_t)(c) <= 0x7ff) { \
+ (s)[(i)++] = (uint8_t)(((c) >> 6) | 0xc0); \
+ } else { \
+ if ((uint32_t)(c) <= 0xffff) { \
+ (s)[(i)++] = (uint8_t)(((c) >> 12) | 0xe0); \
+ } else { \
+ (s)[(i)++] = (uint8_t)(((c) >> 18) | 0xf0); \
+ (s)[(i)++] = (uint8_t)((((c) >> 12) & 0x3f) | 0x80); \
+ } \
+ (s)[(i)++] = (uint8_t)((((c) >> 6) & 0x3f) | 0x80); \
+ } \
+ (s)[(i)++] = (uint8_t)(((c)&0x3f) | 0x80); \
+ } \
+ }
// UTF-16 macros ---------------------------------------------------------------
// from utf16.h
@@ -325,7 +332,7 @@ UChar32 utf8_nextCharSafeBody(const uint8 *s, int32 *pi, int32 length, UChar32 c
* @return 1 or 2
* @stable ICU 2.4
*/
-#define CBU16_LENGTH(c) ((uint32)(c)<=0xffff ? 1 : 2)
+#define CBU16_LENGTH(c) ((uint32_t)(c) <= 0xffff ? 1 : 2)
/**
* The maximum number of 16-bit code units per Unicode code point (U+0000..U+10ffff).
@@ -353,16 +360,17 @@ UChar32 utf8_nextCharSafeBody(const uint8 *s, int32 *pi, int32 length, UChar32 c
* @param c output UChar32 variable
* @stable ICU 2.4
*/
-#define CBU16_NEXT(s, i, length, c) { \
- (c)=(s)[(i)++]; \
- if(CBU16_IS_LEAD(c)) { \
- uint16 __c2; \
- if((i)<(length) && CBU16_IS_TRAIL(__c2=(s)[(i)])) { \
- ++(i); \
- (c)=CBU16_GET_SUPPLEMENTARY((c), __c2); \
- } \
- } \
-}
+#define CBU16_NEXT(s, i, length, c) \
+ { \
+ (c) = (s)[(i)++]; \
+ if (CBU16_IS_LEAD(c)) { \
+ uint16_t __c2; \
+ if ((i) < (length) && CBU16_IS_TRAIL(__c2 = (s)[(i)])) { \
+ ++(i); \
+ (c) = CBU16_GET_SUPPLEMENTARY((c), __c2); \
+ } \
+ } \
+ }
/**
* Append a code point to a string, overwriting 1 or 2 code units.
@@ -377,14 +385,15 @@ UChar32 utf8_nextCharSafeBody(const uint8 *s, int32 *pi, int32 length, UChar32 c
* @see CBU16_APPEND
* @stable ICU 2.4
*/
-#define CBU16_APPEND_UNSAFE(s, i, c) { \
- if((uint32)(c)<=0xffff) { \
- (s)[(i)++]=(uint16)(c); \
- } else { \
- (s)[(i)++]=(uint16)(((c)>>10)+0xd7c0); \
- (s)[(i)++]=(uint16)(((c)&0x3ff)|0xdc00); \
- } \
-}
+#define CBU16_APPEND_UNSAFE(s, i, c) \
+ { \
+ if ((uint32_t)(c) <= 0xffff) { \
+ (s)[(i)++] = (uint16_t)(c); \
+ } else { \
+ (s)[(i)++] = (uint16_t)(((c) >> 10) + 0xd7c0); \
+ (s)[(i)++] = (uint16_t)(((c)&0x3ff) | 0xdc00); \
+ } \
+ }
} // namesapce base_icu
diff --git a/base/third_party/nspr/prtime.cc b/base/third_party/nspr/prtime.cc
index e7a3b580bb..88bd47b33a 100644
--- a/base/third_party/nspr/prtime.cc
+++ b/base/third_party/nspr/prtime.cc
@@ -65,6 +65,8 @@
* Unit tests are in base/time/pr_time_unittest.cc.
*/
+#include <limits.h>
+
#include "base/logging.h"
#include "base/third_party/nspr/prtime.h"
#include "build/build_config.h"
@@ -107,9 +109,9 @@ PR_ImplodeTime(const PRExplodedTime *exploded)
static const PRTime kSecondsToMicroseconds = static_cast<PRTime>(1000000);
#if defined(OS_WIN)
// Create the system struct representing our exploded time.
- SYSTEMTIME st = {0};
- FILETIME ft = {0};
- ULARGE_INTEGER uli = {0};
+ SYSTEMTIME st = {};
+ FILETIME ft = {};
+ ULARGE_INTEGER uli = {};
st.wYear = exploded->tm_year;
st.wMonth = static_cast<WORD>(exploded->tm_month + 1);
diff --git a/base/thread_task_runner_handle.cc b/base/thread_task_runner_handle.cc
index 860a0ec31d..ee337b382e 100644
--- a/base/thread_task_runner_handle.cc
+++ b/base/thread_task_runner_handle.cc
@@ -12,7 +12,7 @@ namespace base {
namespace {
-base::LazyInstance<base::ThreadLocalPointer<ThreadTaskRunnerHandle> >
+base::LazyInstance<base::ThreadLocalPointer<ThreadTaskRunnerHandle> >::Leaky
lazy_tls_ptr = LAZY_INSTANCE_INITIALIZER;
} // namespace
diff --git a/base/thread_task_runner_handle.h b/base/thread_task_runner_handle.h
index 238435f978..197669ed88 100644
--- a/base/thread_task_runner_handle.h
+++ b/base/thread_task_runner_handle.h
@@ -16,6 +16,7 @@ class SingleThreadTaskRunner;
// in thread-local storage. Callers can then retrieve the TaskRunner
// for the current thread by calling ThreadTaskRunnerHandle::Get().
// At most one TaskRunner may be bound to each thread at a time.
+// Prefer SequenceTaskRunnerHandle to this unless thread affinity is required.
class BASE_EXPORT ThreadTaskRunnerHandle {
public:
// Gets the SingleThreadTaskRunner for the current thread.
diff --git a/base/threading/non_thread_safe_unittest.cc b/base/threading/non_thread_safe_unittest.cc
index 955c939d92..2a27c3fb88 100644
--- a/base/threading/non_thread_safe_unittest.cc
+++ b/base/threading/non_thread_safe_unittest.cc
@@ -2,8 +2,8 @@
// 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/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/threading/non_thread_safe.h"
#include "base/threading/simple_thread.h"
diff --git a/base/threading/platform_thread.h b/base/threading/platform_thread.h
index 3468f45f91..e2b09bcb5b 100644
--- a/base/threading/platform_thread.h
+++ b/base/threading/platform_thread.h
@@ -9,8 +9,10 @@
#ifndef BASE_THREADING_PLATFORM_THREAD_H_
#define BASE_THREADING_PLATFORM_THREAD_H_
+#include <stddef.h>
+
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/time/time.h"
#include "build/build_config.h"
@@ -73,25 +75,9 @@ class PlatformThreadHandle {
typedef pthread_t Handle;
#endif
- PlatformThreadHandle()
- : handle_(0),
- id_(0) {
- }
-
- explicit PlatformThreadHandle(Handle handle)
- : handle_(handle),
- id_(0) {
- }
-
- PlatformThreadHandle(Handle handle,
- PlatformThreadId id)
- : handle_(handle),
- id_(id) {
- }
+ PlatformThreadHandle() : handle_(0) {}
- PlatformThreadId id() const {
- return id_;
- }
+ explicit PlatformThreadHandle(Handle handle) : handle_(handle) {}
bool is_equal(const PlatformThreadHandle& other) const {
return handle_ == other.handle_;
@@ -107,13 +93,12 @@ class PlatformThreadHandle {
private:
Handle handle_;
- PlatformThreadId id_;
};
const PlatformThreadId kInvalidThreadId(0);
-// Valid values for SetThreadPriority(), listed in increasing order of
-// importance.
+// Valid values for priority of Thread::Options and SimpleThread::Options, and
+// SetCurrentThreadPriority(), listed in increasing order of importance.
enum class ThreadPriority {
// Suitable for threads that shouldn't disrupt high priority work.
BACKGROUND,
@@ -172,12 +157,15 @@ class BASE_EXPORT PlatformThread {
// NOTE: When you are done with the thread handle, you must call Join to
// release system resources associated with the thread. You must ensure that
// the Delegate object outlives the thread.
- static bool Create(size_t stack_size, Delegate* delegate,
- PlatformThreadHandle* thread_handle);
+ static bool Create(size_t stack_size,
+ Delegate* delegate,
+ PlatformThreadHandle* thread_handle) {
+ return CreateWithPriority(stack_size, delegate, thread_handle,
+ ThreadPriority::NORMAL);
+ }
// CreateWithPriority() does the same thing as Create() except the priority of
- // the thread is set based on |priority|. Can be used in place of Create()
- // followed by SetThreadPriority().
+ // the thread is set based on |priority|.
static bool CreateWithPriority(size_t stack_size, Delegate* delegate,
PlatformThreadHandle* thread_handle,
ThreadPriority priority);
@@ -192,15 +180,15 @@ class BASE_EXPORT PlatformThread {
// |thread_handle|.
static void Join(PlatformThreadHandle thread_handle);
- // Toggles the target thread's priority at runtime. Prefer
- // CreateWithPriority() to set the thread's initial priority.
- // NOTE: The call may fail if the caller thread is not the same as the
- // target thread on POSIX. For example, seccomp-bpf blocks it by default
- // in the sandbox.
- static void SetThreadPriority(PlatformThreadHandle handle,
- ThreadPriority priority);
+ // Toggles the current thread's priority at runtime. A thread may not be able
+ // to raise its priority back up after lowering it if the process does not
+ // have a proper permission, e.g. CAP_SYS_NICE on Linux.
+ // Since changing other threads' priority is not permitted in favor of
+ // security, this interface is restricted to change only the current thread
+ // priority (https://crbug.com/399473).
+ static void SetCurrentThreadPriority(ThreadPriority priority);
- static ThreadPriority GetThreadPriority(PlatformThreadHandle handle);
+ static ThreadPriority GetCurrentThreadPriority();
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(PlatformThread);
diff --git a/base/threading/platform_thread_internal_posix.h b/base/threading/platform_thread_internal_posix.h
index 62006ce13c..05a8d1e26e 100644
--- a/base/threading/platform_thread_internal_posix.h
+++ b/base/threading/platform_thread_internal_posix.h
@@ -26,17 +26,15 @@ int ThreadPriorityToNiceValue(ThreadPriority priority);
ThreadPriority NiceValueToThreadPriority(int nice_value);
// Allows platform specific tweaks to the generic POSIX solution for
-// SetThreadPriority. Returns true if the platform-specific implementation
-// handled this |priority| change, false if the generic implementation should
-// instead proceed.
-bool SetThreadPriorityForPlatform(PlatformThreadHandle handle,
- ThreadPriority priority);
-
-// Returns true if there is a platform-specific ThreadPriority set on |handle|
-// (and returns the actual ThreadPriority via |priority|). Returns false
-// otherwise, leaving |priority| untouched.
-bool GetThreadPriorityForPlatform(PlatformThreadHandle handle,
- ThreadPriority* priority);
+// SetCurrentThreadPriority. Returns true if the platform-specific
+// implementation handled this |priority| change, false if the generic
+// implementation should instead proceed.
+bool SetCurrentThreadPriorityForPlatform(ThreadPriority priority);
+
+// Returns true if there is a platform-specific ThreadPriority set on the
+// current thread (and returns the actual ThreadPriority via |priority|).
+// Returns false otherwise, leaving |priority| untouched.
+bool GetCurrentThreadPriorityForPlatform(ThreadPriority* priority);
} // namespace internal
diff --git a/base/threading/platform_thread_linux.cc b/base/threading/platform_thread_linux.cc
index 64a97279d9..3e7ee68803 100644
--- a/base/threading/platform_thread_linux.cc
+++ b/base/threading/platform_thread_linux.cc
@@ -6,12 +6,14 @@
#include <errno.h>
#include <sched.h>
+#include <stddef.h>
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/threading/platform_thread_internal_posix.h"
#include "base/threading/thread_id_name_manager.h"
#include "base/tracked_objects.h"
+#include "build/build_config.h"
#if !defined(OS_NACL)
#include <pthread.h>
@@ -27,6 +29,7 @@ namespace internal {
namespace {
#if !defined(OS_NACL)
const struct sched_param kRealTimePrio = {8};
+const struct sched_param kResetPrio = {0};
#endif
} // namespace
@@ -37,11 +40,18 @@ const ThreadPriorityToNiceValuePair kThreadPriorityToNiceValueMap[4] = {
{ThreadPriority::REALTIME_AUDIO, -10},
};
-bool SetThreadPriorityForPlatform(PlatformThreadHandle /* handle */,
- ThreadPriority priority) {
+bool SetCurrentThreadPriorityForPlatform(ThreadPriority priority) {
#if !defined(OS_NACL)
- // TODO(gab): Assess the correctness of using |pthread_self()| below instead
- // of |handle|. http://crbug.com/468793.
+ ThreadPriority current_priority;
+ if (priority != ThreadPriority::REALTIME_AUDIO &&
+ GetCurrentThreadPriorityForPlatform(&current_priority) &&
+ current_priority == ThreadPriority::REALTIME_AUDIO) {
+ // If the pthread's round-robin scheduler is already enabled, and the new
+ // priority will use setpriority() instead, the pthread scheduler should be
+ // reset to use SCHED_OTHER so that setpriority() just works.
+ pthread_setschedparam(pthread_self(), SCHED_OTHER, &kResetPrio);
+ return false;
+ }
return priority == ThreadPriority::REALTIME_AUDIO &&
pthread_setschedparam(pthread_self(), SCHED_RR, &kRealTimePrio) == 0;
#else
@@ -49,13 +59,10 @@ bool SetThreadPriorityForPlatform(PlatformThreadHandle /* handle */,
#endif
}
-bool GetThreadPriorityForPlatform(PlatformThreadHandle /* handle */,
- ThreadPriority* priority) {
+bool GetCurrentThreadPriorityForPlatform(ThreadPriority* priority) {
#if !defined(OS_NACL)
int maybe_sched_rr = 0;
struct sched_param maybe_realtime_prio = {0};
- // TODO(gab): Assess the correctness of using |pthread_self()| below instead
- // of |handle|. http://crbug.com/468793.
if (pthread_getschedparam(pthread_self(), &maybe_sched_rr,
&maybe_realtime_prio) == 0 &&
maybe_sched_rr == SCHED_RR &&
diff --git a/base/threading/platform_thread_mac.mm b/base/threading/platform_thread_mac.mm
index f737854111..df11f852e5 100644
--- a/base/threading/platform_thread_mac.mm
+++ b/base/threading/platform_thread_mac.mm
@@ -8,6 +8,7 @@
#include <mach/mach.h>
#include <mach/mach_time.h>
#include <mach/thread_policy.h>
+#include <stddef.h>
#include <sys/resource.h>
#include <algorithm>
@@ -17,6 +18,7 @@
#include "base/mac/mach_logging.h"
#include "base/threading/thread_id_name_manager.h"
#include "base/tracked_objects.h"
+#include "build/build_config.h"
namespace base {
@@ -155,10 +157,10 @@ void SetPriorityRealtimeAudio(mach_port_t mach_thread_id) {
} // anonymous namespace
// static
-void PlatformThread::SetThreadPriority(PlatformThreadHandle handle,
- ThreadPriority priority) {
+void PlatformThread::SetCurrentThreadPriority(ThreadPriority priority) {
// Convert from pthread_t to mach thread identifier.
- mach_port_t mach_thread_id = pthread_mach_thread_np(handle.platform_handle());
+ mach_port_t mach_thread_id =
+ pthread_mach_thread_np(PlatformThread::CurrentHandle().platform_handle());
switch (priority) {
case ThreadPriority::NORMAL:
@@ -174,8 +176,7 @@ void PlatformThread::SetThreadPriority(PlatformThreadHandle handle,
}
// static
-ThreadPriority PlatformThread::GetThreadPriority(
- PlatformThreadHandle /* handle */) {
+ThreadPriority PlatformThread::GetCurrentThreadPriority() {
NOTIMPLEMENTED();
return ThreadPriority::NORMAL;
}
diff --git a/base/threading/platform_thread_posix.cc b/base/threading/platform_thread_posix.cc
index 0d821a9b7a..39a007316f 100644
--- a/base/threading/platform_thread_posix.cc
+++ b/base/threading/platform_thread_posix.cc
@@ -7,17 +7,18 @@
#include <errno.h>
#include <pthread.h>
#include <sched.h>
+#include <stddef.h>
+#include <stdint.h>
#include <sys/resource.h>
#include <sys/time.h>
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
-#include "base/synchronization/waitable_event.h"
#include "base/threading/platform_thread_internal_posix.h"
#include "base/threading/thread_id_name_manager.h"
#include "base/threading/thread_restrictions.h"
-#include "base/tracked_objects.h"
+#include "build/build_config.h"
#if defined(OS_LINUX)
#include <sys/syscall.h>
@@ -36,38 +37,28 @@ namespace {
struct ThreadParams {
ThreadParams()
- : delegate(NULL),
- joinable(false),
- priority(ThreadPriority::NORMAL),
- handle(NULL),
- handle_set(false, false) {
- }
+ : delegate(NULL), joinable(false), priority(ThreadPriority::NORMAL) {}
PlatformThread::Delegate* delegate;
bool joinable;
ThreadPriority priority;
- PlatformThreadHandle* handle;
- WaitableEvent handle_set;
};
void* ThreadFunc(void* params) {
base::InitOnThread();
- ThreadParams* thread_params = static_cast<ThreadParams*>(params);
- PlatformThread::Delegate* delegate = thread_params->delegate;
- if (!thread_params->joinable)
- base::ThreadRestrictions::SetSingletonAllowed(false);
+ PlatformThread::Delegate* delegate = nullptr;
- if (thread_params->priority != ThreadPriority::NORMAL) {
- PlatformThread::SetThreadPriority(PlatformThread::CurrentHandle(),
- thread_params->priority);
- }
+ {
+ scoped_ptr<ThreadParams> thread_params(static_cast<ThreadParams*>(params));
- // Stash the id in the handle so the calling thread has a complete
- // handle, and unblock the parent thread.
- *(thread_params->handle) = PlatformThreadHandle(pthread_self(),
- PlatformThread::CurrentId());
- thread_params->handle_set.Signal();
+ delegate = thread_params->delegate;
+ if (!thread_params->joinable)
+ base::ThreadRestrictions::SetSingletonAllowed(false);
+
+ if (thread_params->priority != ThreadPriority::NORMAL)
+ PlatformThread::SetCurrentThreadPriority(thread_params->priority);
+ }
ThreadIdNameManager::GetInstance()->RegisterThread(
PlatformThread::CurrentHandle().platform_handle(),
@@ -83,21 +74,21 @@ void* ThreadFunc(void* params) {
return NULL;
}
-bool CreateThread(size_t stack_size, bool joinable,
+bool CreateThread(size_t stack_size,
+ bool joinable,
PlatformThread::Delegate* delegate,
PlatformThreadHandle* thread_handle,
ThreadPriority priority) {
+ DCHECK(thread_handle);
base::InitThreading();
- bool success = false;
pthread_attr_t attributes;
pthread_attr_init(&attributes);
// Pthreads are joinable by default, so only specify the detached
// attribute if the thread should be non-joinable.
- if (!joinable) {
+ if (!joinable)
pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_DETACHED);
- }
// Get a better default if available.
if (stack_size == 0)
@@ -106,33 +97,27 @@ bool CreateThread(size_t stack_size, bool joinable,
if (stack_size > 0)
pthread_attr_setstacksize(&attributes, stack_size);
- ThreadParams params;
- params.delegate = delegate;
- params.joinable = joinable;
- params.priority = priority;
- params.handle = thread_handle;
+ scoped_ptr<ThreadParams> params(new ThreadParams);
+ params->delegate = delegate;
+ params->joinable = joinable;
+ params->priority = priority;
pthread_t handle;
- int err = pthread_create(&handle,
- &attributes,
- ThreadFunc,
- &params);
- success = !err;
- if (!success) {
+ int err = pthread_create(&handle, &attributes, ThreadFunc, params.get());
+ bool success = !err;
+ if (success) {
+ // ThreadParams should be deleted on the created thread after used.
+ ignore_result(params.release());
+ } else {
// Value of |handle| is undefined if pthread_create fails.
handle = 0;
errno = err;
PLOG(ERROR) << "pthread_create";
}
+ *thread_handle = PlatformThreadHandle(handle);
pthread_attr_destroy(&attributes);
- // Don't let this call complete until the thread id
- // is set in the handle.
- if (success)
- params.handle_set.Wait();
- CHECK_EQ(handle, thread_handle->platform_handle());
-
return success;
}
@@ -154,9 +139,9 @@ PlatformThreadId PlatformThread::CurrentId() {
return pthread_self();
#elif defined(OS_NACL) && !defined(__GLIBC__)
// Pointers are 32-bits in NaCl.
- return reinterpret_cast<int32>(pthread_self());
+ return reinterpret_cast<int32_t>(pthread_self());
#elif defined(OS_POSIX)
- return reinterpret_cast<int64>(pthread_self());
+ return reinterpret_cast<int64_t>(pthread_self());
#endif
}
@@ -167,7 +152,7 @@ PlatformThreadRef PlatformThread::CurrentRef() {
// static
PlatformThreadHandle PlatformThread::CurrentHandle() {
- return PlatformThreadHandle(pthread_self(), CurrentId());
+ return PlatformThreadHandle(pthread_self());
}
// static
@@ -196,18 +181,9 @@ const char* PlatformThread::GetName() {
}
// static
-bool PlatformThread::Create(size_t stack_size, Delegate* delegate,
- PlatformThreadHandle* thread_handle) {
- base::ThreadRestrictions::ScopedAllowWait allow_wait;
- return CreateThread(stack_size, true /* joinable thread */,
- delegate, thread_handle, ThreadPriority::NORMAL);
-}
-
-// static
bool PlatformThread::CreateWithPriority(size_t stack_size, Delegate* delegate,
PlatformThreadHandle* thread_handle,
ThreadPriority priority) {
- base::ThreadRestrictions::ScopedAllowWait allow_wait;
return CreateThread(stack_size, true, // joinable thread
delegate, thread_handle, priority);
}
@@ -216,7 +192,6 @@ bool PlatformThread::CreateWithPriority(size_t stack_size, Delegate* delegate,
bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) {
PlatformThreadHandle unused;
- base::ThreadRestrictions::ScopedAllowWait allow_wait;
bool result = CreateThread(stack_size, false /* non-joinable thread */,
delegate, &unused, ThreadPriority::NORMAL);
return result;
@@ -231,16 +206,15 @@ void PlatformThread::Join(PlatformThreadHandle thread_handle) {
CHECK_EQ(0, pthread_join(thread_handle.platform_handle(), NULL));
}
-// Mac has its own Set/GetThreadPriority() implementations.
+// Mac has its own Set/GetCurrentThreadPriority() implementations.
#if !defined(OS_MACOSX)
// static
-void PlatformThread::SetThreadPriority(PlatformThreadHandle handle,
- ThreadPriority priority) {
+void PlatformThread::SetCurrentThreadPriority(ThreadPriority priority) {
#if defined(OS_NACL)
NOTIMPLEMENTED();
#else
- if (internal::SetThreadPriorityForPlatform(handle, priority))
+ if (internal::SetCurrentThreadPriorityForPlatform(priority))
return;
// setpriority(2) should change the whole thread group's (i.e. process)
@@ -249,39 +223,34 @@ void PlatformThread::SetThreadPriority(PlatformThreadHandle handle,
// Linux/NPTL implementation of POSIX threads, the nice value is a per-thread
// attribute". Also, 0 is prefered to the current thread id since it is
// equivalent but makes sandboxing easier (https://crbug.com/399473).
- DCHECK_NE(handle.id(), kInvalidThreadId);
const int nice_setting = internal::ThreadPriorityToNiceValue(priority);
- const PlatformThreadId current_id = PlatformThread::CurrentId();
- if (setpriority(PRIO_PROCESS, handle.id() == current_id ? 0 : handle.id(),
- nice_setting)) {
- DVPLOG(1) << "Failed to set nice value of thread (" << handle.id()
- << ") to " << nice_setting;
+ if (setpriority(PRIO_PROCESS, 0, nice_setting)) {
+ DVPLOG(1) << "Failed to set nice value of thread ("
+ << PlatformThread::CurrentId() << ") to " << nice_setting;
}
#endif // defined(OS_NACL)
}
// static
-ThreadPriority PlatformThread::GetThreadPriority(PlatformThreadHandle handle) {
+ThreadPriority PlatformThread::GetCurrentThreadPriority() {
#if defined(OS_NACL)
NOTIMPLEMENTED();
return ThreadPriority::NORMAL;
#else
- // Mirrors SetThreadPriority()'s implementation.
+ // Mirrors SetCurrentThreadPriority()'s implementation.
ThreadPriority platform_specific_priority;
- if (internal::GetThreadPriorityForPlatform(handle,
- &platform_specific_priority)) {
+ if (internal::GetCurrentThreadPriorityForPlatform(
+ &platform_specific_priority)) {
return platform_specific_priority;
}
- DCHECK_NE(handle.id(), kInvalidThreadId);
- const PlatformThreadId current_id = PlatformThread::CurrentId();
// Need to clear errno before calling getpriority():
// http://man7.org/linux/man-pages/man2/getpriority.2.html
errno = 0;
- int nice_value =
- getpriority(PRIO_PROCESS, handle.id() == current_id ? 0 : handle.id());
+ int nice_value = getpriority(PRIO_PROCESS, 0);
if (errno != 0) {
- DVPLOG(1) << "Failed to get nice value of thread (" << handle.id() << ")";
+ DVPLOG(1) << "Failed to get nice value of thread ("
+ << PlatformThread::CurrentId() << ")";
return ThreadPriority::NORMAL;
}
diff --git a/base/threading/platform_thread_unittest.cc b/base/threading/platform_thread_unittest.cc
index c4b3d5d7ec..52f8d1ba6f 100644
--- a/base/threading/platform_thread_unittest.cc
+++ b/base/threading/platform_thread_unittest.cc
@@ -2,13 +2,19 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stddef.h>
+
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/platform_thread.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
-#if defined(OS_WIN)
+#if defined(OS_POSIX)
+#include <sys/types.h>
+#include <unistd.h>
+#elif defined(OS_WIN)
#include <windows.h>
#endif
@@ -16,6 +22,8 @@ namespace base {
// Trivial tests that thread runs and doesn't crash on create and join ---------
+namespace {
+
class TrivialThread : public PlatformThread::Delegate {
public:
TrivialThread() : did_run_(false) {}
@@ -30,6 +38,8 @@ class TrivialThread : public PlatformThread::Delegate {
DISALLOW_COPY_AND_ASSIGN(TrivialThread);
};
+} // namespace
+
TEST(PlatformThreadTest, Trivial) {
TrivialThread thread;
PlatformThreadHandle handle;
@@ -56,11 +66,13 @@ TEST(PlatformThreadTest, TrivialTimesTen) {
// Tests of basic thread functions ---------------------------------------------
+namespace {
+
class FunctionTestThread : public PlatformThread::Delegate {
public:
FunctionTestThread()
: thread_id_(kInvalidThreadId),
- thread_started_(true, false),
+ termination_ready_(true, false),
terminate_thread_(true, false),
done_(false) {}
~FunctionTestThread() override {
@@ -70,8 +82,9 @@ class FunctionTestThread : public PlatformThread::Delegate {
<< "WaitableEvent blocking the underlying thread's main.";
}
- // Grabs |thread_id_|, signals |thread_started_|, and then waits for
- // |terminate_thread_| to be signaled before exiting.
+ // Grabs |thread_id_|, runs an optional test on that thread, signals
+ // |termination_ready_|, and then waits for |terminate_thread_| to be
+ // signaled before exiting.
void ThreadMain() override {
thread_id_ = PlatformThread::CurrentId();
EXPECT_NE(thread_id_, kInvalidThreadId);
@@ -79,39 +92,46 @@ class FunctionTestThread : public PlatformThread::Delegate {
// Make sure that the thread ID is the same across calls.
EXPECT_EQ(thread_id_, PlatformThread::CurrentId());
- thread_started_.Signal();
+ // Run extra tests.
+ RunTest();
+ termination_ready_.Signal();
terminate_thread_.Wait();
done_ = true;
}
PlatformThreadId thread_id() const {
- EXPECT_TRUE(thread_started_.IsSignaled()) << "Thread ID still unknown";
+ EXPECT_TRUE(termination_ready_.IsSignaled()) << "Thread ID still unknown";
return thread_id_;
}
bool IsRunning() const {
- return thread_started_.IsSignaled() && !done_;
+ return termination_ready_.IsSignaled() && !done_;
}
- // Blocks until this thread is started.
- void WaitForThreadStart() { thread_started_.Wait(); }
+ // Blocks until this thread is started and ready to be terminated.
+ void WaitForTerminationReady() { termination_ready_.Wait(); }
- // Mark this thread for termination (callers must then join this thread to be
+ // Marks this thread for termination (callers must then join this thread to be
// guaranteed of termination).
void MarkForTermination() { terminate_thread_.Signal(); }
private:
+ // Runs an optional test on the newly created thread.
+ virtual void RunTest() {}
+
PlatformThreadId thread_id_;
- mutable WaitableEvent thread_started_;
+ mutable WaitableEvent termination_ready_;
WaitableEvent terminate_thread_;
bool done_;
DISALLOW_COPY_AND_ASSIGN(FunctionTestThread);
};
+} // namespace
+
TEST(PlatformThreadTest, Function) {
PlatformThreadId main_thread_id = PlatformThread::CurrentId();
@@ -120,7 +140,7 @@ TEST(PlatformThreadTest, Function) {
ASSERT_FALSE(thread.IsRunning());
ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
- thread.WaitForThreadStart();
+ thread.WaitForTerminationReady();
ASSERT_TRUE(thread.IsRunning());
EXPECT_NE(thread.thread_id(), main_thread_id);
@@ -144,7 +164,7 @@ TEST(PlatformThreadTest, FunctionTimesTen) {
for (size_t n = 0; n < arraysize(thread); n++)
ASSERT_TRUE(PlatformThread::Create(0, &thread[n], &handle[n]));
for (size_t n = 0; n < arraysize(thread); n++)
- thread[n].WaitForThreadStart();
+ thread[n].WaitForTerminationReady();
for (size_t n = 0; n < arraysize(thread); n++) {
ASSERT_TRUE(thread[n].IsRunning());
@@ -170,106 +190,86 @@ TEST(PlatformThreadTest, FunctionTimesTen) {
namespace {
const ThreadPriority kThreadPriorityTestValues[] = {
-// Disable non-normal priority toggling on POSIX as it appears to be broken
-// (http://crbug.com/468793). This is prefered to disabling the tests altogether
-// on POSIX as it at least provides coverage for running this code under
-// "normal" priority.
-#if !defined(OS_POSIX)
- ThreadPriority::DISPLAY,
+// The order should be higher to lower to cover as much cases as possible on
+// Linux trybots running without CAP_SYS_NICE permission.
+#if !defined(OS_ANDROID)
+ // PlatformThread::GetCurrentThreadPriority() on Android does not support
+ // REALTIME_AUDIO case. See http://crbug.com/505474.
ThreadPriority::REALTIME_AUDIO,
- // Keep BACKGROUND second to last to test backgrounding from other
- // priorities.
+#endif
+ ThreadPriority::DISPLAY,
+ // This redundant BACKGROUND priority is to test backgrounding from other
+ // priorities, and unbackgrounding.
ThreadPriority::BACKGROUND,
-#endif // !defined(OS_POSIX)
- // Keep NORMAL last to test unbackgrounding.
- ThreadPriority::NORMAL
-};
-
-} // namespace
-
-// Test changing another thread's priority.
-// NOTE: This test is partially disabled on POSIX, see note above and
-// http://crbug.com/468793.
-TEST(PlatformThreadTest, ThreadPriorityOtherThread) {
- PlatformThreadHandle current_handle(PlatformThread::CurrentHandle());
-
- // Confirm that the current thread's priority is as expected.
- EXPECT_EQ(ThreadPriority::NORMAL,
- PlatformThread::GetThreadPriority(current_handle));
-
- // Create a test thread.
- FunctionTestThread thread;
- PlatformThreadHandle handle;
- ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
- thread.WaitForThreadStart();
- EXPECT_NE(thread.thread_id(), kInvalidThreadId);
- EXPECT_NE(thread.thread_id(), PlatformThread::CurrentId());
-
- // New threads should get normal priority by default.
- EXPECT_EQ(ThreadPriority::NORMAL, PlatformThread::GetThreadPriority(handle));
-
- // Toggle each supported priority on the test thread and confirm it only
- // affects it (and not the current thread).
- for (size_t i = 0; i < arraysize(kThreadPriorityTestValues); ++i) {
- SCOPED_TRACE(i);
+ ThreadPriority::NORMAL,
+ ThreadPriority::BACKGROUND};
+
+bool IsBumpingPriorityAllowed() {
+#if defined(OS_POSIX)
+ // Only root can raise thread priority on POSIX environment. On Linux, users
+ // who have CAP_SYS_NICE permission also can raise the thread priority, but
+ // libcap.so would be needed to check the capability.
+ return geteuid() == 0;
+#else
+ return true;
+#endif
+}
- // Alter and verify the test thread's priority.
- PlatformThread::SetThreadPriority(handle, kThreadPriorityTestValues[i]);
- EXPECT_EQ(kThreadPriorityTestValues[i],
- PlatformThread::GetThreadPriority(handle));
+class ThreadPriorityTestThread : public FunctionTestThread {
+ public:
+ ThreadPriorityTestThread() = default;
+ ~ThreadPriorityTestThread() override = default;
- // Make sure the current thread was otherwise unaffected.
+ private:
+ void RunTest() override {
+ // Confirm that the current thread's priority is as expected.
EXPECT_EQ(ThreadPriority::NORMAL,
- PlatformThread::GetThreadPriority(current_handle));
+ PlatformThread::GetCurrentThreadPriority());
+
+ // Toggle each supported priority on the current thread and confirm it
+ // affects it.
+ const bool bumping_priority_allowed = IsBumpingPriorityAllowed();
+ for (size_t i = 0; i < arraysize(kThreadPriorityTestValues); ++i) {
+ SCOPED_TRACE(i);
+ if (!bumping_priority_allowed &&
+ kThreadPriorityTestValues[i] >
+ PlatformThread::GetCurrentThreadPriority()) {
+ continue;
+ }
+
+ // Alter and verify the current thread's priority.
+ PlatformThread::SetCurrentThreadPriority(kThreadPriorityTestValues[i]);
+ EXPECT_EQ(kThreadPriorityTestValues[i],
+ PlatformThread::GetCurrentThreadPriority());
+ }
}
- thread.MarkForTermination();
- PlatformThread::Join(handle);
-}
+ DISALLOW_COPY_AND_ASSIGN(ThreadPriorityTestThread);
+};
-// Test changing the current thread's priority (which has different semantics on
-// some platforms).
-// NOTE: This test is partially disabled on POSIX, see note above and
-// http://crbug.com/468793.
-TEST(PlatformThreadTest, ThreadPriorityCurrentThread) {
- PlatformThreadHandle current_handle(PlatformThread::CurrentHandle());
+} // namespace
- // Confirm that the current thread's priority is as expected.
- EXPECT_EQ(ThreadPriority::NORMAL,
- PlatformThread::GetThreadPriority(current_handle));
+#if defined(OS_MACOSX)
+// PlatformThread::GetCurrentThreadPriority() is not implemented on OS X.
+#define MAYBE_ThreadPriorityCurrentThread DISABLED_ThreadPriorityCurrentThread
+#else
+#define MAYBE_ThreadPriorityCurrentThread ThreadPriorityCurrentThread
+#endif
- // Create a test thread for verification purposes only.
- FunctionTestThread thread;
+// Test changing a created thread's priority (which has different semantics on
+// some platforms).
+TEST(PlatformThreadTest, MAYBE_ThreadPriorityCurrentThread) {
+ ThreadPriorityTestThread thread;
PlatformThreadHandle handle;
- ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
- thread.WaitForThreadStart();
- EXPECT_NE(thread.thread_id(), kInvalidThreadId);
- EXPECT_NE(thread.thread_id(), PlatformThread::CurrentId());
-
- // Confirm that the new thread's priority is as expected.
- EXPECT_EQ(ThreadPriority::NORMAL, PlatformThread::GetThreadPriority(handle));
-
- // Toggle each supported priority on the current thread and confirm it only
- // affects it (and not the test thread).
- for (size_t i = 0; i < arraysize(kThreadPriorityTestValues); ++i) {
- SCOPED_TRACE(i);
-
- // Alter and verify the current thread's priority.
- PlatformThread::SetThreadPriority(current_handle,
- kThreadPriorityTestValues[i]);
- EXPECT_EQ(kThreadPriorityTestValues[i],
- PlatformThread::GetThreadPriority(current_handle));
-
- // Make sure the test thread was otherwise unaffected.
- EXPECT_EQ(ThreadPriority::NORMAL,
- PlatformThread::GetThreadPriority(handle));
- }
- // Restore current thread priority for follow-up tests.
- PlatformThread::SetThreadPriority(current_handle, ThreadPriority::NORMAL);
+ ASSERT_FALSE(thread.IsRunning());
+ ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
+ thread.WaitForTerminationReady();
+ ASSERT_TRUE(thread.IsRunning());
thread.MarkForTermination();
PlatformThread::Join(handle);
+ ASSERT_FALSE(thread.IsRunning());
}
} // namespace base
diff --git a/base/threading/post_task_and_reply_impl.cc b/base/threading/post_task_and_reply_impl.cc
index f3e88abf60..80ca52009f 100644
--- a/base/threading/post_task_and_reply_impl.cc
+++ b/base/threading/post_task_and_reply_impl.cc
@@ -75,6 +75,9 @@ bool PostTaskAndReplyImpl::PostTaskAndReply(
const tracked_objects::Location& from_here,
const Closure& task,
const Closure& reply) {
+ // TODO(tzik): Use DCHECK here once the crash is gone. http://crbug.com/541319
+ CHECK(!task.is_null()) << from_here.ToString();
+ CHECK(!reply.is_null()) << from_here.ToString();
PostTaskAndReplyRelay* relay =
new PostTaskAndReplyRelay(from_here, task, reply);
if (!PostTask(from_here, Bind(&PostTaskAndReplyRelay::Run,
diff --git a/base/threading/sequenced_worker_pool.cc b/base/threading/sequenced_worker_pool.cc
index 7bbca92a2f..3cc50f404c 100644
--- a/base/threading/sequenced_worker_pool.cc
+++ b/base/threading/sequenced_worker_pool.cc
@@ -4,6 +4,8 @@
#include "base/threading/sequenced_worker_pool.h"
+#include <stdint.h>
+
#include <list>
#include <map>
#include <set>
@@ -16,6 +18,7 @@
#include "base/critical_closure.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/linked_ptr.h"
#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
@@ -29,6 +32,7 @@
#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
#include "base/tracked_objects.h"
+#include "build/build_config.h"
#if defined(OS_MACOSX)
#include "base/mac/scoped_nsautorelease_pool.h"
@@ -62,7 +66,7 @@ struct SequencedTask : public TrackingInfo {
int sequence_token_id;
int trace_id;
- int64 sequence_task_number;
+ int64_t sequence_task_number;
SequencedWorkerPool::WorkerShutdown shutdown_behavior;
tracked_objects::Location posted_from;
Closure task;
@@ -213,16 +217,11 @@ bool SequencedWorkerPoolSequencedTaskRunner::PostNonNestableDelayedTask(
// Create 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 SequencedTask& task,
- void* pool) {
- return (static_cast<uint64>(task.trace_id) << 32) |
- static_cast<uint64>(reinterpret_cast<intptr_t>(pool));
+uint64_t GetTaskTraceID(const SequencedTask& task, void* pool) {
+ return (static_cast<uint64_t>(task.trace_id) << 32) |
+ static_cast<uint64_t>(reinterpret_cast<intptr_t>(pool));
}
-base::LazyInstance<base::ThreadLocalPointer<
- SequencedWorkerPool::SequenceToken> >::Leaky g_lazy_tls_ptr =
- LAZY_INSTANCE_INITIALIZER;
-
} // namespace
// Worker ---------------------------------------------------------------------
@@ -239,6 +238,9 @@ class SequencedWorkerPool::Worker : public SimpleThread {
// SimpleThread implementation. This actually runs the background thread.
void Run() override;
+ // Gets the worker for the current thread out of thread-local storage.
+ static Worker* GetForCurrentThread();
+
// Indicates that a task is about to be run. The parameters provide
// additional metainformation about the task being run.
void set_running_task_info(SequenceToken token,
@@ -264,7 +266,14 @@ class SequencedWorkerPool::Worker : public SimpleThread {
return task_shutdown_behavior_;
}
+ scoped_refptr<SequencedWorkerPool> worker_pool() const {
+ return worker_pool_;
+ }
+
private:
+ static LazyInstance<ThreadLocalPointer<SequencedWorkerPool::Worker>>::Leaky
+ lazy_tls_ptr_;
+
scoped_refptr<SequencedWorkerPool> worker_pool_;
// The sequence token of the task being processed. Only valid when
// is_processing_task_ is true.
@@ -290,7 +299,7 @@ class SequencedWorkerPool::Inner {
~Inner();
- SequenceToken GetSequenceToken();
+ static SequenceToken GetSequenceToken();
SequenceToken GetNamedSequenceToken(const std::string& name);
@@ -308,6 +317,11 @@ class SequencedWorkerPool::Inner {
bool IsRunningSequenceOnCurrentThread(SequenceToken sequence_token) const;
+ bool IsRunningSequence(SequenceToken sequence_token) const;
+
+ void SetRunningTaskInfoForCurrentThread(SequenceToken sequence_token,
+ WorkerShutdown shutdown_behavior);
+
void CleanupForTesting();
void SignalHasWorkForTesting();
@@ -341,7 +355,7 @@ class SequencedWorkerPool::Inner {
int LockedGetNamedTokenID(const std::string& name);
// Called from within the lock, this returns the next sequence task number.
- int64 LockedGetNextSequenceTaskNumber();
+ int64_t LockedGetNextSequenceTaskNumber();
// Gets new task. There are 3 cases depending on the return value:
//
@@ -457,7 +471,7 @@ class SequencedWorkerPool::Inner {
PendingTaskSet pending_tasks_;
// The next sequence number for a new sequenced task.
- int64 next_sequence_task_number_;
+ int64_t next_sequence_task_number_;
// Number of tasks in the pending_tasks_ list that are marked as blocking
// shutdown.
@@ -508,9 +522,10 @@ void SequencedWorkerPool::Worker::Run() {
win::ScopedCOMInitializer com_initializer;
#endif
- // Store a pointer to the running sequence in thread local storage for
- // static function access.
- g_lazy_tls_ptr.Get().Set(&task_sequence_token_);
+ // Store a pointer to this worker in thread local storage for static function
+ // access.
+ DCHECK(!lazy_tls_ptr_.Get().Get());
+ lazy_tls_ptr_.Get().Set(this);
// Just jump back to the Inner object to run the thread, since it has all the
// tracking information and queues. It might be more natural to implement
@@ -519,9 +534,23 @@ void SequencedWorkerPool::Worker::Run() {
// send thread-specific information easily to the thread loop.
worker_pool_->inner_->ThreadLoop(this);
// Release our cyclic reference once we're done.
- worker_pool_ = NULL;
+ worker_pool_ = nullptr;
}
+// static
+SequencedWorkerPool::Worker*
+SequencedWorkerPool::Worker::GetForCurrentThread() {
+ // Don't construct lazy instance on check.
+ if (lazy_tls_ptr_ == nullptr)
+ return nullptr;
+
+ return lazy_tls_ptr_.Get().Get();
+}
+
+// static
+LazyInstance<ThreadLocalPointer<SequencedWorkerPool::Worker>>::Leaky
+ SequencedWorkerPool::Worker::lazy_tls_ptr_ = LAZY_INSTANCE_INITIALIZER;
+
// Inner definitions ---------------------------------------------------------
SequencedWorkerPool::Inner::Inner(
@@ -562,6 +591,7 @@ SequencedWorkerPool::Inner::~Inner() {
testing_observer_->OnDestruct();
}
+// static
SequencedWorkerPool::SequenceToken
SequencedWorkerPool::Inner::GetSequenceToken() {
// Need to add one because StaticAtomicSequenceNumber starts at zero, which
@@ -619,9 +649,10 @@ bool SequencedWorkerPool::Inner::PostTask(
// The trace_id is used for identifying the task in about:tracing.
sequenced.trace_id = trace_id_++;
- TRACE_EVENT_FLOW_BEGIN0(TRACE_DISABLED_BY_DEFAULT("toplevel.flow"),
- "SequencedWorkerPool::PostTask",
- TRACE_ID_MANGLE(GetTaskTraceID(sequenced, static_cast<void*>(this))));
+ TRACE_EVENT_WITH_FLOW0(TRACE_DISABLED_BY_DEFAULT("toplevel.flow"),
+ "SequencedWorkerPool::Inner::PostTask",
+ TRACE_ID_MANGLE(GetTaskTraceID(sequenced, static_cast<void*>(this))),
+ TRACE_EVENT_FLAG_FLOW_OUT);
sequenced.sequence_task_number = LockedGetNextSequenceTaskNumber();
@@ -661,6 +692,28 @@ bool SequencedWorkerPool::Inner::IsRunningSequenceOnCurrentThread(
sequence_token.Equals(found->second->task_sequence_token());
}
+bool SequencedWorkerPool::Inner::IsRunningSequence(
+ SequenceToken sequence_token) const {
+ DCHECK(sequence_token.IsValid());
+ AutoLock lock(lock_);
+ return !IsSequenceTokenRunnable(sequence_token.id_);
+}
+
+void SequencedWorkerPool::Inner::SetRunningTaskInfoForCurrentThread(
+ SequenceToken sequence_token,
+ WorkerShutdown shutdown_behavior) {
+ AutoLock lock(lock_);
+ ThreadMap::const_iterator found = threads_.find(PlatformThread::CurrentId());
+ DCHECK(found != threads_.end());
+ DCHECK(found->second->is_processing_task());
+ DCHECK(!found->second->task_sequence_token().IsValid());
+ found->second->set_running_task_info(sequence_token, shutdown_behavior);
+
+ // Mark the sequence token as in use.
+ bool success = current_sequences_.insert(sequence_token.id_).second;
+ DCHECK(success);
+}
+
// See https://code.google.com/p/chromium/issues/detail?id=168415
void SequencedWorkerPool::Inner::CleanupForTesting() {
DCHECK(!RunsTasksOnCurrentThread());
@@ -754,12 +807,12 @@ void SequencedWorkerPool::Inner::ThreadLoop(Worker* this_worker) {
GetWorkStatus status =
GetWork(&task, &wait_time, &delete_these_outside_lock);
if (status == GET_WORK_FOUND) {
- TRACE_EVENT_FLOW_END0(TRACE_DISABLED_BY_DEFAULT("toplevel.flow"),
- "SequencedWorkerPool::PostTask",
- TRACE_ID_MANGLE(GetTaskTraceID(task, static_cast<void*>(this))));
- TRACE_EVENT2("toplevel", "SequencedWorkerPool::ThreadLoop",
- "src_file", task.posted_from.file_name(),
- "src_func", task.posted_from.function_name());
+ TRACE_EVENT_WITH_FLOW2(TRACE_DISABLED_BY_DEFAULT("toplevel.flow"),
+ "SequencedWorkerPool::Inner::ThreadLoop",
+ TRACE_ID_MANGLE(GetTaskTraceID(task, static_cast<void*>(this))),
+ TRACE_EVENT_FLAG_FLOW_IN,
+ "src_file", task.posted_from.file_name(),
+ "src_func", task.posted_from.function_name());
int new_thread_id = WillRunWorkerTask(task);
{
AutoUnlock unlock(lock_);
@@ -785,6 +838,11 @@ void SequencedWorkerPool::Inner::ThreadLoop(Worker* this_worker) {
tracked_objects::ThreadData::TallyRunOnNamedThreadIfTracking(
task, stopwatch);
+ // Update the sequence token in case it has been set from within the
+ // task, so it can be removed from the set of currently running
+ // sequences in DidRunWorkerTask() below.
+ task.sequence_token_id = this_worker->task_sequence_token().id_;
+
// Make sure our task is erased outside the lock for the
// same reason we do this with delete_these_oustide_lock.
// Also, do it before calling reset_running_task_info() so
@@ -919,7 +977,7 @@ int SequencedWorkerPool::Inner::LockedGetNamedTokenID(
return result.id_;
}
-int64 SequencedWorkerPool::Inner::LockedGetNextSequenceTaskNumber() {
+int64_t SequencedWorkerPool::Inner::LockedGetNextSequenceTaskNumber() {
lock_.AssertAcquired();
// We assume that we never create enough tasks to wrap around.
return next_sequence_task_number_++;
@@ -1144,17 +1202,55 @@ SequencedWorkerPool::Inner::g_last_sequence_number_;
// SequencedWorkerPool --------------------------------------------------------
+std::string SequencedWorkerPool::SequenceToken::ToString() const {
+ return base::StringPrintf("[%d]", id_);
+}
+
// static
SequencedWorkerPool::SequenceToken
SequencedWorkerPool::GetSequenceTokenForCurrentThread() {
- // Don't construct lazy instance on check.
- if (g_lazy_tls_ptr == NULL)
+ Worker* worker = Worker::GetForCurrentThread();
+ if (!worker)
return SequenceToken();
- SequencedWorkerPool::SequenceToken* token = g_lazy_tls_ptr.Get().Get();
- if (!token)
- return SequenceToken();
- return *token;
+ return worker->task_sequence_token();
+}
+
+// static
+scoped_refptr<SequencedWorkerPool>
+SequencedWorkerPool::GetWorkerPoolForCurrentThread() {
+ Worker* worker = Worker::GetForCurrentThread();
+ if (!worker)
+ return nullptr;
+
+ return worker->worker_pool();
+}
+
+// static
+scoped_refptr<SequencedTaskRunner>
+SequencedWorkerPool::GetSequencedTaskRunnerForCurrentThread() {
+ Worker* worker = Worker::GetForCurrentThread();
+
+ // If there is no worker, this thread is not a worker thread. Otherwise, it is
+ // currently running a task (sequenced or unsequenced).
+ if (!worker)
+ return nullptr;
+
+ scoped_refptr<SequencedWorkerPool> pool = worker->worker_pool();
+ SequenceToken sequence_token = worker->task_sequence_token();
+ WorkerShutdown shutdown_behavior = worker->task_shutdown_behavior();
+ if (!sequence_token.IsValid()) {
+ // Create a new sequence token and bind this thread to it, to make sure that
+ // a task posted to the SequencedTaskRunner we are going to return is not
+ // immediately going to run on a different thread.
+ sequence_token = Inner::GetSequenceToken();
+ pool->inner_->SetRunningTaskInfoForCurrentThread(sequence_token,
+ shutdown_behavior);
+ }
+
+ DCHECK(pool->IsRunningSequenceOnCurrentThread(sequence_token));
+ return new SequencedWorkerPoolSequencedTaskRunner(
+ std::move(pool), sequence_token, shutdown_behavior);
}
SequencedWorkerPool::SequencedWorkerPool(size_t max_threads,
@@ -1173,8 +1269,7 @@ SequencedWorkerPool::SequencedWorkerPool(size_t max_threads,
SequencedWorkerPool::~SequencedWorkerPool() {}
void SequencedWorkerPool::OnDestruct() const {
- // Avoid deleting ourselves on a worker thread (which would
- // deadlock).
+ // Avoid deleting ourselves on a worker thread (which would deadlock).
if (RunsTasksOnCurrentThread()) {
constructor_task_runner_->DeleteSoon(FROM_HERE, this);
} else {
@@ -1182,8 +1277,9 @@ void SequencedWorkerPool::OnDestruct() const {
}
}
+// static
SequencedWorkerPool::SequenceToken SequencedWorkerPool::GetSequenceToken() {
- return inner_->GetSequenceToken();
+ return Inner::GetSequenceToken();
}
SequencedWorkerPool::SequenceToken SequencedWorkerPool::GetNamedSequenceToken(
@@ -1287,6 +1383,11 @@ bool SequencedWorkerPool::IsRunningSequenceOnCurrentThread(
return inner_->IsRunningSequenceOnCurrentThread(sequence_token);
}
+bool SequencedWorkerPool::IsRunningSequence(
+ SequenceToken sequence_token) const {
+ return inner_->IsRunningSequence(sequence_token);
+}
+
void SequencedWorkerPool::FlushForTesting() {
inner_->CleanupForTesting();
}
diff --git a/base/threading/sequenced_worker_pool.h b/base/threading/sequenced_worker_pool.h
index ee282bc231..ba0e444210 100644
--- a/base/threading/sequenced_worker_pool.h
+++ b/base/threading/sequenced_worker_pool.h
@@ -5,12 +5,14 @@
#ifndef BASE_THREADING_SEQUENCED_WORKER_POOL_H_
#define BASE_THREADING_SEQUENCED_WORKER_POOL_H_
+#include <stddef.h>
+
#include <cstddef>
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/callback_forward.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/single_thread_task_runner.h"
@@ -45,7 +47,8 @@ class SequencedTaskRunner;
// destruction will be visible to T2.
//
// Example:
-// SequencedWorkerPool::SequenceToken token = pool.GetSequenceToken();
+// SequencedWorkerPool::SequenceToken token =
+// SequencedWorkerPool::GetSequenceToken();
// pool.PostSequencedWorkerTask(token, SequencedWorkerPool::SKIP_ON_SHUTDOWN,
// FROM_HERE, base::Bind(...));
// pool.PostSequencedWorkerTask(token, SequencedWorkerPool::SKIP_ON_SHUTDOWN,
@@ -121,7 +124,7 @@ class BASE_EXPORT SequencedWorkerPool : public TaskRunner {
// Opaque identifier that defines sequencing of tasks posted to the worker
// pool.
- class SequenceToken {
+ class BASE_EXPORT SequenceToken {
public:
SequenceToken() : id_(0) {}
~SequenceToken() {}
@@ -135,6 +138,10 @@ class BASE_EXPORT SequencedWorkerPool : public TaskRunner {
return id_ != 0;
}
+ // Returns a string representation of this token. This method should only be
+ // used for debugging.
+ std::string ToString() const;
+
private:
friend class SequencedWorkerPool;
@@ -157,25 +164,38 @@ class BASE_EXPORT SequencedWorkerPool : public TaskRunner {
// an unsequenced task, returns an invalid SequenceToken.
static SequenceToken GetSequenceTokenForCurrentThread();
+ // Gets a SequencedTaskRunner for the current thread. If the current thread is
+ // running an unsequenced task, a new SequenceToken will be generated and set,
+ // so that the returned SequencedTaskRunner is guaranteed to run tasks after
+ // the current task has finished running.
+ static scoped_refptr<SequencedTaskRunner>
+ GetSequencedTaskRunnerForCurrentThread();
+
+ // Returns a unique token that can be used to sequence tasks posted to
+ // PostSequencedWorkerTask(). Valid tokens are always nonzero.
+ // TODO(bauerb): Rename this to better differentiate from
+ // GetSequenceTokenForCurrentThread().
+ static SequenceToken GetSequenceToken();
+
+ // Returns the SequencedWorkerPool that owns this thread, or null if the
+ // current thread is not a SequencedWorkerPool worker thread.
+ static scoped_refptr<SequencedWorkerPool> GetWorkerPoolForCurrentThread();
+
// When constructing a SequencedWorkerPool, there must be a
- // MessageLoop on the current thread unless you plan to deliberately
- // leak it.
+ // ThreadTaskRunnerHandle on the current thread unless you plan to
+ // deliberately leak it.
// Pass the maximum number of threads (they will be lazily created as needed)
// and a prefix for the thread name to aid in debugging.
SequencedWorkerPool(size_t max_threads,
const std::string& thread_name_prefix);
- // Like above, but with |observer| for testing. Does not take
- // ownership of |observer|.
+ // Like above, but with |observer| for testing. Does not take ownership of
+ // |observer|.
SequencedWorkerPool(size_t max_threads,
const std::string& thread_name_prefix,
TestingObserver* observer);
- // Returns a unique token that can be used to sequence tasks posted to
- // PostSequencedWorkerTask(). Valid tokens are always nonzero.
- SequenceToken GetSequenceToken();
-
// Returns the sequence token associated with the given name. Calling this
// function multiple times with the same string will always produce the
// same sequence token. If the name has not been used before, a new token
@@ -300,6 +320,10 @@ class BASE_EXPORT SequencedWorkerPool : public TaskRunner {
// sequence_token.
bool IsRunningSequenceOnCurrentThread(SequenceToken sequence_token) const;
+ // Returns true if any thread is currently processing a task with the given
+ // sequence token. Should only be called with a valid sequence token.
+ bool IsRunningSequence(SequenceToken sequence_token) const;
+
// Blocks until all pending tasks are complete. This should only be called in
// unit tests when you want to validate something that should have happened.
// This will not flush delayed tasks; delayed tasks get deleted.
diff --git a/base/threading/simple_thread.h b/base/threading/simple_thread.h
index 36548d36fd..3deeb1018c 100644
--- a/base/threading/simple_thread.h
+++ b/base/threading/simple_thread.h
@@ -40,16 +40,17 @@
#ifndef BASE_THREADING_SIMPLE_THREAD_H_
#define BASE_THREADING_SIMPLE_THREAD_H_
-#include <string>
+#include <stddef.h>
+
#include <queue>
+#include <string>
#include <vector>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/compiler_specific.h"
-#include "base/threading/platform_thread.h"
#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
+#include "base/threading/platform_thread.h"
namespace base {
@@ -59,8 +60,10 @@ class BASE_EXPORT SimpleThread : public PlatformThread::Delegate {
public:
class BASE_EXPORT Options {
public:
- Options() : stack_size_(0), priority_(ThreadPriority::NORMAL) { }
- ~Options() { }
+ Options() : stack_size_(0), priority_(ThreadPriority::NORMAL) {}
+ explicit Options(ThreadPriority priority)
+ : stack_size_(0), priority_(priority) {}
+ ~Options() {}
// We use the standard compiler-supplied copy constructor.
@@ -109,12 +112,6 @@ class BASE_EXPORT SimpleThread : public PlatformThread::Delegate {
// Overridden from PlatformThread::Delegate:
void ThreadMain() override;
- // Only set priorities with a careful understanding of the consequences.
- // This is meant for very limited use cases.
- void SetThreadPriority(ThreadPriority priority) {
- PlatformThread::SetThreadPriority(thread_, priority);
- }
-
private:
const std::string name_prefix_;
std::string name_;
diff --git a/base/threading/thread.cc b/base/threading/thread.cc
index b3e74e3d57..783add8798 100644
--- a/base/threading/thread.cc
+++ b/base/threading/thread.cc
@@ -11,6 +11,7 @@
#include "base/threading/thread_id_name_manager.h"
#include "base/threading/thread_local.h"
#include "base/threading/thread_restrictions.h"
+#include "build/build_config.h"
#if defined(OS_WIN)
#include "base/win/scoped_com_initializer.h"
@@ -61,9 +62,12 @@ Thread::Thread(const std::string& name)
stopping_(false),
running_(false),
thread_(0),
+ id_(kInvalidThreadId),
+ id_event_(true, false),
message_loop_(nullptr),
message_loop_timer_slack_(TIMER_SLACK_NONE),
- name_(name) {
+ name_(name),
+ start_event_(false, false) {
}
Thread::~Thread() {
@@ -86,6 +90,10 @@ bool Thread::StartWithOptions(const Options& options) {
(options.message_loop_type == MessageLoop::TYPE_UI));
#endif
+ // Reset |id_| here to support restarting the thread.
+ id_event_.Reset();
+ id_ = kInvalidThreadId;
+
SetThreadWasQuitProperly(false);
MessageLoop::Type type = options.message_loop_type;
@@ -93,30 +101,27 @@ bool Thread::StartWithOptions(const Options& options) {
type = MessageLoop::TYPE_CUSTOM;
message_loop_timer_slack_ = options.timer_slack;
- message_loop_ = new MessageLoop(type, options.message_pump_factory);
-
- start_event_.reset(new WaitableEvent(false, false));
+ scoped_ptr<MessageLoop> message_loop = MessageLoop::CreateUnbound(
+ type, options.message_pump_factory);
+ message_loop_ = message_loop.get();
+ start_event_.Reset();
// Hold the thread_lock_ while starting a new thread, so that we can make sure
// that thread_ is populated before the newly created thread accesses it.
{
AutoLock lock(thread_lock_);
- bool created;
- if (options.priority == ThreadPriority::NORMAL) {
- created = PlatformThread::Create(options.stack_size, this, &thread_);
- } else {
- created = PlatformThread::CreateWithPriority(options.stack_size, this,
- &thread_, options.priority);
- }
- if (!created) {
+ if (!PlatformThread::CreateWithPriority(options.stack_size, this, &thread_,
+ options.priority)) {
DLOG(ERROR) << "failed to create thread";
- delete message_loop_;
message_loop_ = nullptr;
- start_event_.reset();
return false;
}
}
+ // The ownership of message_loop is managemed by the newly created thread
+ // within the ThreadMain.
+ ignore_result(message_loop.release());
+
DCHECK(message_loop_);
return true;
}
@@ -129,16 +134,17 @@ bool Thread::StartAndWaitForTesting() {
return true;
}
-bool Thread::WaitUntilThreadStarted() {
- if (!start_event_)
+bool Thread::WaitUntilThreadStarted() const {
+ if (!message_loop_)
return false;
base::ThreadRestrictions::ScopedAllowWait allow_wait;
- start_event_->Wait();
+ start_event_.Wait();
return true;
}
void Thread::Stop() {
- if (!start_event_)
+ AutoLock lock(thread_lock_);
+ if (thread_.is_null())
return;
StopSoon();
@@ -149,20 +155,18 @@ void Thread::Stop() {
// the thread exits. Some consumers are abusing the API. Make them stop.
//
PlatformThread::Join(thread_);
+ thread_ = base::PlatformThreadHandle();
- // The thread should NULL message_loop_ on exit.
+ // The thread should nullify message_loop_ on exit.
DCHECK(!message_loop_);
- // The thread no longer needs to be joined.
- start_event_.reset();
-
stopping_ = false;
}
void Thread::StopSoon() {
// We should only be called on the same thread that started us.
- DCHECK_NE(thread_id(), PlatformThread::CurrentId());
+ DCHECK_NE(GetThreadId(), PlatformThread::CurrentId());
if (stopping_ || !message_loop_)
return;
@@ -171,9 +175,11 @@ void Thread::StopSoon() {
task_runner()->PostTask(FROM_HERE, base::Bind(&ThreadQuitHelper));
}
-PlatformThreadId Thread::thread_id() const {
- AutoLock lock(thread_lock_);
- return thread_.id();
+PlatformThreadId Thread::GetThreadId() const {
+ // If the thread is created but not started yet, wait for |id_| being ready.
+ base::ThreadRestrictions::ScopedAllowWait allow_wait;
+ id_event_.Wait();
+ return id_;
}
bool Thread::IsRunning() const {
@@ -189,13 +195,6 @@ bool Thread::IsRunning() const {
return running_;
}
-void Thread::SetPriority(ThreadPriority priority) {
- // The thread must be started (and id known) for this to be
- // compatible with all platforms.
- DCHECK(message_loop_ != nullptr);
- PlatformThread::SetThreadPriority(thread_, priority);
-}
-
void Thread::Run(MessageLoop* message_loop) {
message_loop->Run();
}
@@ -213,6 +212,12 @@ bool Thread::GetThreadWasQuitProperly() {
}
void Thread::ThreadMain() {
+ // First, make GetThreadId() available to avoid deadlocks. It could be called
+ // any place in the following thread initialization code.
+ id_ = PlatformThread::CurrentId();
+ DCHECK_NE(kInvalidThreadId, id_);
+ id_event_.Signal();
+
// Complete the initialization of our Thread object.
PlatformThread::SetName(name_.c_str());
@@ -232,10 +237,6 @@ void Thread::ThreadMain() {
}
#endif
- // Make sure the thread_id() returns current thread.
- // (This internally acquires lock against PlatformThread::Create)
- DCHECK_EQ(thread_id(), PlatformThread::CurrentId());
-
// Let the thread do extra initialization.
Init();
@@ -244,7 +245,7 @@ void Thread::ThreadMain() {
running_ = true;
}
- start_event_->Signal();
+ start_event_.Signal();
Run(message_loop_);
@@ -260,12 +261,16 @@ void Thread::ThreadMain() {
com_initializer.reset();
#endif
- // Assert that MessageLoop::Quit was called by ThreadQuitHelper.
- DCHECK(GetThreadWasQuitProperly());
+ if (message_loop->type() != MessageLoop::TYPE_CUSTOM) {
+ // Assert that MessageLoop::QuitWhenIdle was called by ThreadQuitHelper.
+ // Don't check for custom message pumps, because their shutdown might not
+ // allow this.
+ DCHECK(GetThreadWasQuitProperly());
+ }
// We can't receive messages anymore.
// (The message loop is destructed at the end of this block)
- message_loop_ = NULL;
+ message_loop_ = nullptr;
}
} // namespace base
diff --git a/base/threading/thread.h b/base/threading/thread.h
index 6b7005809b..da985da07a 100644
--- a/base/threading/thread.h
+++ b/base/threading/thread.h
@@ -5,21 +5,25 @@
#ifndef BASE_THREADING_THREAD_H_
#define BASE_THREADING_THREAD_H_
+#include <stddef.h>
+
#include <string>
#include "base/base_export.h"
#include "base/callback.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/message_loop/timer_slack.h"
#include "base/single_thread_task_runner.h"
#include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event.h"
#include "base/threading/platform_thread.h"
+#include "build/build_config.h"
namespace base {
class MessagePump;
-class WaitableEvent;
// A simple thread abstraction that establishes a MessageLoop on a new thread.
// The consumer uses the MessageLoop of the thread to cause code to execute on
@@ -86,7 +90,7 @@ class BASE_EXPORT Thread : PlatformThread::Delegate {
// init_com_with_mta(false) and then StartWithOptions() with any message loop
// type other than TYPE_UI.
void init_com_with_mta(bool use_mta) {
- DCHECK(!start_event_);
+ DCHECK(!message_loop_);
com_status_ = use_mta ? MTA : STA;
}
#endif
@@ -118,7 +122,7 @@ class BASE_EXPORT Thread : PlatformThread::Delegate {
// Blocks until the thread starts running. Called within StartAndWait().
// Note that calling this causes jank on the calling thread, must be used
// carefully for production code.
- bool WaitUntilThreadStarted();
+ bool WaitUntilThreadStarted() const;
// Signals the thread to exit and returns once the thread has exited. After
// this method returns, the Thread object is completely reset and may be used
@@ -148,27 +152,15 @@ class BASE_EXPORT Thread : PlatformThread::Delegate {
// Returns the message loop for this thread. Use the MessageLoop's
// PostTask methods to execute code on the thread. This only returns
// non-null after a successful call to Start. After Stop has been called,
- // this will return NULL.
+ // this will return nullptr.
//
// NOTE: You must not call this MessageLoop's Quit method directly. Use
// the Thread's Stop method instead.
//
MessageLoop* message_loop() const { return message_loop_; }
- // Returns a MessageLoopProxy for this thread. Use the MessageLoopProxy's
- // PostTask methods to execute code on the thread. Returns NULL if the thread
- // is not running (e.g. before Start or after Stop have been called). Callers
- // can hold on to this even after the thread is gone; in this situation,
- // attempts to PostTask() will fail.
- //
- // Note: This method is deprecated. Callers should call task_runner() instead
- // and use the TaskRunner interfaces for safely interfacing with the Thread.
- scoped_refptr<MessageLoopProxy> message_loop_proxy() const {
- return message_loop_ ? message_loop_->message_loop_proxy() : NULL;
- }
-
// Returns a TaskRunner for this thread. Use the TaskRunner's PostTask
- // methods to execute code on the thread. Returns NULL if the thread is not
+ // methods to execute code on the thread. Returns nullptr if the thread is not
// running (e.g. before Start or after Stop have been called). Callers can
// hold on to this even after the thread is gone; in this situation, attempts
// to PostTask() will fail.
@@ -182,15 +174,17 @@ class BASE_EXPORT Thread : PlatformThread::Delegate {
// The native thread handle.
PlatformThreadHandle thread_handle() { return thread_; }
- // The thread ID.
- PlatformThreadId thread_id() const;
+ // Returns the thread ID. Should not be called before the first Start*()
+ // call. Keeps on returning the same ID even after a Stop() call. The next
+ // Start*() call renews the ID.
+ //
+ // WARNING: This function will block if the thread hasn't started yet.
+ //
+ PlatformThreadId GetThreadId() const;
// Returns true if the thread has been started, and not yet stopped.
bool IsRunning() const;
- // Sets the thread priority. The thread must already be started.
- void SetPriority(ThreadPriority priority);
-
protected:
// Called just prior to starting the message loop
virtual void Init() {}
@@ -226,16 +220,22 @@ class BASE_EXPORT Thread : PlatformThread::Delegate {
#endif
// If true, we're in the middle of stopping, and shouldn't access
- // |message_loop_|. It may non-NULL and invalid.
+ // |message_loop_|. It may non-nullptr and invalid.
+ // Should be written on the thread that created this thread. Also read data
+ // could be wrong on other threads.
bool stopping_;
// True while inside of Run().
bool running_;
- mutable base::Lock running_lock_; // Protects running_.
+ mutable base::Lock running_lock_; // Protects |running_|.
// The thread's handle.
PlatformThreadHandle thread_;
- mutable base::Lock thread_lock_; // Protects thread_.
+ mutable base::Lock thread_lock_; // Protects |thread_|.
+
+ // The thread's id once it has started.
+ PlatformThreadId id_;
+ mutable WaitableEvent id_event_; // Protects |id_|.
// The thread's message loop. Valid only while the thread is alive. Set
// by the created thread.
@@ -248,8 +248,8 @@ class BASE_EXPORT Thread : PlatformThread::Delegate {
// The name of the thread. Used for debugging purposes.
std::string name_;
- // Non-null if the thread has successfully started.
- scoped_ptr<WaitableEvent> start_event_;
+ // Signaled when the created thread gets ready to use the message loop.
+ mutable WaitableEvent start_event_;
friend void ThreadQuitHelper();
diff --git a/base/threading/thread_checker.h b/base/threading/thread_checker.h
index 449247af9d..1d970f093e 100644
--- a/base/threading/thread_checker.h
+++ b/base/threading/thread_checker.h
@@ -5,23 +5,19 @@
#ifndef BASE_THREADING_THREAD_CHECKER_H_
#define BASE_THREADING_THREAD_CHECKER_H_
+#include "base/logging.h"
+#include "base/threading/thread_checker_impl.h"
+
// Apart from debug builds, we also enable the thread checker in
// builds with DCHECK_ALWAYS_ON so that trybots and waterfall bots
// with this define will get the same level of thread checking as
// debug bots.
-//
-// Note that this does not perfectly match situations where DCHECK is
-// enabled. For example a non-official release build may have
-// DCHECK_ALWAYS_ON undefined (and therefore ThreadChecker would be
-// disabled) but have DCHECKs enabled at runtime.
-#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON))
+#if DCHECK_IS_ON()
#define ENABLE_THREAD_CHECKER 1
#else
#define ENABLE_THREAD_CHECKER 0
#endif
-#include "base/threading/thread_checker_impl.h"
-
namespace base {
// Do nothing implementation, for use in release mode.
diff --git a/base/threading/thread_checker_unittest.cc b/base/threading/thread_checker_unittest.cc
index d42cbc2627..fd98f764ed 100644
--- a/base/threading/thread_checker_unittest.cc
+++ b/base/threading/thread_checker_unittest.cc
@@ -2,11 +2,11 @@
// 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/macros.h"
#include "base/memory/scoped_ptr.h"
-#include "base/threading/thread_checker.h"
#include "base/threading/simple_thread.h"
+#include "base/threading/thread_checker.h"
#include "testing/gtest/include/gtest/gtest.h"
// Duplicated from base/threading/thread_checker.h so that we can be
diff --git a/base/threading/thread_collision_warner.h b/base/threading/thread_collision_warner.h
index de4e9c3eb5..4699a910dd 100644
--- a/base/threading/thread_collision_warner.h
+++ b/base/threading/thread_collision_warner.h
@@ -9,8 +9,8 @@
#include "base/atomicops.h"
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/compiler_specific.h"
+#include "base/macros.h"
// A helper class alongside macros to be used to verify assumptions about thread
// safety of a class.
diff --git a/base/threading/thread_collision_warner_unittest.cc b/base/threading/thread_collision_warner_unittest.cc
index d7ce79ec37..79ca7e2a4c 100644
--- a/base/threading/thread_collision_warner_unittest.cc
+++ b/base/threading/thread_collision_warner_unittest.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/synchronization/lock.h"
#include "base/threading/platform_thread.h"
diff --git a/base/threading/thread_id_name_manager.h b/base/threading/thread_id_name_manager.h
index 927d25fe1e..f469b605e4 100644
--- a/base/threading/thread_id_name_manager.h
+++ b/base/threading/thread_id_name_manager.h
@@ -9,14 +9,15 @@
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/synchronization/lock.h"
#include "base/threading/platform_thread.h"
-template <typename T> struct DefaultSingletonTraits;
-
namespace base {
+template <typename T>
+struct DefaultSingletonTraits;
+
class BASE_EXPORT ThreadIdNameManager {
public:
static ThreadIdNameManager* GetInstance();
diff --git a/base/threading/thread_id_name_manager_unittest.cc b/base/threading/thread_id_name_manager_unittest.cc
index b17c681412..350dc0fa73 100644
--- a/base/threading/thread_id_name_manager_unittest.cc
+++ b/base/threading/thread_id_name_manager_unittest.cc
@@ -24,8 +24,8 @@ TEST_F(ThreadIdNameManagerTest, AddThreads) {
thread_a.StartAndWaitForTesting();
thread_b.StartAndWaitForTesting();
- EXPECT_STREQ(kAThread, manager->GetName(thread_a.thread_id()));
- EXPECT_STREQ(kBThread, manager->GetName(thread_b.thread_id()));
+ EXPECT_STREQ(kAThread, manager->GetName(thread_a.GetThreadId()));
+ EXPECT_STREQ(kBThread, manager->GetName(thread_b.GetThreadId()));
thread_b.Stop();
thread_a.Stop();
@@ -41,10 +41,10 @@ TEST_F(ThreadIdNameManagerTest, RemoveThreads) {
thread_b.StartAndWaitForTesting();
thread_b.Stop();
}
- EXPECT_STREQ(kAThread, manager->GetName(thread_a.thread_id()));
+ EXPECT_STREQ(kAThread, manager->GetName(thread_a.GetThreadId()));
thread_a.Stop();
- EXPECT_STREQ("", manager->GetName(thread_a.thread_id()));
+ EXPECT_STREQ("", manager->GetName(thread_a.GetThreadId()));
}
TEST_F(ThreadIdNameManagerTest, RestartThread) {
@@ -52,13 +52,13 @@ TEST_F(ThreadIdNameManagerTest, RestartThread) {
base::Thread thread_a(kAThread);
thread_a.StartAndWaitForTesting();
- base::PlatformThreadId a_id = thread_a.thread_id();
+ base::PlatformThreadId a_id = thread_a.GetThreadId();
EXPECT_STREQ(kAThread, manager->GetName(a_id));
thread_a.Stop();
thread_a.StartAndWaitForTesting();
EXPECT_STREQ("", manager->GetName(a_id));
- EXPECT_STREQ(kAThread, manager->GetName(thread_a.thread_id()));
+ EXPECT_STREQ(kAThread, manager->GetName(thread_a.GetThreadId()));
thread_a.Stop();
}
diff --git a/base/threading/thread_local.h b/base/threading/thread_local.h
index df9c4b7257..f40420cd2f 100644
--- a/base/threading/thread_local.h
+++ b/base/threading/thread_local.h
@@ -52,8 +52,9 @@
#define BASE_THREADING_THREAD_LOCAL_H_
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/threading/thread_local_storage.h"
+#include "build/build_config.h"
#if defined(OS_POSIX)
#include <pthread.h>
diff --git a/base/threading/thread_local_posix.cc b/base/threading/thread_local_posix.cc
index 75ea4795d4..8bc46ad190 100644
--- a/base/threading/thread_local_posix.cc
+++ b/base/threading/thread_local_posix.cc
@@ -7,6 +7,7 @@
#include <pthread.h>
#include "base/logging.h"
+#include "build/build_config.h"
#if !defined(OS_ANDROID)
diff --git a/base/threading/thread_local_storage.cc b/base/threading/thread_local_storage.cc
index 0bb396cfd7..a7eb527888 100644
--- a/base/threading/thread_local_storage.cc
+++ b/base/threading/thread_local_storage.cc
@@ -6,6 +6,7 @@
#include "base/atomicops.h"
#include "base/logging.h"
+#include "build/build_config.h"
using base::internal::PlatformThreadLocalStorage;
@@ -76,8 +77,10 @@ void** ConstructTlsVector() {
// TLS_KEY_OUT_OF_INDEXES, go ahead and set it. Otherwise, do nothing, as
// another thread already did our dirty work.
if (PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES !=
- base::subtle::NoBarrier_CompareAndSwap(&g_native_tls_key,
- PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES, key)) {
+ static_cast<PlatformThreadLocalStorage::TLSKey>(
+ base::subtle::NoBarrier_CompareAndSwap(
+ &g_native_tls_key,
+ PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES, key))) {
// We've been shortcut. Another thread replaced g_native_tls_key first so
// we need to destroy our index and use the one the other thread got
// first.
@@ -192,8 +195,8 @@ void PlatformThreadLocalStorage::OnThreadExit(void* value) {
} // namespace internal
ThreadLocalStorage::Slot::Slot(TLSDestructorFunc destructor) {
- initialized_ = false;
slot_ = 0;
+ base::subtle::Release_Store(&initialized_, 0);
Initialize(destructor);
}
@@ -211,7 +214,7 @@ void ThreadLocalStorage::StaticSlot::Initialize(TLSDestructorFunc destructor) {
// Setup our destructor.
g_tls_destructors[slot_] = destructor;
- initialized_ = true;
+ base::subtle::Release_Store(&initialized_, 1);
}
void ThreadLocalStorage::StaticSlot::Free() {
@@ -221,7 +224,7 @@ void ThreadLocalStorage::StaticSlot::Free() {
DCHECK_LT(slot_, kThreadLocalStorageSize);
g_tls_destructors[slot_] = NULL;
slot_ = 0;
- initialized_ = false;
+ base::subtle::Release_Store(&initialized_, 0);
}
void* ThreadLocalStorage::StaticSlot::Get() const {
diff --git a/base/threading/thread_local_storage.h b/base/threading/thread_local_storage.h
index 8ba9e5243c..0c7a692a66 100644
--- a/base/threading/thread_local_storage.h
+++ b/base/threading/thread_local_storage.h
@@ -5,8 +5,10 @@
#ifndef BASE_THREADING_THREAD_LOCAL_STORAGE_H_
#define BASE_THREADING_THREAD_LOCAL_STORAGE_H_
+#include "base/atomicops.h"
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
+#include "build/build_config.h"
#if defined(OS_WIN)
#include <windows.h>
@@ -26,7 +28,7 @@ class BASE_EXPORT PlatformThreadLocalStorage {
#if defined(OS_WIN)
typedef unsigned long TLSKey;
- enum { TLS_KEY_OUT_OF_INDEXES = TLS_OUT_OF_INDEXES };
+ enum : unsigned { TLS_KEY_OUT_OF_INDEXES = TLS_OUT_OF_INDEXES };
#elif defined(OS_POSIX)
typedef pthread_key_t TLSKey;
// The following is a "reserved key" which is used in our generic Chromium
@@ -114,10 +116,12 @@ class BASE_EXPORT ThreadLocalStorage {
// value 'value'.
void Set(void* value);
- bool initialized() const { return initialized_; }
+ bool initialized() const {
+ return base::subtle::Acquire_Load(&initialized_) != 0;
+ }
// The internals of this struct should be considered private.
- bool initialized_;
+ base::subtle::Atomic32 initialized_;
int slot_;
};
diff --git a/base/threading/thread_local_storage_unittest.cc b/base/threading/thread_local_storage_unittest.cc
index bcc1d1b9db..322524b10e 100644
--- a/base/threading/thread_local_storage_unittest.cc
+++ b/base/threading/thread_local_storage_unittest.cc
@@ -7,8 +7,10 @@
#include <process.h>
#endif
+#include "base/macros.h"
#include "base/threading/simple_thread.h"
#include "base/threading/thread_local_storage.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#if defined(OS_WIN)
diff --git a/base/threading/thread_restrictions.cc b/base/threading/thread_restrictions.cc
index 871f2dc874..00306c5ae7 100644
--- a/base/threading/thread_restrictions.cc
+++ b/base/threading/thread_restrictions.cc
@@ -23,7 +23,7 @@ LazyInstance<ThreadLocalBoolean>::Leaky
LazyInstance<ThreadLocalBoolean>::Leaky
g_wait_disallowed = LAZY_INSTANCE_INITIALIZER;
-} // anonymous namespace
+} // namespace
// static
bool ThreadRestrictions::SetIOAllowed(bool allowed) {
@@ -69,7 +69,7 @@ void ThreadRestrictions::DisallowWaiting() {
// static
void ThreadRestrictions::AssertWaitAllowed() {
if (g_wait_disallowed.Get().Get()) {
- LOG(FATAL) << "Waiting is not allowed to be used on this thread to prevent"
+ LOG(FATAL) << "Waiting is not allowed to be used on this thread to prevent "
<< "jank and deadlock.";
}
}
diff --git a/base/threading/thread_restrictions.h b/base/threading/thread_restrictions.h
index 4ba70a9c94..fb536ecdaf 100644
--- a/base/threading/thread_restrictions.h
+++ b/base/threading/thread_restrictions.h
@@ -6,7 +6,7 @@
#define BASE_THREADING_THREAD_RESTRICTIONS_H_
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
// See comment at top of thread_checker.h
#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON))
@@ -22,7 +22,7 @@ class ScopedAllowWaitForLegacyWebViewApi;
namespace cc {
class CompletionEvent;
-class TaskGraphRunner;
+class SingleThreadTaskGraphRunner;
}
namespace chromeos {
class BlockingMethodCaller;
@@ -40,10 +40,11 @@ class BrowserShutdownProfileDumper;
class BrowserTestBase;
class GpuChannelHost;
class NestedMessagePumpAndroid;
-class RenderWidgetResizeHelper;
class ScopedAllowWaitForAndroidLayoutTests;
class ScopedAllowWaitForDebugURL;
+class SoftwareOutputDeviceMus;
class TextInputClientMac;
+class RasterWorkerPool;
} // namespace content
namespace dbus {
class Bus;
@@ -52,12 +53,20 @@ namespace disk_cache {
class BackendImpl;
class InFlightIO;
}
+namespace gles2 {
+class CommandBufferClientImpl;
+}
namespace mojo {
namespace common {
-class WatcherThreadManager;
+class MessagePumpMojo;
+}
}
+namespace mus {
+class CommandBufferLocal;
+class GpuState;
}
namespace net {
+class NetworkChangeNotifierMac;
namespace internal {
class AddressTrackerLinux;
}
@@ -67,6 +76,14 @@ namespace remoting {
class AutoThread;
}
+namespace ui {
+class WindowResizeHelperMac;
+}
+
+namespace views {
+class WindowManagerConnection;
+}
+
namespace base {
namespace android {
@@ -174,15 +191,15 @@ class BASE_EXPORT ThreadRestrictions {
friend class content::BrowserShutdownProfileDumper;
friend class content::BrowserTestBase;
friend class content::NestedMessagePumpAndroid;
- friend class content::RenderWidgetResizeHelper;
friend class content::ScopedAllowWaitForAndroidLayoutTests;
friend class content::ScopedAllowWaitForDebugURL;
friend class ::HistogramSynchronizer;
friend class ::ScopedAllowWaitForLegacyWebViewApi;
friend class cc::CompletionEvent;
- friend class cc::TaskGraphRunner;
- friend class mojo::common::WatcherThreadManager;
+ friend class cc::SingleThreadTaskGraphRunner;
+ friend class content::RasterWorkerPool;
friend class remoting::AutoThread;
+ friend class ui::WindowResizeHelperMac;
friend class MessagePumpDefault;
friend class SequencedWorkerPool;
friend class SimpleThread;
@@ -190,6 +207,10 @@ class BASE_EXPORT ThreadRestrictions {
friend class ThreadTestHelper;
friend class PlatformThread;
friend class android::JavaHandlerThread;
+ friend class gles2::CommandBufferClientImpl;
+ friend class mojo::common::MessagePumpMojo;
+ friend class mus::CommandBufferLocal;
+ friend class mus::GpuState;
// END ALLOWED USAGE.
// BEGIN USAGE THAT NEEDS TO BE FIXED.
@@ -206,9 +227,14 @@ class BASE_EXPORT ThreadRestrictions {
friend class disk_cache::BackendImpl; // http://crbug.com/74623
friend class disk_cache::InFlightIO; // http://crbug.com/74623
friend class net::internal::AddressTrackerLinux; // http://crbug.com/125097
+ friend class net::NetworkChangeNotifierMac; // http://crbug.com/125097
friend class ::BrowserProcessImpl; // http://crbug.com/125207
friend class ::NativeBackendKWallet; // http://crbug.com/125331
- // END USAGE THAT NEEDS TO BE FIXED.
+#if !defined(OFFICIAL_BUILD)
+ friend class content::SoftwareOutputDeviceMus; // Interim non-production code
+#endif
+ friend class views::WindowManagerConnection;
+// END USAGE THAT NEEDS TO BE FIXED.
#if ENABLE_THREAD_RESTRICTIONS
static bool SetWaitAllowed(bool allowed);
diff --git a/base/threading/thread_unittest.cc b/base/threading/thread_unittest.cc
index 9993ca6825..f6ecbe64e2 100644
--- a/base/threading/thread_unittest.cc
+++ b/base/threading/thread_unittest.cc
@@ -4,11 +4,15 @@
#include "base/threading/thread.h"
+#include <stddef.h>
+
#include <vector>
#include "base/bind.h"
#include "base/location.h"
#include "base/single_thread_task_runner.h"
+#include "base/synchronization/waitable_event.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
@@ -100,6 +104,15 @@ void RegisterDestructionObserver(
base::MessageLoop::current()->AddDestructionObserver(observer);
}
+// Task that calls GetThreadId() of |thread|, stores the result into |id|, then
+// signal |event|.
+void ReturnThreadId(base::Thread* thread,
+ base::PlatformThreadId* id,
+ base::WaitableEvent* event) {
+ *id = thread->GetThreadId();
+ event->Signal();
+}
+
} // namespace
TEST_F(ThreadTest, Restart) {
@@ -189,6 +202,47 @@ TEST_F(ThreadTest, ThreadName) {
EXPECT_EQ("ThreadName", a.thread_name());
}
+TEST_F(ThreadTest, ThreadId) {
+ Thread a("ThreadId0");
+ Thread b("ThreadId1");
+ a.Start();
+ b.Start();
+
+ // Post a task that calls GetThreadId() on the created thread.
+ base::WaitableEvent event(false, false);
+ base::PlatformThreadId id_from_new_thread;
+ a.task_runner()->PostTask(
+ FROM_HERE, base::Bind(ReturnThreadId, &a, &id_from_new_thread, &event));
+
+ // Call GetThreadId() on the current thread before calling event.Wait() so
+ // that this test can find a race issue with TSAN.
+ base::PlatformThreadId id_from_current_thread = a.GetThreadId();
+
+ // Check if GetThreadId() returns consistent value in both threads.
+ event.Wait();
+ EXPECT_EQ(id_from_current_thread, id_from_new_thread);
+
+ // A started thread should have a valid ID.
+ EXPECT_NE(base::kInvalidThreadId, a.GetThreadId());
+ EXPECT_NE(base::kInvalidThreadId, b.GetThreadId());
+
+ // Each thread should have a different thread ID.
+ EXPECT_NE(a.GetThreadId(), b.GetThreadId());
+}
+
+TEST_F(ThreadTest, ThreadIdWithRestart) {
+ Thread a("ThreadIdWithRestart");
+ base::PlatformThreadId previous_id = base::kInvalidThreadId;
+
+ for (size_t i = 0; i < 16; ++i) {
+ EXPECT_TRUE(a.Start());
+ base::PlatformThreadId current_id = a.GetThreadId();
+ EXPECT_NE(previous_id, current_id);
+ previous_id = current_id;
+ a.Stop();
+ }
+}
+
// Make sure Init() is called after Start() and before
// WaitUntilThreadInitialized() returns.
TEST_F(ThreadTest, SleepInsideInit) {
@@ -232,6 +286,5 @@ TEST_F(ThreadTest, CleanUp) {
TEST_F(ThreadTest, ThreadNotStarted) {
Thread a("Inert");
- EXPECT_EQ(nullptr, a.message_loop_proxy());
EXPECT_EQ(nullptr, a.task_runner());
}
diff --git a/base/threading/worker_pool.cc b/base/threading/worker_pool.cc
index fa750f2290..0b7bf8eca1 100644
--- a/base/threading/worker_pool.cc
+++ b/base/threading/worker_pool.cc
@@ -7,6 +7,7 @@
#include "base/bind.h"
#include "base/compiler_specific.h"
#include "base/lazy_instance.h"
+#include "base/macros.h"
#include "base/task_runner.h"
#include "base/threading/post_task_and_reply_impl.h"
#include "base/tracked_objects.h"
@@ -20,7 +21,7 @@ class PostTaskAndReplyWorkerPool : public internal::PostTaskAndReplyImpl {
explicit PostTaskAndReplyWorkerPool(bool task_is_slow)
: task_is_slow_(task_is_slow) {
}
- virtual ~PostTaskAndReplyWorkerPool() = default;
+ ~PostTaskAndReplyWorkerPool() override = default;
private:
bool PostTask(const tracked_objects::Location& from_here,
diff --git a/base/threading/worker_pool_posix.cc b/base/threading/worker_pool_posix.cc
index 1757f5e09b..e6b1d649e6 100644
--- a/base/threading/worker_pool_posix.cc
+++ b/base/threading/worker_pool_posix.cc
@@ -4,10 +4,13 @@
#include "base/threading/worker_pool_posix.h"
+#include <stddef.h>
+
#include "base/bind.h"
#include "base/callback.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/strings/stringprintf.h"
#include "base/threading/platform_thread.h"
@@ -33,7 +36,8 @@ class WorkerPoolImpl {
~WorkerPoolImpl();
void PostTask(const tracked_objects::Location& from_here,
- const base::Closure& task, bool task_is_slow);
+ const base::Closure& task,
+ bool task_is_slow);
private:
scoped_refptr<base::PosixDynamicThreadPool> pool_;
@@ -41,8 +45,7 @@ class WorkerPoolImpl {
WorkerPoolImpl::WorkerPoolImpl()
: pool_(new base::PosixDynamicThreadPool("WorkerPool",
- kIdleSecondsBeforeExit)) {
-}
+ kIdleSecondsBeforeExit)) {}
WorkerPoolImpl::~WorkerPoolImpl() {
pool_->Terminate();
@@ -61,8 +64,7 @@ class WorkerThread : public PlatformThread::Delegate {
public:
WorkerThread(const std::string& name_prefix,
base::PosixDynamicThreadPool* pool)
- : name_prefix_(name_prefix),
- pool_(pool) {}
+ : name_prefix_(name_prefix), pool_(pool) {}
void ThreadMain() override;
@@ -75,8 +77,8 @@ class WorkerThread : public PlatformThread::Delegate {
void WorkerThread::ThreadMain() {
g_worker_pool_running_on_this_thread.Get().Set(true);
- const std::string name = base::StringPrintf(
- "%s/%d", name_prefix_.c_str(), PlatformThread::CurrentId());
+ const std::string name = base::StringPrintf("%s/%d", name_prefix_.c_str(),
+ PlatformThread::CurrentId());
// Note |name.c_str()| must remain valid for for the whole life of the thread.
PlatformThread::SetName(name);
@@ -105,7 +107,8 @@ void WorkerThread::ThreadMain() {
// static
bool WorkerPool::PostTask(const tracked_objects::Location& from_here,
- const base::Closure& task, bool task_is_slow) {
+ const base::Closure& task,
+ bool task_is_slow) {
g_lazy_worker_pool.Pointer()->PostTask(from_here, task, task_is_slow);
return true;
}
@@ -146,8 +149,8 @@ void PosixDynamicThreadPool::PostTask(
void PosixDynamicThreadPool::AddTask(PendingTask* pending_task) {
AutoLock locked(lock_);
- DCHECK(!terminated_) <<
- "This thread pool is already terminated. Do not post new tasks.";
+ DCHECK(!terminated_)
+ << "This thread pool is already terminated. Do not post new tasks.";
pending_tasks_.push(*pending_task);
pending_task->task.Reset();
@@ -158,8 +161,7 @@ void PosixDynamicThreadPool::AddTask(PendingTask* pending_task) {
} else {
// The new PlatformThread will take ownership of the WorkerThread object,
// which will delete itself on exit.
- WorkerThread* worker =
- new WorkerThread(name_prefix_, this);
+ WorkerThread* worker = new WorkerThread(name_prefix_, this);
PlatformThread::CreateNonJoinable(0, worker);
}
}
diff --git a/base/threading/worker_pool_posix.h b/base/threading/worker_pool_posix.h
index dd0ffb656f..f8971aca7d 100644
--- a/base/threading/worker_pool_posix.h
+++ b/base/threading/worker_pool_posix.h
@@ -27,9 +27,9 @@
#include <queue>
#include <string>
-#include "base/basictypes.h"
#include "base/callback_forward.h"
#include "base/location.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/pending_task.h"
diff --git a/base/threading/worker_pool_posix_unittest.cc b/base/threading/worker_pool_posix_unittest.cc
index 354a99c538..99a9369607 100644
--- a/base/threading/worker_pool_posix_unittest.cc
+++ b/base/threading/worker_pool_posix_unittest.cc
@@ -8,10 +8,11 @@
#include "base/bind.h"
#include "base/callback.h"
+#include "base/macros.h"
#include "base/synchronization/condition_variable.h"
#include "base/synchronization/lock.h"
-#include "base/threading/platform_thread.h"
#include "base/synchronization/waitable_event.h"
+#include "base/threading/platform_thread.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
@@ -90,7 +91,7 @@ void BlockingIncrementingTask(const BlockingIncrementingTaskArgs& args) {
class PosixDynamicThreadPoolTest : public testing::Test {
protected:
PosixDynamicThreadPoolTest()
- : pool_(new base::PosixDynamicThreadPool("dynamic_pool", 60*60)),
+ : pool_(new base::PosixDynamicThreadPool("dynamic_pool", 60 * 60)),
peer_(pool_.get()),
counter_(0),
num_waiting_to_start_(0),
@@ -103,7 +104,8 @@ class PosixDynamicThreadPoolTest : public testing::Test {
void TearDown() override {
// Wake up the idle threads so they can terminate.
- if (pool_.get()) pool_->Terminate();
+ if (pool_.get())
+ pool_->Terminate();
}
void WaitForTasksToStart(int num_tasks) {
diff --git a/base/threading/worker_pool_unittest.cc b/base/threading/worker_pool_unittest.cc
index 9a9ab951b9..27af50be67 100644
--- a/base/threading/worker_pool_unittest.cc
+++ b/base/threading/worker_pool_unittest.cc
@@ -13,6 +13,7 @@
#include "base/test/test_timeouts.h"
#include "base/threading/thread_checker_impl.h"
#include "base/time/time.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
diff --git a/base/time/pr_time_unittest.cc b/base/time/pr_time_unittest.cc
index 06043a5b8e..3f1a348ae8 100644
--- a/base/time/pr_time_unittest.cc
+++ b/base/time/pr_time_unittest.cc
@@ -6,8 +6,10 @@
#include <time.h>
#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "base/third_party/nspr/prtime.h"
#include "base/time/time.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::Time;
diff --git a/base/time/time.cc b/base/time/time.cc
index 8cbb382bb9..76ffeb7441 100644
--- a/base/time/time.cc
+++ b/base/time/time.cc
@@ -12,8 +12,10 @@
#include "base/lazy_instance.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/strings/stringprintf.h"
#include "base/third_party/nspr/prtime.h"
+#include "build/build_config.h"
namespace base {
@@ -21,7 +23,7 @@ namespace base {
// static
TimeDelta TimeDelta::Max() {
- return TimeDelta(std::numeric_limits<int64>::max());
+ return TimeDelta(std::numeric_limits<int64_t>::max());
}
int TimeDelta::InDays() const {
@@ -56,10 +58,10 @@ double TimeDelta::InSecondsF() const {
return static_cast<double>(delta_) / Time::kMicrosecondsPerSecond;
}
-int64 TimeDelta::InSeconds() const {
+int64_t TimeDelta::InSeconds() const {
if (is_max()) {
// Preserve max to prevent overflow.
- return std::numeric_limits<int64>::max();
+ return std::numeric_limits<int64_t>::max();
}
return delta_ / Time::kMicrosecondsPerSecond;
}
@@ -72,46 +74,46 @@ double TimeDelta::InMillisecondsF() const {
return static_cast<double>(delta_) / Time::kMicrosecondsPerMillisecond;
}
-int64 TimeDelta::InMilliseconds() const {
+int64_t TimeDelta::InMilliseconds() const {
if (is_max()) {
// Preserve max to prevent overflow.
- return std::numeric_limits<int64>::max();
+ return std::numeric_limits<int64_t>::max();
}
return delta_ / Time::kMicrosecondsPerMillisecond;
}
-int64 TimeDelta::InMillisecondsRoundedUp() const {
+int64_t TimeDelta::InMillisecondsRoundedUp() const {
if (is_max()) {
// Preserve max to prevent overflow.
- return std::numeric_limits<int64>::max();
+ return std::numeric_limits<int64_t>::max();
}
return (delta_ + Time::kMicrosecondsPerMillisecond - 1) /
Time::kMicrosecondsPerMillisecond;
}
-int64 TimeDelta::InMicroseconds() const {
+int64_t TimeDelta::InMicroseconds() const {
if (is_max()) {
// Preserve max to prevent overflow.
- return std::numeric_limits<int64>::max();
+ return std::numeric_limits<int64_t>::max();
}
return delta_;
}
namespace time_internal {
-int64 SaturatedAdd(TimeDelta delta, int64 value) {
- CheckedNumeric<int64> rv(delta.delta_);
+int64_t SaturatedAdd(TimeDelta delta, int64_t value) {
+ CheckedNumeric<int64_t> rv(delta.delta_);
rv += value;
return FromCheckedNumeric(rv);
}
-int64 SaturatedSub(TimeDelta delta, int64 value) {
- CheckedNumeric<int64> rv(delta.delta_);
+int64_t SaturatedSub(TimeDelta delta, int64_t value) {
+ CheckedNumeric<int64_t> rv(delta.delta_);
rv -= value;
return FromCheckedNumeric(rv);
}
-int64 FromCheckedNumeric(const CheckedNumeric<int64> value) {
+int64_t FromCheckedNumeric(const CheckedNumeric<int64_t> value) {
if (value.IsValid())
return value.ValueUnsafe();
@@ -119,7 +121,7 @@ int64 FromCheckedNumeric(const CheckedNumeric<int64> value) {
// is. Instead, return max/(-max), which is something that clients can reason
// about.
// TODO(rvargas) crbug.com/332611: don't use internal values.
- int64 limit = std::numeric_limits<int64>::max();
+ int64_t limit = std::numeric_limits<int64_t>::max();
if (value.validity() == internal::RANGE_UNDERFLOW)
limit = -limit;
return value.ValueOrDefault(limit);
@@ -135,7 +137,7 @@ std::ostream& operator<<(std::ostream& os, TimeDelta time_delta) {
// static
Time Time::Max() {
- return Time(std::numeric_limits<int64>::max());
+ return Time(std::numeric_limits<int64_t>::max());
}
// static
@@ -144,7 +146,7 @@ Time Time::FromTimeT(time_t tt) {
return Time(); // Preserve 0 so we can tell it doesn't exist.
if (tt == std::numeric_limits<time_t>::max())
return Max();
- return Time((tt * kMicrosecondsPerSecond) + kTimeTToMicrosecondsOffset);
+ return Time(kTimeTToMicrosecondsOffset) + TimeDelta::FromSeconds(tt);
}
time_t Time::ToTimeT() const {
@@ -154,7 +156,7 @@ time_t Time::ToTimeT() const {
// Preserve max without offset to prevent overflow.
return std::numeric_limits<time_t>::max();
}
- if (std::numeric_limits<int64>::max() - kTimeTToMicrosecondsOffset <= us_) {
+ if (std::numeric_limits<int64_t>::max() - kTimeTToMicrosecondsOffset <= us_) {
DLOG(WARNING) << "Overflow when converting base::Time with internal " <<
"value " << us_ << " to time_t.";
return std::numeric_limits<time_t>::max();
@@ -166,11 +168,7 @@ time_t Time::ToTimeT() const {
Time Time::FromDoubleT(double dt) {
if (dt == 0 || std::isnan(dt))
return Time(); // Preserve 0 so we can tell it doesn't exist.
- if (dt == std::numeric_limits<double>::infinity())
- return Max();
- return Time(static_cast<int64>((dt *
- static_cast<double>(kMicrosecondsPerSecond)) +
- kTimeTToMicrosecondsOffset));
+ return Time(kTimeTToMicrosecondsOffset) + TimeDelta::FromSecondsD(dt);
}
double Time::ToDoubleT() const {
@@ -197,10 +195,8 @@ Time Time::FromTimeSpec(const timespec& ts) {
Time Time::FromJsTime(double ms_since_epoch) {
// The epoch is a valid time, so this constructor doesn't interpret
// 0 as the null time.
- if (ms_since_epoch == std::numeric_limits<double>::infinity())
- return Max();
- return Time(static_cast<int64>(ms_since_epoch * kMicrosecondsPerMillisecond) +
- kTimeTToMicrosecondsOffset);
+ return Time(kTimeTToMicrosecondsOffset) +
+ TimeDelta::FromMillisecondsD(ms_since_epoch);
}
double Time::ToJsTime() const {
@@ -216,14 +212,14 @@ double Time::ToJsTime() const {
kMicrosecondsPerMillisecond);
}
-int64 Time::ToJavaTime() const {
+int64_t Time::ToJavaTime() const {
if (is_null()) {
// Preserve 0 so the invalid result doesn't depend on the platform.
return 0;
}
if (is_max()) {
// Preserve max without offset to prevent overflow.
- return std::numeric_limits<int64>::max();
+ return std::numeric_limits<int64_t>::max();
}
return ((us_ - kTimeTToMicrosecondsOffset) /
kMicrosecondsPerMillisecond);
@@ -332,11 +328,6 @@ std::ostream& operator<<(std::ostream& os, ThreadTicks thread_ticks) {
return os << as_time_delta.InMicroseconds() << " bogo-thread-microseconds";
}
-std::ostream& operator<<(std::ostream& os, TraceTicks trace_ticks) {
- const TimeDelta as_time_delta = trace_ticks - TraceTicks();
- return os << as_time_delta.InMicroseconds() << " bogo-trace-microseconds";
-}
-
// Time::Exploded -------------------------------------------------------------
inline bool is_in_range(int value, int lo, int hi) {
diff --git a/base/time/time.h b/base/time/time.h
index a02fbeb01f..066d910833 100644
--- a/base/time/time.h
+++ b/base/time/time.h
@@ -13,13 +13,13 @@
// TimeDelta represents a duration of time, internally represented in
// microseconds.
//
-// TimeTicks, ThreadTicks, and TraceTicks represent an abstract time that is
-// most of the time incrementing, for use in measuring time durations.
-// Internally, they are represented in microseconds. They can not be converted
-// to a human-readable time, but are guaranteed not to decrease (unlike the Time
-// class). Note that TimeTicks may "stand still" (e.g., if the computer is
-// suspended), and ThreadTicks will "stand still" whenever the thread has been
-// de-scheduled by the operating system.
+// TimeTicks and ThreadTicks represent an abstract time that is most of the time
+// incrementing, for use in measuring time durations. Internally, they are
+// represented in microseconds. They can not be converted to a human-readable
+// time, but are guaranteed not to decrease (unlike the Time class). Note that
+// TimeTicks may "stand still" (e.g., if the computer is suspended), and
+// ThreadTicks will "stand still" whenever the thread has been de-scheduled by
+// the operating system.
//
// All time classes are copyable, assignable, and occupy 64-bits per
// instance. Thus, they can be efficiently passed by-value (as opposed to
@@ -45,22 +45,17 @@
//
// ThreadTicks: Benchmarking how long the current thread has been doing actual
// work.
-//
-// TraceTicks: This is only meant to be used by the event tracing
-// infrastructure, and by outside code modules in special
-// circumstances. Please be sure to consult a
-// base/trace_event/OWNER before committing any new code that
-// uses this.
#ifndef BASE_TIME_TIME_H_
#define BASE_TIME_TIME_H_
+#include <stdint.h>
#include <time.h>
#include <iosfwd>
+#include <limits>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/numerics/safe_math.h"
#include "build/build_config.h"
@@ -79,9 +74,9 @@
// For FILETIME in FromFileTime, until it moves to a new converter class.
// See TODO(iyengar) below.
#include <windows.h>
-#endif
-#include <limits>
+#include "base/gtest_prod_util.h"
+#endif
namespace base {
@@ -92,14 +87,14 @@ class TimeDelta;
// time classes instead.
namespace time_internal {
-// Add or subtract |value| from a TimeDelta. The int64 argument and return value
-// are in terms of a microsecond timebase.
-BASE_EXPORT int64 SaturatedAdd(TimeDelta delta, int64 value);
-BASE_EXPORT int64 SaturatedSub(TimeDelta delta, int64 value);
+// Add or subtract |value| from a TimeDelta. The int64_t argument and return
+// value are in terms of a microsecond timebase.
+BASE_EXPORT int64_t SaturatedAdd(TimeDelta delta, int64_t value);
+BASE_EXPORT int64_t SaturatedSub(TimeDelta delta, int64_t value);
-// Clamp |value| on overflow and underflow conditions. The int64 argument and
+// Clamp |value| on overflow and underflow conditions. The int64_t argument and
// return value are in terms of a microsecond timebase.
-BASE_EXPORT int64 FromCheckedNumeric(const CheckedNumeric<int64> value);
+BASE_EXPORT int64_t FromCheckedNumeric(const CheckedNumeric<int64_t> value);
} // namespace time_internal
@@ -114,11 +109,11 @@ class BASE_EXPORT TimeDelta {
static TimeDelta FromDays(int days);
static TimeDelta FromHours(int hours);
static TimeDelta FromMinutes(int minutes);
- static TimeDelta FromSeconds(int64 secs);
- static TimeDelta FromMilliseconds(int64 ms);
+ static TimeDelta FromSeconds(int64_t secs);
+ static TimeDelta FromMilliseconds(int64_t ms);
static TimeDelta FromSecondsD(double secs);
static TimeDelta FromMillisecondsD(double ms);
- static TimeDelta FromMicroseconds(int64 us);
+ static TimeDelta FromMicroseconds(int64_t us);
#if defined(OS_WIN)
static TimeDelta FromQPCValue(LONGLONG qpc_value);
#endif
@@ -127,9 +122,7 @@ class BASE_EXPORT TimeDelta {
// when deserializing a |TimeDelta| structure, using a value known to be
// compatible. It is not provided as a constructor because the integer type
// may be unclear from the perspective of a caller.
- static TimeDelta FromInternalValue(int64 delta) {
- return TimeDelta(delta);
- }
+ static TimeDelta FromInternalValue(int64_t delta) { return TimeDelta(delta); }
// Returns the maximum time delta, which should be greater than any reasonable
// time delta we might compare it to. Adding or subtracting the maximum time
@@ -140,16 +133,14 @@ class BASE_EXPORT TimeDelta {
// use this and do arithmetic on it, as it is more error prone than using the
// provided operators.
// For serializing, use FromInternalValue to reconstitute.
- int64 ToInternalValue() const {
- return delta_;
- }
+ int64_t ToInternalValue() const { return delta_; }
// Returns the magnitude (absolute value) of this TimeDelta.
TimeDelta magnitude() const {
// Some toolchains provide an incomplete C++11 implementation and lack an
- // int64 overload for std::abs(). The following is a simple branchless
+ // int64_t overload for std::abs(). The following is a simple branchless
// implementation:
- const int64 mask = delta_ >> (sizeof(delta_) * 8 - 1);
+ const int64_t mask = delta_ >> (sizeof(delta_) * 8 - 1);
return TimeDelta((delta_ + mask) ^ mask);
}
@@ -159,9 +150,7 @@ class BASE_EXPORT TimeDelta {
}
// Returns true if the time delta is the maximum time delta.
- bool is_max() const {
- return delta_ == std::numeric_limits<int64>::max();
- }
+ bool is_max() const { return delta_ == std::numeric_limits<int64_t>::max(); }
#if defined(OS_POSIX)
struct timespec ToTimeSpec() const;
@@ -176,11 +165,11 @@ class BASE_EXPORT TimeDelta {
int InHours() const;
int InMinutes() const;
double InSecondsF() const;
- int64 InSeconds() const;
+ int64_t InSeconds() const;
double InMillisecondsF() const;
- int64 InMilliseconds() const;
- int64 InMillisecondsRoundedUp() const;
- int64 InMicroseconds() const;
+ int64_t InMilliseconds() const;
+ int64_t InMillisecondsRoundedUp() const;
+ int64_t InMicroseconds() const;
TimeDelta& operator=(TimeDelta other) {
delta_ = other.delta_;
@@ -208,13 +197,13 @@ class BASE_EXPORT TimeDelta {
// Computations with numeric types.
template<typename T>
TimeDelta operator*(T a) const {
- CheckedNumeric<int64> rv(delta_);
+ CheckedNumeric<int64_t> rv(delta_);
rv *= a;
return TimeDelta(time_internal::FromCheckedNumeric(rv));
}
template<typename T>
TimeDelta operator/(T a) const {
- CheckedNumeric<int64> rv(delta_);
+ CheckedNumeric<int64_t> rv(delta_);
rv /= a;
return TimeDelta(time_internal::FromCheckedNumeric(rv));
}
@@ -227,9 +216,7 @@ class BASE_EXPORT TimeDelta {
return *this = (*this / a);
}
- int64 operator/(TimeDelta a) const {
- return delta_ / a.delta_;
- }
+ int64_t operator/(TimeDelta a) const { return delta_ / a.delta_; }
TimeDelta operator%(TimeDelta a) const {
return TimeDelta(delta_ % a.delta_);
}
@@ -255,17 +242,19 @@ class BASE_EXPORT TimeDelta {
}
private:
- friend int64 time_internal::SaturatedAdd(TimeDelta delta, int64 value);
- friend int64 time_internal::SaturatedSub(TimeDelta delta, int64 value);
+ friend int64_t time_internal::SaturatedAdd(TimeDelta delta, int64_t value);
+ friend int64_t time_internal::SaturatedSub(TimeDelta delta, int64_t value);
// Constructs a delta given the duration in microseconds. This is private
// to avoid confusion by callers with an integer constructor. Use
// FromSeconds, FromMilliseconds, etc. instead.
- explicit TimeDelta(int64 delta_us) : delta_(delta_us) {
- }
+ explicit TimeDelta(int64_t delta_us) : delta_(delta_us) {}
+
+ // Private method to build a delta from a double.
+ static TimeDelta FromDouble(double value);
// Delta in microseconds.
- int64 delta_;
+ int64_t delta_;
};
template<typename T>
@@ -290,20 +279,21 @@ namespace time_internal {
template<class TimeClass>
class TimeBase {
public:
- static const int64 kHoursPerDay = 24;
- static const int64 kMillisecondsPerSecond = 1000;
- static const int64 kMillisecondsPerDay = kMillisecondsPerSecond * 60 * 60 *
- kHoursPerDay;
- static const int64 kMicrosecondsPerMillisecond = 1000;
- static const int64 kMicrosecondsPerSecond = kMicrosecondsPerMillisecond *
- kMillisecondsPerSecond;
- static const int64 kMicrosecondsPerMinute = kMicrosecondsPerSecond * 60;
- static const int64 kMicrosecondsPerHour = kMicrosecondsPerMinute * 60;
- static const int64 kMicrosecondsPerDay = kMicrosecondsPerHour * kHoursPerDay;
- static const int64 kMicrosecondsPerWeek = kMicrosecondsPerDay * 7;
- static const int64 kNanosecondsPerMicrosecond = 1000;
- static const int64 kNanosecondsPerSecond = kNanosecondsPerMicrosecond *
- kMicrosecondsPerSecond;
+ static const int64_t kHoursPerDay = 24;
+ static const int64_t kMillisecondsPerSecond = 1000;
+ static const int64_t kMillisecondsPerDay =
+ kMillisecondsPerSecond * 60 * 60 * kHoursPerDay;
+ static const int64_t kMicrosecondsPerMillisecond = 1000;
+ static const int64_t kMicrosecondsPerSecond =
+ kMicrosecondsPerMillisecond * kMillisecondsPerSecond;
+ static const int64_t kMicrosecondsPerMinute = kMicrosecondsPerSecond * 60;
+ static const int64_t kMicrosecondsPerHour = kMicrosecondsPerMinute * 60;
+ static const int64_t kMicrosecondsPerDay =
+ kMicrosecondsPerHour * kHoursPerDay;
+ static const int64_t kMicrosecondsPerWeek = kMicrosecondsPerDay * 7;
+ static const int64_t kNanosecondsPerMicrosecond = 1000;
+ static const int64_t kNanosecondsPerSecond =
+ kNanosecondsPerMicrosecond * kMicrosecondsPerSecond;
// Returns true if this object has not been initialized.
//
@@ -315,16 +305,12 @@ class TimeBase {
}
// Returns true if this object represents the maximum time.
- bool is_max() const {
- return us_ == std::numeric_limits<int64>::max();
- }
+ bool is_max() const { return us_ == std::numeric_limits<int64_t>::max(); }
// For serializing only. Use FromInternalValue() to reconstitute. Please don't
// use this and do arithmetic on it, as it is more error prone than using the
// provided operators.
- int64 ToInternalValue() const {
- return us_;
- }
+ int64_t ToInternalValue() const { return us_; }
TimeClass& operator=(TimeClass other) {
us_ = other.us_;
@@ -376,16 +362,13 @@ class TimeBase {
// when deserializing a |TimeClass| structure, using a value known to be
// compatible. It is not provided as a constructor because the integer type
// may be unclear from the perspective of a caller.
- static TimeClass FromInternalValue(int64 us) {
- return TimeClass(us);
- }
+ static TimeClass FromInternalValue(int64_t us) { return TimeClass(us); }
protected:
- explicit TimeBase(int64 us) : us_(us) {
- }
+ explicit TimeBase(int64_t us) : us_(us) {}
// Time value in a microsecond timebase.
- int64 us_;
+ int64_t us_;
};
} // namespace time_internal
@@ -403,7 +386,7 @@ class BASE_EXPORT Time : public time_internal::TimeBase<Time> {
public:
// The representation of Jan 1, 1970 UTC in microseconds since the
// platform-dependent epoch.
- static const int64 kTimeTToMicrosecondsOffset;
+ static const int64_t kTimeTToMicrosecondsOffset;
#if !defined(OS_WIN)
// On Mac & Linux, this value is the delta from the Windows epoch of 1601 to
@@ -411,12 +394,12 @@ class BASE_EXPORT Time : public time_internal::TimeBase<Time> {
// 1970-based epochs to the new 1601-based ones. It should be removed from
// this global header and put in the platform-specific ones when we remove the
// migration code.
- static const int64 kWindowsEpochDeltaMicroseconds;
+ static const int64_t kWindowsEpochDeltaMicroseconds;
#else
// To avoid overflow in QPC to Microseconds calculations, since we multiply
// by kMicrosecondsPerSecond, then the QPC value should not exceed
// (2^63 - 1) / 1E6. If it exceeds that threshold, we divide then multiply.
- static const int64 kQPCOverflowThreshold = 0x8637BD05AF7;
+ enum : int64_t{kQPCOverflowThreshold = 0x8637BD05AF7};
#endif
// Represents an exploded time that can be formatted nicely. This is kind of
@@ -491,7 +474,7 @@ class BASE_EXPORT Time : public time_internal::TimeBase<Time> {
// Converts to Java convention for times, a number of
// milliseconds since the epoch.
- int64 ToJavaTime() const;
+ int64_t ToJavaTime() const;
#if defined(OS_POSIX)
static Time FromTimeVal(struct timeval t);
@@ -570,8 +553,7 @@ class BASE_EXPORT Time : public time_internal::TimeBase<Time> {
private:
friend class time_internal::TimeBase<Time>;
- explicit Time(int64 us) : TimeBase(us) {
- }
+ explicit Time(int64_t us) : TimeBase(us) {}
// Explodes the given time to either local time |is_local = true| or UTC
// |is_local = false|.
@@ -597,7 +579,6 @@ class BASE_EXPORT Time : public time_internal::TimeBase<Time> {
// static
inline TimeDelta TimeDelta::FromDays(int days) {
- // Preserve max to prevent overflow.
if (days == std::numeric_limits<int>::max())
return Max();
return TimeDelta(days * Time::kMicrosecondsPerDay);
@@ -605,7 +586,6 @@ inline TimeDelta TimeDelta::FromDays(int days) {
// static
inline TimeDelta TimeDelta::FromHours(int hours) {
- // Preserve max to prevent overflow.
if (hours == std::numeric_limits<int>::max())
return Max();
return TimeDelta(hours * Time::kMicrosecondsPerHour);
@@ -613,52 +593,47 @@ inline TimeDelta TimeDelta::FromHours(int hours) {
// static
inline TimeDelta TimeDelta::FromMinutes(int minutes) {
- // Preserve max to prevent overflow.
if (minutes == std::numeric_limits<int>::max())
return Max();
return TimeDelta(minutes * Time::kMicrosecondsPerMinute);
}
// static
-inline TimeDelta TimeDelta::FromSeconds(int64 secs) {
- // Preserve max to prevent overflow.
- if (secs == std::numeric_limits<int64>::max())
- return Max();
- return TimeDelta(secs * Time::kMicrosecondsPerSecond);
+inline TimeDelta TimeDelta::FromSeconds(int64_t secs) {
+ return TimeDelta(secs) * Time::kMicrosecondsPerSecond;
}
// static
-inline TimeDelta TimeDelta::FromMilliseconds(int64 ms) {
- // Preserve max to prevent overflow.
- if (ms == std::numeric_limits<int64>::max())
- return Max();
- return TimeDelta(ms * Time::kMicrosecondsPerMillisecond);
+inline TimeDelta TimeDelta::FromMilliseconds(int64_t ms) {
+ return TimeDelta(ms) * Time::kMicrosecondsPerMillisecond;
}
// static
inline TimeDelta TimeDelta::FromSecondsD(double secs) {
- // Preserve max to prevent overflow.
- if (secs == std::numeric_limits<double>::infinity())
- return Max();
- return TimeDelta(static_cast<int64>(secs * Time::kMicrosecondsPerSecond));
+ return FromDouble(secs * Time::kMicrosecondsPerSecond);
}
// static
inline TimeDelta TimeDelta::FromMillisecondsD(double ms) {
- // Preserve max to prevent overflow.
- if (ms == std::numeric_limits<double>::infinity())
- return Max();
- return TimeDelta(static_cast<int64>(ms * Time::kMicrosecondsPerMillisecond));
+ return FromDouble(ms * Time::kMicrosecondsPerMillisecond);
}
// static
-inline TimeDelta TimeDelta::FromMicroseconds(int64 us) {
- // Preserve max to prevent overflow.
- if (us == std::numeric_limits<int64>::max())
- return Max();
+inline TimeDelta TimeDelta::FromMicroseconds(int64_t us) {
return TimeDelta(us);
}
+// static
+inline TimeDelta TimeDelta::FromDouble(double value) {
+ double max_magnitude = std::numeric_limits<int64_t>::max();
+ TimeDelta delta = TimeDelta(static_cast<int64_t>(value));
+ if (value > max_magnitude)
+ delta = Max();
+ else if (value < -max_magnitude)
+ delta = -Max();
+ return delta;
+}
+
// For logging use only.
BASE_EXPORT std::ostream& operator<<(std::ostream& os, Time time);
@@ -689,12 +664,14 @@ class BASE_EXPORT TimeTicks : public time_internal::TimeBase<TimeTicks> {
static TimeTicks FromQPCValue(LONGLONG qpc_value);
#endif
- // Get the TimeTick value at the time of the UnixEpoch. This is useful when
- // you need to relate the value of TimeTicks to a real time and date.
- // Note: Upon first invocation, this function takes a snapshot of the realtime
- // clock to establish a reference point. This function will return the same
- // value for the duration of the application, but will be different in future
- // application runs.
+ // Get an estimate of the TimeTick value at the time of the UnixEpoch. Because
+ // Time and TimeTicks respond differently to user-set time and NTP
+ // adjustments, this number is only an estimate. Nevertheless, this can be
+ // useful when you need to relate the value of TimeTicks to a real time and
+ // date. Note: Upon first invocation, this function takes a snapshot of the
+ // realtime clock to establish a reference point. This function will return
+ // the same value for the duration of the application, but will be different
+ // in future application runs.
static TimeTicks UnixEpoch();
// Returns |this| snapped to the next tick, given a |tick_phase| and
@@ -714,8 +691,7 @@ class BASE_EXPORT TimeTicks : public time_internal::TimeBase<TimeTicks> {
// Please use Now() to create a new object. This is for internal use
// and testing.
- explicit TimeTicks(int64 us) : TimeBase(us) {
- }
+ explicit TimeTicks(int64_t us) : TimeBase(us) {}
};
// For logging use only.
@@ -735,16 +711,28 @@ class BASE_EXPORT ThreadTicks : public time_internal::TimeBase<ThreadTicks> {
#if (defined(_POSIX_THREAD_CPUTIME) && (_POSIX_THREAD_CPUTIME >= 0)) || \
(defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_ANDROID)
return true;
+#elif defined(OS_WIN)
+ return IsSupportedWin();
#else
return false;
#endif
}
+ // Waits until the initialization is completed. Needs to be guarded with a
+ // call to IsSupported().
+ static void WaitUntilInitialized() {
+#if defined(OS_WIN)
+ WaitUntilInitializedWin();
+#endif
+ }
+
// Returns thread-specific CPU-time on systems that support this feature.
// Needs to be guarded with a call to IsSupported(). Use this timer
// to (approximately) measure how much time the calling thread spent doing
// actual work vs. being de-scheduled. May return bogus results if the thread
- // migrates to another CPU between two calls.
+ // migrates to another CPU between two calls. Returns an empty ThreadTicks
+ // object until the initialization is completed. If a clock reading is
+ // absolutely needed, call WaitUntilInitialized() before this method.
static ThreadTicks Now();
private:
@@ -752,58 +740,24 @@ class BASE_EXPORT ThreadTicks : public time_internal::TimeBase<ThreadTicks> {
// Please use Now() to create a new object. This is for internal use
// and testing.
- explicit ThreadTicks(int64 us) : TimeBase(us) {
- }
-};
+ explicit ThreadTicks(int64_t us) : TimeBase(us) {}
-// For logging use only.
-BASE_EXPORT std::ostream& operator<<(std::ostream& os, ThreadTicks time_ticks);
+#if defined(OS_WIN)
+ FRIEND_TEST_ALL_PREFIXES(TimeTicks, TSCTicksPerSecond);
-// TraceTicks ----------------------------------------------------------------
+ // Returns the frequency of the TSC in ticks per second, or 0 if it hasn't
+ // been measured yet. Needs to be guarded with a call to IsSupported().
+ // This method is declared here rather than in the anonymous namespace to
+ // allow testing.
+ static double TSCTicksPerSecond();
-// Represents high-resolution system trace clock time.
-class BASE_EXPORT TraceTicks : public time_internal::TimeBase<TraceTicks> {
- public:
- // We define this even without OS_CHROMEOS for seccomp sandbox testing.
-#if defined(OS_LINUX)
- // Force definition of the system trace clock; it is a chromeos-only api
- // at the moment and surfacing it in the right place requires mucking
- // with glibc et al.
- static const clockid_t kClockSystemTrace = 11;
+ static bool IsSupportedWin();
+ static void WaitUntilInitializedWin();
#endif
-
- TraceTicks() : TimeBase(0) {
- }
-
- // Returns the current system trace time or, if not available on this
- // platform, a high-resolution time value; or a low-resolution time value if
- // neither are avalable. On systems where a global trace clock is defined,
- // timestamping TraceEvents's with this value guarantees synchronization
- // between events collected inside chrome and events collected outside
- // (e.g. kernel, X server).
- //
- // On some platforms, the clock source used for tracing can vary depending on
- // hardware and/or kernel support. Do not make any assumptions without
- // consulting the documentation for this functionality in the time_win.cc,
- // time_posix.cc, etc. files.
- //
- // NOTE: This is only meant to be used by the event tracing infrastructure,
- // and by outside code modules in special circumstances. Please be sure to
- // consult a base/trace_event/OWNER before committing any new code that uses
- // this.
- static TraceTicks Now();
-
- private:
- friend class time_internal::TimeBase<TraceTicks>;
-
- // Please use Now() to create a new object. This is for internal use
- // and testing.
- explicit TraceTicks(int64 us) : TimeBase(us) {
- }
};
// For logging use only.
-BASE_EXPORT std::ostream& operator<<(std::ostream& os, TraceTicks time_ticks);
+BASE_EXPORT std::ostream& operator<<(std::ostream& os, ThreadTicks time_ticks);
} // namespace base
diff --git a/base/time/time_mac.cc b/base/time/time_mac.cc
index 1dbbc3370d..f2bc5ed8c9 100644
--- a/base/time/time_mac.cc
+++ b/base/time/time_mac.cc
@@ -8,18 +8,20 @@
#include <CoreFoundation/CFTimeZone.h>
#include <mach/mach.h>
#include <mach/mach_time.h>
+#include <stddef.h>
#include <stdint.h>
#include <sys/sysctl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <time.h>
-#include "base/basictypes.h"
#include "base/logging.h"
#include "base/mac/mach_logging.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/mac/scoped_mach_port.h"
+#include "base/macros.h"
#include "base/numerics/safe_conversions.h"
+#include "build/build_config.h"
namespace {
@@ -83,7 +85,7 @@ int64_t ComputeThreadTicks() {
}
kern_return_t kr = thread_info(
- thread,
+ thread.get(),
THREAD_BASIC_INFO,
reinterpret_cast<thread_info_t>(&thread_info_data),
&thread_info_count);
@@ -117,16 +119,16 @@ namespace base {
// => Thu Jan 01 00:00:00 UTC 1970
// irb(main):011:0> Time.at(-11644473600).getutc()
// => Mon Jan 01 00:00:00 UTC 1601
-static const int64 kWindowsEpochDeltaSeconds = INT64_C(11644473600);
+static const int64_t kWindowsEpochDeltaSeconds = INT64_C(11644473600);
// static
-const int64 Time::kWindowsEpochDeltaMicroseconds =
+const int64_t Time::kWindowsEpochDeltaMicroseconds =
kWindowsEpochDeltaSeconds * Time::kMicrosecondsPerSecond;
// Some functions in time.cc use time_t directly, so we provide an offset
// to convert from time_t (Unix epoch) and internal (Windows epoch).
// static
-const int64 Time::kTimeTToMicrosecondsOffset = kWindowsEpochDeltaMicroseconds;
+const int64_t Time::kTimeTToMicrosecondsOffset = kWindowsEpochDeltaMicroseconds;
// static
Time Time::Now() {
@@ -135,20 +137,20 @@ Time Time::Now() {
// static
Time Time::FromCFAbsoluteTime(CFAbsoluteTime t) {
- COMPILE_ASSERT(std::numeric_limits<CFAbsoluteTime>::has_infinity,
- numeric_limits_infinity_is_undefined_when_not_has_infinity);
+ static_assert(std::numeric_limits<CFAbsoluteTime>::has_infinity,
+ "CFAbsoluteTime must have an infinity value");
if (t == 0)
return Time(); // Consider 0 as a null Time.
if (t == std::numeric_limits<CFAbsoluteTime>::infinity())
return Max();
- return Time(static_cast<int64>(
- (t + kCFAbsoluteTimeIntervalSince1970) * kMicrosecondsPerSecond) +
- kWindowsEpochDeltaMicroseconds);
+ return Time(static_cast<int64_t>((t + kCFAbsoluteTimeIntervalSince1970) *
+ kMicrosecondsPerSecond) +
+ kWindowsEpochDeltaMicroseconds);
}
CFAbsoluteTime Time::ToCFAbsoluteTime() const {
- COMPILE_ASSERT(std::numeric_limits<CFAbsoluteTime>::has_infinity,
- numeric_limits_infinity_is_undefined_when_not_has_infinity);
+ static_assert(std::numeric_limits<CFAbsoluteTime>::has_infinity,
+ "CFAbsoluteTime must have an infinity value");
if (is_null())
return 0; // Consider 0 as a null Time.
if (is_max())
@@ -178,14 +180,14 @@ Time Time::FromExploded(bool is_local, const Exploded& exploded) {
is_local ? CFTimeZoneCopySystem() : NULL);
CFAbsoluteTime seconds = CFGregorianDateGetAbsoluteTime(date, time_zone) +
kCFAbsoluteTimeIntervalSince1970;
- return Time(static_cast<int64>(seconds * kMicrosecondsPerSecond) +
- kWindowsEpochDeltaMicroseconds);
+ return Time(static_cast<int64_t>(seconds * kMicrosecondsPerSecond) +
+ kWindowsEpochDeltaMicroseconds);
}
void Time::Explode(bool is_local, Exploded* exploded) const {
// Avoid rounding issues, by only putting the integral number of seconds
// (rounded towards -infinity) into a |CFAbsoluteTime| (which is a |double|).
- int64 microsecond = us_ % kMicrosecondsPerSecond;
+ int64_t microsecond = us_ % kMicrosecondsPerSecond;
if (microsecond < 0)
microsecond += kMicrosecondsPerSecond;
CFAbsoluteTime seconds = ((us_ - microsecond) / kMicrosecondsPerSecond) -
@@ -231,9 +233,4 @@ ThreadTicks ThreadTicks::Now() {
return ThreadTicks(ComputeThreadTicks());
}
-// static
-TraceTicks TraceTicks::Now() {
- return TraceTicks(ComputeCurrentTicks());
-}
-
} // namespace base
diff --git a/base/time/time_posix.cc b/base/time/time_posix.cc
index fc82c620b3..4aadee618a 100644
--- a/base/time/time_posix.cc
+++ b/base/time/time_posix.cc
@@ -15,7 +15,6 @@
#include <limits>
#include <ostream>
-#include "base/basictypes.h"
#include "base/logging.h"
#include "build/build_config.h"
@@ -80,8 +79,8 @@ void SysTimeToTimeStruct(SysTime t, struct tm* timestruct, bool is_local) {
}
#endif // OS_ANDROID
-int64 ConvertTimespecToMicros(const struct timespec& ts) {
- base::CheckedNumeric<int64> result(ts.tv_sec);
+int64_t ConvertTimespecToMicros(const struct timespec& ts) {
+ base::CheckedNumeric<int64_t> result(ts.tv_sec);
result *= base::Time::kMicrosecondsPerSecond;
result += (ts.tv_nsec / base::Time::kNanosecondsPerMicrosecond);
return result.ValueOrDie();
@@ -94,7 +93,7 @@ int64 ConvertTimespecToMicros(const struct timespec& ts) {
#if (defined(OS_POSIX) && \
defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0) || \
defined(OS_BSD) || defined(OS_ANDROID)
-int64 ClockNow(clockid_t clk_id) {
+int64_t ClockNow(clockid_t clk_id) {
struct timespec ts;
if (clock_gettime(clk_id, &ts) != 0) {
NOTREACHED() << "clock_gettime(" << clk_id << ") failed.";
@@ -112,7 +111,7 @@ int64 ClockNow(clockid_t clk_id) {
namespace base {
struct timespec TimeDelta::ToTimeSpec() const {
- int64 microseconds = InMicroseconds();
+ int64_t microseconds = InMicroseconds();
time_t seconds = 0;
if (microseconds >= Time::kMicrosecondsPerSecond) {
seconds = InSeconds();
@@ -137,16 +136,16 @@ struct timespec TimeDelta::ToTimeSpec() const {
// => Thu Jan 01 00:00:00 UTC 1970
// irb(main):011:0> Time.at(-11644473600).getutc()
// => Mon Jan 01 00:00:00 UTC 1601
-static const int64 kWindowsEpochDeltaSeconds = INT64_C(11644473600);
+static const int64_t kWindowsEpochDeltaSeconds = INT64_C(11644473600);
// static
-const int64 Time::kWindowsEpochDeltaMicroseconds =
+const int64_t Time::kWindowsEpochDeltaMicroseconds =
kWindowsEpochDeltaSeconds * Time::kMicrosecondsPerSecond;
// Some functions in time.cc use time_t directly, so we provide an offset
// to convert from time_t (Unix epoch) and internal (Windows epoch).
// static
-const int64 Time::kTimeTToMicrosecondsOffset = kWindowsEpochDeltaMicroseconds;
+const int64_t Time::kTimeTToMicrosecondsOffset = kWindowsEpochDeltaMicroseconds;
// static
Time Time::Now() {
@@ -176,9 +175,9 @@ void Time::Explode(bool is_local, Exploded* exploded) const {
// Time stores times with microsecond resolution, but Exploded only carries
// millisecond resolution, so begin by being lossy. Adjust from Windows
// epoch (1601) to Unix epoch (1970);
- int64 microseconds = us_ - kWindowsEpochDeltaMicroseconds;
+ int64_t microseconds = us_ - kWindowsEpochDeltaMicroseconds;
// The following values are all rounded towards -infinity.
- int64 milliseconds; // Milliseconds since epoch.
+ int64_t milliseconds; // Milliseconds since epoch.
SysTime seconds; // Seconds since epoch.
int millisecond; // Exploded millisecond value (0-999).
if (microseconds >= 0) {
@@ -228,8 +227,7 @@ Time Time::FromExploded(bool is_local, const Exploded& exploded) {
timestruct.tm_zone = NULL; // not a POSIX field, so mktime/timegm ignore
#endif
-
- int64 milliseconds;
+ int64_t milliseconds;
SysTime seconds;
// Certain exploded dates do not really exist due to daylight saving times,
@@ -247,11 +245,11 @@ Time Time::FromExploded(bool is_local, const Exploded& exploded) {
// to UTC 00:00:00 that isn't -1.
timestruct = timestruct0;
timestruct.tm_isdst = 0;
- int64 seconds_isdst0 = SysTimeFromTimeStruct(&timestruct, is_local);
+ int64_t seconds_isdst0 = SysTimeFromTimeStruct(&timestruct, is_local);
timestruct = timestruct0;
timestruct.tm_isdst = 1;
- int64 seconds_isdst1 = SysTimeFromTimeStruct(&timestruct, is_local);
+ int64_t seconds_isdst1 = SysTimeFromTimeStruct(&timestruct, is_local);
// seconds_isdst0 or seconds_isdst1 can be -1 for some timezones.
// E.g. "CLST" (Chile Summer Time) returns -1 for 'tm_isdt == 1'.
@@ -284,14 +282,14 @@ Time Time::FromExploded(bool is_local, const Exploded& exploded) {
// 999ms to avoid the time being less than any other possible value that
// this function can return.
- // On Android, SysTime is int64, special care must be taken to avoid
+ // On Android, SysTime is int64_t, special care must be taken to avoid
// overflows.
- const int64 min_seconds = (sizeof(SysTime) < sizeof(int64))
- ? std::numeric_limits<SysTime>::min()
- : std::numeric_limits<int32_t>::min();
- const int64 max_seconds = (sizeof(SysTime) < sizeof(int64))
- ? std::numeric_limits<SysTime>::max()
- : std::numeric_limits<int32_t>::max();
+ const int64_t min_seconds = (sizeof(SysTime) < sizeof(int64_t))
+ ? std::numeric_limits<SysTime>::min()
+ : std::numeric_limits<int32_t>::min();
+ const int64_t max_seconds = (sizeof(SysTime) < sizeof(int64_t))
+ ? std::numeric_limits<SysTime>::max()
+ : std::numeric_limits<int32_t>::max();
if (exploded.year < 1969) {
milliseconds = min_seconds * kMillisecondsPerSecond;
} else {
@@ -329,27 +327,6 @@ ThreadTicks ThreadTicks::Now() {
#endif
}
-// Use the Chrome OS specific system-wide clock.
-#if defined(OS_CHROMEOS)
-// static
-TraceTicks TraceTicks::Now() {
- struct timespec ts;
- if (clock_gettime(kClockSystemTrace, &ts) != 0) {
- // NB: fall-back for a chrome os build running on linux
- return TraceTicks(ClockNow(CLOCK_MONOTONIC));
- }
- return TraceTicks(ConvertTimespecToMicros(ts));
-}
-
-#else // !defined(OS_CHROMEOS)
-
-// static
-TraceTicks TraceTicks::Now() {
- return TraceTicks(ClockNow(CLOCK_MONOTONIC));
-}
-
-#endif // defined(OS_CHROMEOS)
-
#endif // !OS_MACOSX
// static
@@ -361,10 +338,8 @@ Time Time::FromTimeVal(struct timeval t) {
if (t.tv_usec == static_cast<suseconds_t>(Time::kMicrosecondsPerSecond) - 1 &&
t.tv_sec == std::numeric_limits<time_t>::max())
return Max();
- return Time(
- (static_cast<int64>(t.tv_sec) * Time::kMicrosecondsPerSecond) +
- t.tv_usec +
- kTimeTToMicrosecondsOffset);
+ return Time((static_cast<int64_t>(t.tv_sec) * Time::kMicrosecondsPerSecond) +
+ t.tv_usec + kTimeTToMicrosecondsOffset);
}
struct timeval Time::ToTimeVal() const {
@@ -379,7 +354,7 @@ struct timeval Time::ToTimeVal() const {
result.tv_usec = static_cast<suseconds_t>(Time::kMicrosecondsPerSecond) - 1;
return result;
}
- int64 us = us_ - kTimeTToMicrosecondsOffset;
+ int64_t us = us_ - kTimeTToMicrosecondsOffset;
result.tv_sec = us / Time::kMicrosecondsPerSecond;
result.tv_usec = us % Time::kMicrosecondsPerSecond;
return result;
diff --git a/base/time/time_unittest.cc b/base/time/time_unittest.cc
index b7e05b786b..8a6a7f5177 100644
--- a/base/time/time_unittest.cc
+++ b/base/time/time_unittest.cc
@@ -11,6 +11,7 @@
#include "base/compiler_specific.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/strings/stringprintf.h"
#include "base/threading/platform_thread.h"
#include "build/build_config.h"
@@ -484,52 +485,6 @@ TEST_F(TimeTest, ExplodeBeforeUnixEpoch) {
EXPECT_EQ(1, exploded.millisecond);
}
-TEST_F(TimeTest, TimeDeltaMax) {
- TimeDelta max = TimeDelta::Max();
- EXPECT_TRUE(max.is_max());
- EXPECT_EQ(max, TimeDelta::Max());
- EXPECT_GT(max, TimeDelta::FromDays(100 * 365));
- EXPECT_GT(max, TimeDelta());
-}
-
-TEST_F(TimeTest, TimeDeltaMaxConversions) {
- TimeDelta t = TimeDelta::Max();
- EXPECT_EQ(std::numeric_limits<int64>::max(), t.ToInternalValue());
-
- EXPECT_EQ(std::numeric_limits<int>::max(), t.InDays());
- EXPECT_EQ(std::numeric_limits<int>::max(), t.InHours());
- EXPECT_EQ(std::numeric_limits<int>::max(), t.InMinutes());
- EXPECT_EQ(std::numeric_limits<double>::infinity(), t.InSecondsF());
- EXPECT_EQ(std::numeric_limits<int64>::max(), t.InSeconds());
- EXPECT_EQ(std::numeric_limits<double>::infinity(), t.InMillisecondsF());
- EXPECT_EQ(std::numeric_limits<int64>::max(), t.InMilliseconds());
- EXPECT_EQ(std::numeric_limits<int64>::max(), t.InMillisecondsRoundedUp());
-
- t = TimeDelta::FromDays(std::numeric_limits<int>::max());
- EXPECT_TRUE(t.is_max());
-
- t = TimeDelta::FromHours(std::numeric_limits<int>::max());
- EXPECT_TRUE(t.is_max());
-
- t = TimeDelta::FromMinutes(std::numeric_limits<int>::max());
- EXPECT_TRUE(t.is_max());
-
- t = TimeDelta::FromSeconds(std::numeric_limits<int64>::max());
- EXPECT_TRUE(t.is_max());
-
- t = TimeDelta::FromMilliseconds(std::numeric_limits<int64>::max());
- EXPECT_TRUE(t.is_max());
-
- t = TimeDelta::FromSecondsD(std::numeric_limits<double>::infinity());
- EXPECT_TRUE(t.is_max());
-
- t = TimeDelta::FromMillisecondsD(std::numeric_limits<double>::infinity());
- EXPECT_TRUE(t.is_max());
-
- t = TimeDelta::FromMicroseconds(std::numeric_limits<int64>::max());
- EXPECT_TRUE(t.is_max());
-}
-
TEST_F(TimeTest, Max) {
Time max = Time::Max();
EXPECT_TRUE(max.is_max());
@@ -540,7 +495,7 @@ TEST_F(TimeTest, Max) {
TEST_F(TimeTest, MaxConversions) {
Time t = Time::Max();
- EXPECT_EQ(std::numeric_limits<int64>::max(), t.ToInternalValue());
+ EXPECT_EQ(std::numeric_limits<int64_t>::max(), t.ToInternalValue());
t = Time::FromDoubleT(std::numeric_limits<double>::infinity());
EXPECT_TRUE(t.is_max());
@@ -587,7 +542,7 @@ TEST_F(TimeTest, MaxConversions) {
#if defined(OS_MACOSX)
TEST_F(TimeTest, TimeTOverflow) {
- Time t = Time::FromInternalValue(std::numeric_limits<int64>::max() - 1);
+ Time t = Time::FromInternalValue(std::numeric_limits<int64_t>::max() - 1);
EXPECT_FALSE(t.is_max());
EXPECT_EQ(std::numeric_limits<time_t>::max(), t.ToTimeT());
}
@@ -692,6 +647,7 @@ TEST(TimeTicks, HighRes) {
#endif
TEST(ThreadTicks, MAYBE_ThreadNow) {
if (ThreadTicks::IsSupported()) {
+ ThreadTicks::WaitUntilInitialized();
TimeTicks begin = TimeTicks::Now();
ThreadTicks begin_thread = ThreadTicks::Now();
// Make sure that ThreadNow value is non-zero.
@@ -710,12 +666,6 @@ TEST(ThreadTicks, MAYBE_ThreadNow) {
}
}
-TEST(TraceTicks, NowFromSystemTraceTime) {
- // Re-use HighRes test for now since clock properties are identical.
- using NowFunction = TimeTicks (*)(void);
- HighResClockTest(reinterpret_cast<NowFunction>(&TraceTicks::Now));
-}
-
TEST(TimeTicks, SnappedToNextTickBasic) {
base::TimeTicks phase = base::TimeTicks::FromInternalValue(4000);
base::TimeDelta interval = base::TimeDelta::FromMicroseconds(1000);
@@ -795,6 +745,7 @@ TEST(TimeDelta, FromAndIn) {
EXPECT_EQ(13, TimeDelta::FromMillisecondsD(13.3).InMilliseconds());
EXPECT_EQ(13.3, TimeDelta::FromMillisecondsD(13.3).InMillisecondsF());
EXPECT_EQ(13, TimeDelta::FromMicroseconds(13).InMicroseconds());
+ EXPECT_EQ(3.456, TimeDelta::FromMillisecondsD(3.45678).InMillisecondsF());
}
#if defined(OS_POSIX)
@@ -849,25 +800,102 @@ std::string AnyToString(Any any) {
}
TEST(TimeDelta, Magnitude) {
- const int64 zero = 0;
+ const int64_t zero = 0;
EXPECT_EQ(TimeDelta::FromMicroseconds(zero),
TimeDelta::FromMicroseconds(zero).magnitude());
- const int64 one = 1;
- const int64 negative_one = -1;
+ const int64_t one = 1;
+ const int64_t negative_one = -1;
EXPECT_EQ(TimeDelta::FromMicroseconds(one),
TimeDelta::FromMicroseconds(one).magnitude());
EXPECT_EQ(TimeDelta::FromMicroseconds(one),
TimeDelta::FromMicroseconds(negative_one).magnitude());
- const int64 max_int64_minus_one = std::numeric_limits<int64>::max() - 1;
- const int64 min_int64_plus_two = std::numeric_limits<int64>::min() + 2;
+ const int64_t max_int64_minus_one = std::numeric_limits<int64_t>::max() - 1;
+ const int64_t min_int64_plus_two = std::numeric_limits<int64_t>::min() + 2;
EXPECT_EQ(TimeDelta::FromMicroseconds(max_int64_minus_one),
TimeDelta::FromMicroseconds(max_int64_minus_one).magnitude());
EXPECT_EQ(TimeDelta::FromMicroseconds(max_int64_minus_one),
TimeDelta::FromMicroseconds(min_int64_plus_two).magnitude());
}
+TEST(TimeDelta, Max) {
+ TimeDelta max = TimeDelta::Max();
+ EXPECT_TRUE(max.is_max());
+ EXPECT_EQ(max, TimeDelta::Max());
+ EXPECT_GT(max, TimeDelta::FromDays(100 * 365));
+ EXPECT_GT(max, TimeDelta());
+}
+
+bool IsMin(TimeDelta delta) {
+ return (-delta).is_max();
+}
+
+TEST(TimeDelta, MaxConversions) {
+ TimeDelta t = TimeDelta::Max();
+ EXPECT_EQ(std::numeric_limits<int64_t>::max(), t.ToInternalValue());
+
+ EXPECT_EQ(std::numeric_limits<int>::max(), t.InDays());
+ EXPECT_EQ(std::numeric_limits<int>::max(), t.InHours());
+ EXPECT_EQ(std::numeric_limits<int>::max(), t.InMinutes());
+ EXPECT_EQ(std::numeric_limits<double>::infinity(), t.InSecondsF());
+ EXPECT_EQ(std::numeric_limits<int64_t>::max(), t.InSeconds());
+ EXPECT_EQ(std::numeric_limits<double>::infinity(), t.InMillisecondsF());
+ EXPECT_EQ(std::numeric_limits<int64_t>::max(), t.InMilliseconds());
+ EXPECT_EQ(std::numeric_limits<int64_t>::max(), t.InMillisecondsRoundedUp());
+
+ t = TimeDelta::FromDays(std::numeric_limits<int>::max());
+ EXPECT_TRUE(t.is_max());
+
+ t = TimeDelta::FromHours(std::numeric_limits<int>::max());
+ EXPECT_TRUE(t.is_max());
+
+ t = TimeDelta::FromMinutes(std::numeric_limits<int>::max());
+ EXPECT_TRUE(t.is_max());
+
+ int64_t max_int = std::numeric_limits<int64_t>::max();
+
+ t = TimeDelta::FromSeconds(max_int / Time::kMicrosecondsPerSecond + 1);
+ EXPECT_TRUE(t.is_max());
+
+ t = TimeDelta::FromMilliseconds(max_int / Time::kMillisecondsPerSecond + 1);
+ EXPECT_TRUE(t.is_max());
+
+ t = TimeDelta::FromMicroseconds(max_int);
+ EXPECT_TRUE(t.is_max());
+
+ t = TimeDelta::FromSeconds(-max_int / Time::kMicrosecondsPerSecond - 1);
+ EXPECT_TRUE(IsMin(t));
+
+ t = TimeDelta::FromMilliseconds(-max_int / Time::kMillisecondsPerSecond - 1);
+ EXPECT_TRUE(IsMin(t));
+
+ t = TimeDelta::FromMicroseconds(-max_int);
+ EXPECT_TRUE(IsMin(t));
+
+ t = -TimeDelta::FromMicroseconds(std::numeric_limits<int64_t>::min());
+ EXPECT_FALSE(IsMin(t));
+
+ t = TimeDelta::FromSecondsD(std::numeric_limits<double>::infinity());
+ EXPECT_TRUE(t.is_max());
+
+ double max_d = max_int;
+
+ t = TimeDelta::FromSecondsD(max_d / Time::kMicrosecondsPerSecond + 1);
+ EXPECT_TRUE(t.is_max());
+
+ t = TimeDelta::FromMillisecondsD(std::numeric_limits<double>::infinity());
+ EXPECT_TRUE(t.is_max());
+
+ t = TimeDelta::FromMillisecondsD(max_d / Time::kMillisecondsPerSecond * 2);
+ EXPECT_TRUE(t.is_max());
+
+ t = TimeDelta::FromSecondsD(-max_d / Time::kMicrosecondsPerSecond - 1);
+ EXPECT_TRUE(IsMin(t));
+
+ t = TimeDelta::FromMillisecondsD(-max_d / Time::kMillisecondsPerSecond * 2);
+ EXPECT_TRUE(IsMin(t));
+}
TEST(TimeDelta, NumericOperators) {
double d = 0.5;
@@ -894,7 +922,6 @@ TEST(TimeDelta, NumericOperators) {
EXPECT_EQ(TimeDelta::FromMilliseconds(500),
f * TimeDelta::FromMilliseconds(1000));
-
int i = 2;
EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
TimeDelta::FromMilliseconds(1000) * i);
@@ -919,7 +946,6 @@ TEST(TimeDelta, NumericOperators) {
EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
i64 * TimeDelta::FromMilliseconds(1000));
-
EXPECT_EQ(TimeDelta::FromMilliseconds(500),
TimeDelta::FromMilliseconds(1000) * 0.5);
EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
@@ -943,10 +969,6 @@ TEST(TimeDelta, NumericOperators) {
2 * TimeDelta::FromMilliseconds(1000));
}
-bool IsMin(TimeDelta delta) {
- return (-delta).is_max();
-}
-
TEST(TimeDelta, Overflows) {
// Some sanity checks.
EXPECT_TRUE(TimeDelta::Max().is_max());
diff --git a/base/timer/hi_res_timer_manager.h b/base/timer/hi_res_timer_manager.h
index ed0e1e04ad..21cdfafb6c 100644
--- a/base/timer/hi_res_timer_manager.h
+++ b/base/timer/hi_res_timer_manager.h
@@ -6,7 +6,7 @@
#define BASE_TIMER_HI_RES_TIMER_MANAGER_H_
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/power_monitor/power_observer.h"
namespace base {
diff --git a/base/timer/hi_res_timer_manager_unittest.cc b/base/timer/hi_res_timer_manager_unittest.cc
index 5475a91446..94160486f9 100644
--- a/base/timer/hi_res_timer_manager_unittest.cc
+++ b/base/timer/hi_res_timer_manager_unittest.cc
@@ -4,11 +4,14 @@
#include "base/timer/hi_res_timer_manager.h"
+#include <utility>
+
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/power_monitor/power_monitor.h"
#include "base/power_monitor/power_monitor_device_source.h"
#include "base/time/time.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
@@ -22,7 +25,7 @@ TEST(HiResTimerManagerTest, ToggleOnOff) {
scoped_ptr<base::PowerMonitorSource> power_monitor_source(
new base::PowerMonitorDeviceSource());
scoped_ptr<base::PowerMonitor> power_monitor(
- new base::PowerMonitor(power_monitor_source.Pass()));
+ new base::PowerMonitor(std::move(power_monitor_source)));
HighResolutionTimerManager manager;
// Simulate a on-AC power event to get to a known initial state.
diff --git a/base/timer/timer.h b/base/timer/timer.h
index 1ef58a3ea0..661829b513 100644
--- a/base/timer/timer.h
+++ b/base/timer/timer.h
@@ -29,7 +29,7 @@
// // This method is called every second to do stuff.
// ...
// }
-// base::RepeatingTimer<MyClass> timer_;
+// base::RepeatingTimer timer_;
// };
//
// Both OneShotTimer and RepeatingTimer also support a Reset method, which
@@ -50,11 +50,11 @@
// should be able to tell the difference.
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/location.h"
+#include "base/macros.h"
#include "base/time/time.h"
namespace base {
@@ -200,11 +200,8 @@ class BASE_EXPORT Timer {
//-----------------------------------------------------------------------------
// This class is an implementation detail of OneShotTimer and RepeatingTimer.
// Please do not use this class directly.
-template <class Receiver, bool kIsRepeating>
class BaseTimerMethodPointer : public Timer {
public:
- typedef void (Receiver::*ReceiverMethod)();
-
// This is here to work around the fact that Timer::Start is "hidden" by the
// Start definition below, rather than being overloaded.
// TODO(tim): We should remove uses of BaseTimerMethodPointer::Start below
@@ -212,15 +209,18 @@ class BaseTimerMethodPointer : public Timer {
// see bug 148832.
using Timer::Start;
- BaseTimerMethodPointer() : Timer(kIsRepeating, kIsRepeating) {}
+ enum RepeatMode { ONE_SHOT, REPEATING };
+ BaseTimerMethodPointer(RepeatMode mode)
+ : Timer(mode == REPEATING, mode == REPEATING) {}
// Start the timer to run at the given |delay| from now. If the timer is
// already running, it will be replaced to call a task formed from
// |reviewer->*method|.
- virtual void Start(const tracked_objects::Location& posted_from,
- TimeDelta delay,
- Receiver* receiver,
- ReceiverMethod method) {
+ template <class Receiver>
+ void Start(const tracked_objects::Location& posted_from,
+ TimeDelta delay,
+ Receiver* receiver,
+ void (Receiver::*method)()) {
Timer::Start(posted_from, delay,
base::Bind(method, base::Unretained(receiver)));
}
@@ -228,13 +228,17 @@ class BaseTimerMethodPointer : public Timer {
//-----------------------------------------------------------------------------
// A simple, one-shot timer. See usage notes at the top of the file.
-template <class Receiver>
-class OneShotTimer : public BaseTimerMethodPointer<Receiver, false> {};
+class OneShotTimer : public BaseTimerMethodPointer {
+ public:
+ OneShotTimer() : BaseTimerMethodPointer(ONE_SHOT) {}
+};
//-----------------------------------------------------------------------------
// A simple, repeating timer. See usage notes at the top of the file.
-template <class Receiver>
-class RepeatingTimer : public BaseTimerMethodPointer<Receiver, true> {};
+class RepeatingTimer : public BaseTimerMethodPointer {
+ public:
+ RepeatingTimer() : BaseTimerMethodPointer(REPEATING) {}
+};
//-----------------------------------------------------------------------------
// A Delay timer is like The Button from Lost. Once started, you have to keep
@@ -247,22 +251,29 @@ class RepeatingTimer : public BaseTimerMethodPointer<Receiver, true> {};
//
// If destroyed, the timeout is canceled and will not occur even if already
// inflight.
-template <class Receiver>
class DelayTimer : protected Timer {
public:
- typedef void (Receiver::*ReceiverMethod)();
-
+ template <class Receiver>
DelayTimer(const tracked_objects::Location& posted_from,
TimeDelta delay,
Receiver* receiver,
- ReceiverMethod method)
- : Timer(posted_from, delay,
+ void (Receiver::*method)())
+ : Timer(posted_from,
+ delay,
base::Bind(method, base::Unretained(receiver)),
false) {}
- void Reset() override { Timer::Reset(); }
+ void Reset() override;
};
+// This class has a templated method so it can not be exported without failing
+// to link in MSVC. But clang-plugin does not allow inline definitions of
+// virtual methods, so the inline definition lives in the header file here
+// to satisfy both.
+inline void DelayTimer::Reset() {
+ Timer::Reset();
+}
+
} // namespace base
#endif // BASE_TIMER_TIMER_H_
diff --git a/base/timer/timer_unittest.cc b/base/timer/timer_unittest.cc
index 7213b809b7..b1d3c3e932 100644
--- a/base/timer/timer_unittest.cc
+++ b/base/timer/timer_unittest.cc
@@ -2,10 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stddef.h>
+
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/test/test_simple_task_runner.h"
#include "base/timer/timer.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::TimeDelta;
@@ -51,17 +55,15 @@ class OneShotTimerTester {
}
bool* did_run_;
- base::OneShotTimer<OneShotTimerTester> timer_;
+ base::OneShotTimer timer_;
const unsigned delay_ms_;
bool quit_message_loop_;
};
class OneShotSelfDeletingTimerTester {
public:
- explicit OneShotSelfDeletingTimerTester(bool* did_run) :
- did_run_(did_run),
- timer_(new base::OneShotTimer<OneShotSelfDeletingTimerTester>()) {
- }
+ explicit OneShotSelfDeletingTimerTester(bool* did_run)
+ : did_run_(did_run), timer_(new base::OneShotTimer()) {}
void Start() {
timer_->Start(FROM_HERE, TimeDelta::FromMilliseconds(10), this,
@@ -76,7 +78,7 @@ class OneShotSelfDeletingTimerTester {
}
bool* did_run_;
- scoped_ptr<base::OneShotTimer<OneShotSelfDeletingTimerTester> > timer_;
+ scoped_ptr<base::OneShotTimer> timer_;
};
class RepeatingTimerTester {
@@ -101,7 +103,7 @@ class RepeatingTimerTester {
bool* did_run_;
int counter_;
TimeDelta delay_;
- base::RepeatingTimer<RepeatingTimerTester> timer_;
+ base::RepeatingTimer timer_;
};
void RunTest_OneShotTimer(base::MessageLoop::Type message_loop_type) {
@@ -205,8 +207,8 @@ void RunTest_DelayTimer_NoCall(base::MessageLoop::Type message_loop_type) {
// If Delay is never called, the timer shouldn't go off.
DelayTimerTarget target;
- base::DelayTimer<DelayTimerTarget> timer(FROM_HERE,
- TimeDelta::FromMilliseconds(1), &target, &DelayTimerTarget::Signal);
+ base::DelayTimer timer(FROM_HERE, TimeDelta::FromMilliseconds(1), &target,
+ &DelayTimerTarget::Signal);
bool did_run = false;
OneShotTimerTester tester(&did_run);
@@ -220,8 +222,8 @@ void RunTest_DelayTimer_OneCall(base::MessageLoop::Type message_loop_type) {
base::MessageLoop loop(message_loop_type);
DelayTimerTarget target;
- base::DelayTimer<DelayTimerTarget> timer(FROM_HERE,
- TimeDelta::FromMilliseconds(1), &target, &DelayTimerTarget::Signal);
+ base::DelayTimer timer(FROM_HERE, TimeDelta::FromMilliseconds(1), &target,
+ &DelayTimerTarget::Signal);
timer.Reset();
bool did_run = false;
@@ -233,11 +235,8 @@ void RunTest_DelayTimer_OneCall(base::MessageLoop::Type message_loop_type) {
}
struct ResetHelper {
- ResetHelper(base::DelayTimer<DelayTimerTarget>* timer,
- DelayTimerTarget* target)
- : timer_(timer),
- target_(target) {
- }
+ ResetHelper(base::DelayTimer* timer, DelayTimerTarget* target)
+ : timer_(timer), target_(target) {}
void Reset() {
ASSERT_FALSE(target_->signaled());
@@ -245,8 +244,8 @@ struct ResetHelper {
}
private:
- base::DelayTimer<DelayTimerTarget> *const timer_;
- DelayTimerTarget *const target_;
+ base::DelayTimer* const timer_;
+ DelayTimerTarget* const target_;
};
void RunTest_DelayTimer_Reset(base::MessageLoop::Type message_loop_type) {
@@ -254,13 +253,13 @@ void RunTest_DelayTimer_Reset(base::MessageLoop::Type message_loop_type) {
// If Delay is never called, the timer shouldn't go off.
DelayTimerTarget target;
- base::DelayTimer<DelayTimerTarget> timer(FROM_HERE,
- TimeDelta::FromMilliseconds(50), &target, &DelayTimerTarget::Signal);
+ base::DelayTimer timer(FROM_HERE, TimeDelta::FromMilliseconds(50), &target,
+ &DelayTimerTarget::Signal);
timer.Reset();
ResetHelper reset_helper(&timer, &target);
- base::OneShotTimer<ResetHelper> timers[20];
+ base::OneShotTimer timers[20];
for (size_t i = 0; i < arraysize(timers); ++i) {
timers[i].Start(FROM_HERE, TimeDelta::FromMilliseconds(i * 10),
&reset_helper, &ResetHelper::Reset);
@@ -288,9 +287,8 @@ void RunTest_DelayTimer_Deleted(base::MessageLoop::Type message_loop_type) {
DelayTimerFatalTarget target;
{
- base::DelayTimer<DelayTimerFatalTarget> timer(
- FROM_HERE, TimeDelta::FromMilliseconds(50), &target,
- &DelayTimerFatalTarget::Signal);
+ base::DelayTimer timer(FROM_HERE, TimeDelta::FromMilliseconds(50), &target,
+ &DelayTimerFatalTarget::Signal);
timer.Reset();
}
diff --git a/base/trace_event/BUILD.gn b/base/trace_event/BUILD.gn
deleted file mode 100644
index 3a8a5bf2b8..0000000000
--- a/base/trace_event/BUILD.gn
+++ /dev/null
@@ -1,115 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-source_set("trace_event") {
- sources = [
- "java_heap_dump_provider_android.cc",
- "java_heap_dump_provider_android.h",
- "memory_allocator_dump.cc",
- "memory_allocator_dump.h",
- "memory_allocator_dump_guid.cc",
- "memory_allocator_dump_guid.h",
- "memory_dump_manager.cc",
- "memory_dump_manager.h",
- "memory_dump_provider.h",
- "memory_dump_request_args.h",
- "memory_dump_session_state.cc",
- "memory_dump_session_state.h",
- "process_memory_dump.cc",
- "process_memory_dump.h",
- "process_memory_maps.cc",
- "process_memory_maps.h",
- "process_memory_maps_dump_provider.cc",
- "process_memory_maps_dump_provider.h",
- "process_memory_totals.cc",
- "process_memory_totals.h",
- "process_memory_totals_dump_provider.cc",
- "process_memory_totals_dump_provider.h",
- "trace_config.cc",
- "trace_config.h",
- "trace_event.h",
- "trace_event_android.cc",
- "trace_event_argument.cc",
- "trace_event_argument.h",
- "trace_event_etw_export_win.cc",
- "trace_event_etw_export_win.h",
- "trace_event_impl.cc",
- "trace_event_impl.h",
- "trace_event_impl_constants.cc",
- "trace_event_memory.cc",
- "trace_event_memory.h",
- "trace_event_memory_overhead.cc",
- "trace_event_memory_overhead.h",
- "trace_event_synthetic_delay.cc",
- "trace_event_synthetic_delay.h",
- "trace_event_system_stats_monitor.cc",
- "trace_event_system_stats_monitor.h",
- "trace_event_win.cc",
- "trace_event_win.h",
- "winheap_dump_provider_win.cc",
- "winheap_dump_provider_win.h",
- ]
-
- if (is_nacl) {
- sources -= [
- "process_memory_totals_dump_provider.cc",
- "trace_event_system_stats_monitor.cc",
- ]
- }
-
- if (is_linux || is_android) {
- sources += [
- "malloc_dump_provider.cc",
- "malloc_dump_provider.h",
- ]
- }
-
- configs += [ "//base:base_implementation" ]
-
- deps = [
- "//base/debug",
- "//base/json",
- "//base/memory",
- "//base/process",
- "//base/third_party/dynamic_annotations",
- ]
-
- if (is_win) {
- deps += [ "//base/trace_event/etw_manifest:chrome_events_win" ]
- }
-
- allow_circular_includes_from = [
- "//base/debug",
- "//base/memory",
- "//base/process",
- ]
-
- visibility = [ "//base/*" ]
-}
-
-source_set("trace_event_unittests") {
- testonly = true
- sources = [
- "java_heap_dump_provider_android_unittest.cc",
- "memory_allocator_dump_unittest.cc",
- "memory_dump_manager_unittest.cc",
- "process_memory_dump_unittest.cc",
- "process_memory_maps_dump_provider_unittest.cc",
- "process_memory_totals_dump_provider_unittest.cc",
- "trace_config_unittest.cc",
- "trace_event_argument_unittest.cc",
- "trace_event_memory_unittest.cc",
- "trace_event_synthetic_delay_unittest.cc",
- "trace_event_system_stats_monitor_unittest.cc",
- "trace_event_unittest.cc",
- "trace_event_win_unittest.cc",
- "winheap_dump_provider_win_unittest.cc",
- ]
-
- deps = [
- "//base/test:test_support",
- "//testing/gmock",
- "//testing/gtest",
- ]
-}
diff --git a/base/trace_event/OWNERS b/base/trace_event/OWNERS
index aa1d675f75..9160267bea 100644
--- a/base/trace_event/OWNERS
+++ b/base/trace_event/OWNERS
@@ -1,4 +1,6 @@
-nduca@chromium.org
dsinclair@chromium.org
+nduca@chromium.org
+oysteine@chromium.org
primiano@chromium.org
+simonhatch@chromium.org
per-file trace_event_android.cc=wangxianzhu@chromium.org
diff --git a/base/trace_event/common/trace_event_common.h b/base/trace_event/common/trace_event_common.h
new file mode 100644
index 0000000000..a266cd53da
--- /dev/null
+++ b/base/trace_event/common/trace_event_common.h
@@ -0,0 +1,1066 @@
+// Copyright 2015 The Chromium 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.
+
+// IMPORTANT: To avoid conflicts, if you need to modify this file for a library,
+// land your change in base/ first, and then copy-and-paste it.
+
+// 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"));
+//
+//
+// Convertable 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::trace_event::ConvertableToTraceFormat {
+// public:
+// MyData() {}
+// void AppendAsTraceFormat(std::string* out) const override {
+// out->append("{\"foo\":1}");
+// }
+// private:
+// ~MyData() override {}
+// DISALLOW_COPY_AND_ASSIGN(MyData);
+// };
+//
+// TRACE_EVENT1("foo", "bar", "data",
+// scoped_refptr<ConvertableToTraceFormat>(new MyData()));
+//
+// 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.
+
+#if defined(TRACE_EVENT0)
+#error "Another copy of this file has already been included."
+#endif
+
+// 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
+
+// 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_EVENT_ADD_SCOPED(category_group, name)
+#define TRACE_EVENT_WITH_FLOW0(category_group, name, bind_id, flow_flags) \
+ INTERNAL_TRACE_EVENT_ADD_SCOPED_WITH_FLOW(category_group, name, bind_id, \
+ flow_flags)
+#define TRACE_EVENT1(category_group, name, arg1_name, arg1_val) \
+ INTERNAL_TRACE_EVENT_ADD_SCOPED(category_group, name, arg1_name, arg1_val)
+#define TRACE_EVENT_WITH_FLOW1(category_group, name, bind_id, flow_flags, \
+ arg1_name, arg1_val) \
+ INTERNAL_TRACE_EVENT_ADD_SCOPED_WITH_FLOW(category_group, name, bind_id, \
+ flow_flags, arg1_name, arg1_val)
+#define TRACE_EVENT2(category_group, name, arg1_name, arg1_val, arg2_name, \
+ arg2_val) \
+ INTERNAL_TRACE_EVENT_ADD_SCOPED(category_group, name, arg1_name, arg1_val, \
+ arg2_name, arg2_val)
+#define TRACE_EVENT_WITH_FLOW2(category_group, name, bind_id, flow_flags, \
+ arg1_name, arg1_val, arg2_name, arg2_val) \
+ INTERNAL_TRACE_EVENT_ADD_SCOPED_WITH_FLOW(category_group, name, bind_id, \
+ flow_flags, 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)
+
+#define TRACE_EVENT_INSTANT_WITH_TIMESTAMP0(category_group, name, scope, \
+ timestamp) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+ TRACE_EVENT_PHASE_INSTANT, category_group, name, 0, 0, timestamp, \
+ TRACE_EVENT_FLAG_NONE | scope)
+
+// 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)
+#define TRACE_EVENT_SET_NONCONST_SAMPLING_STATE(categoryAndName) \
+ TRACE_EVENT_SET_NONCONST_SAMPLING_STATE_FOR_BUCKET(0, categoryAndName)
+
+// 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)
+#define TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP1( \
+ category_group, name, id, thread_id, timestamp, arg1_name, arg1_val) \
+ 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, arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP2( \
+ category_group, name, id, thread_id, timestamp, arg1_name, arg1_val, \
+ arg2_name, arg2_val) \
+ 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, arg1_name, arg1_val, arg2_name, \
+ arg2_val)
+
+// 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)
+
+#define TRACE_EVENT_MARK_WITH_TIMESTAMP1(category_group, name, timestamp, \
+ arg1_name, arg1_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+ TRACE_EVENT_PHASE_MARK, category_group, name, 0, 0, timestamp, \
+ TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+
+#define TRACE_EVENT_COPY_MARK(category_group, name) \
+ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_MARK, category_group, name, \
+ TRACE_EVENT_FLAG_COPY)
+
+#define TRACE_EVENT_COPY_MARK_WITH_TIMESTAMP(category_group, name, timestamp) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+ TRACE_EVENT_PHASE_MARK, category_group, name, 0, 0, timestamp, \
+ TRACE_EVENT_FLAG_COPY)
+
+// 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)
+#define TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP1( \
+ category_group, name, id, thread_id, timestamp, arg1_name, arg1_val) \
+ 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, arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP2( \
+ category_group, name, id, thread_id, timestamp, arg1_name, arg1_val, \
+ arg2_name, arg2_val) \
+ 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, arg1_name, arg1_val, arg2_name, \
+ arg2_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.
+#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<int>(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<int>(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<int>(value1_val), value2_name, \
+ static_cast<int>(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<int>(value1_val), value2_name, \
+ static_cast<int>(value2_val))
+
+// Similar to TRACE_COUNTERx, but with a custom |timestamp| provided.
+#define TRACE_COUNTER_WITH_TIMESTAMP1(category_group, name, timestamp, value) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP( \
+ TRACE_EVENT_PHASE_COUNTER, category_group, name, timestamp, \
+ TRACE_EVENT_FLAG_NONE, "value", static_cast<int>(value))
+
+#define TRACE_COUNTER_WITH_TIMESTAMP2(category_group, name, timestamp, \
+ value1_name, value1_val, value2_name, \
+ value2_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP( \
+ TRACE_EVENT_PHASE_COUNTER, category_group, name, timestamp, \
+ TRACE_EVENT_FLAG_NONE, value1_name, static_cast<int>(value1_val), \
+ value2_name, static_cast<int>(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<int>(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<int>(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<int>(value1_val), \
+ value2_name, static_cast<int>(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<int>(value1_val), \
+ value2_name, static_cast<int>(value2_val))
+
+// TRACE_EVENT_SAMPLE_* events are injected by the sampling profiler.
+#define TRACE_EVENT_SAMPLE_WITH_TID_AND_TIMESTAMP0(category_group, name, \
+ thread_id, timestamp) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+ TRACE_EVENT_PHASE_SAMPLE, category_group, name, 0, thread_id, timestamp, \
+ TRACE_EVENT_FLAG_NONE)
+
+#define TRACE_EVENT_SAMPLE_WITH_TID_AND_TIMESTAMP1( \
+ category_group, name, thread_id, timestamp, arg1_name, arg1_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+ TRACE_EVENT_PHASE_SAMPLE, category_group, name, 0, thread_id, timestamp, \
+ TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+
+#define TRACE_EVENT_SAMPLE_WITH_TID_AND_TIMESTAMP2(category_group, name, \
+ thread_id, timestamp, \
+ arg1_name, arg1_val, \
+ arg2_name, arg2_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+ TRACE_EVENT_PHASE_SAMPLE, category_group, name, 0, thread_id, timestamp, \
+ TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, arg2_name, arg2_val)
+
+// ASYNC_STEP_* APIs should be only used by legacy code. New code should
+// consider using NESTABLE_ASYNC_* APIs to describe substeps within an async
+// event.
+// 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_INTO or ASYNC_STEP_PAST macros. The ASYNC_STEP_INTO macro will
+// annotate the block following the call. The ASYNC_STEP_PAST macro will
+// annotate the block prior to the call. Note that any particular event must use
+// only STEP_INTO or STEP_PAST macros; they can not mix and match. When the
+// operation completes, call ASYNC_END.
+//
+// An ASYNC trace typically occurs 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 step 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)
+
+// Similar to TRACE_EVENT_ASYNC_BEGINx but with a custom |at| timestamp
+// provided.
+#define TRACE_EVENT_ASYNC_BEGIN_WITH_TIMESTAMP0(category_group, name, id, \
+ timestamp) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+ TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, \
+ TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_ASYNC_BEGIN_WITH_TIMESTAMP1( \
+ category_group, name, id, timestamp, arg1_name, arg1_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+ TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, \
+ TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE, \
+ arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_ASYNC_BEGIN_WITH_TIMESTAMP0(category_group, name, id, \
+ timestamp) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+ TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, \
+ TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_COPY)
+
+// Records a single ASYNC_STEP_INTO 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. The ASYNC_BEGIN event must not have any
+// ASYNC_STEP_PAST events.
+#define TRACE_EVENT_ASYNC_STEP_INTO0(category_group, name, id, step) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP_INTO, \
+ category_group, name, id, \
+ TRACE_EVENT_FLAG_NONE, "step", step)
+#define TRACE_EVENT_ASYNC_STEP_INTO1(category_group, name, id, step, \
+ arg1_name, arg1_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID( \
+ TRACE_EVENT_PHASE_ASYNC_STEP_INTO, category_group, name, id, \
+ TRACE_EVENT_FLAG_NONE, "step", step, arg1_name, arg1_val)
+
+// Similar to TRACE_EVENT_ASYNC_STEP_INTOx but with a custom |at| timestamp
+// provided.
+#define TRACE_EVENT_ASYNC_STEP_INTO_WITH_TIMESTAMP0(category_group, name, id, \
+ step, timestamp) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+ TRACE_EVENT_PHASE_ASYNC_STEP_INTO, category_group, name, id, \
+ TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE, \
+ "step", step)
+
+// Records a single ASYNC_STEP_PAST 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. The ASYNC_BEGIN event must not have any
+// ASYNC_STEP_INTO events.
+#define TRACE_EVENT_ASYNC_STEP_PAST0(category_group, name, id, step) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP_PAST, \
+ category_group, name, id, \
+ TRACE_EVENT_FLAG_NONE, "step", step)
+#define TRACE_EVENT_ASYNC_STEP_PAST1(category_group, name, id, step, \
+ arg1_name, arg1_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID( \
+ TRACE_EVENT_PHASE_ASYNC_STEP_PAST, category_group, name, id, \
+ TRACE_EVENT_FLAG_NONE, "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)
+
+// Similar to TRACE_EVENT_ASYNC_ENDx but with a custom |at| timestamp provided.
+#define TRACE_EVENT_ASYNC_END_WITH_TIMESTAMP0(category_group, name, id, \
+ timestamp) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+ TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, \
+ TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_ASYNC_END_WITH_TIMESTAMP1(category_group, name, id, \
+ timestamp, arg1_name, arg1_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+ TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, \
+ TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE, \
+ arg1_name, arg1_val)
+
+// NESTABLE_ASYNC_* APIs are used to describe an async operation, which can
+// be nested within a NESTABLE_ASYNC event and/or have inner NESTABLE_ASYNC
+// events.
+// - category and name strings must have application lifetime (statics or
+// literals). They may not include " chars.
+// - A pair of NESTABLE_ASYNC_BEGIN event and NESTABLE_ASYNC_END event is
+// considered as a match if their category_group, name and id 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.
+// - |id| is used to match a child NESTABLE_ASYNC event with its parent
+// NESTABLE_ASYNC event. Therefore, events in the same nested event tree must
+// be logged using the same id and category_group.
+//
+// Unmatched NESTABLE_ASYNC_END event will be parsed as an event that starts
+// at the first NESTABLE_ASYNC event of that id, and unmatched
+// NESTABLE_ASYNC_BEGIN event will be parsed as an event that ends at the last
+// NESTABLE_ASYNC event of that id. Corresponding warning messages for
+// unmatched events will be shown in the analysis view.
+
+// Records a single NESTABLE_ASYNC_BEGIN event called "name" immediately, with
+// 0, 1 or 2 associated arguments. If the category is not enabled, then this
+// does nothing.
+#define TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(category_group, name, id) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, \
+ category_group, name, id, \
+ TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(category_group, name, id, arg1_name, \
+ arg1_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, \
+ category_group, name, id, \
+ TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+#define TRACE_EVENT_NESTABLE_ASYNC_BEGIN2(category_group, name, id, arg1_name, \
+ arg1_val, arg2_name, arg2_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID( \
+ TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, category_group, name, id, \
+ TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, arg2_name, arg2_val)
+// Records a single NESTABLE_ASYNC_END event called "name" immediately, with 0
+// or 2 associated arguments. If the category is not enabled, then this does
+// nothing.
+#define TRACE_EVENT_NESTABLE_ASYNC_END0(category_group, name, id) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, \
+ category_group, name, id, \
+ TRACE_EVENT_FLAG_NONE)
+// Records a single NESTABLE_ASYNC_END event called "name" immediately, with 1
+// associated argument. If the category is not enabled, then this does nothing.
+#define TRACE_EVENT_NESTABLE_ASYNC_END1(category_group, name, id, arg1_name, \
+ arg1_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, \
+ category_group, name, id, \
+ TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+#define TRACE_EVENT_NESTABLE_ASYNC_END2(category_group, name, id, arg1_name, \
+ arg1_val, arg2_name, arg2_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID( \
+ TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, category_group, name, id, \
+ TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, arg2_name, arg2_val)
+
+// Records a single NESTABLE_ASYNC_INSTANT event called "name" immediately,
+// with one associated argument. If the category is not enabled, then this
+// does nothing.
+#define TRACE_EVENT_NESTABLE_ASYNC_INSTANT1(category_group, name, id, \
+ arg1_name, arg1_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT, \
+ category_group, name, id, \
+ TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+// Records a single NESTABLE_ASYNC_INSTANT event called "name" immediately,
+// with 2 associated arguments. If the category is not enabled, then this
+// does nothing.
+#define TRACE_EVENT_NESTABLE_ASYNC_INSTANT2( \
+ category_group, name, id, arg1_name, arg1_val, arg2_name, arg2_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID( \
+ TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT, category_group, name, id, \
+ TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, arg2_name, arg2_val)
+
+#define TRACE_EVENT_COPY_NESTABLE_ASYNC_BEGIN_WITH_TTS2( \
+ category_group, name, id, arg1_name, arg1_val, arg2_name, arg2_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID( \
+ TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, category_group, name, id, \
+ TRACE_EVENT_FLAG_ASYNC_TTS | TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \
+ arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_NESTABLE_ASYNC_END_WITH_TTS2( \
+ category_group, name, id, arg1_name, arg1_val, arg2_name, arg2_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID( \
+ TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, category_group, name, id, \
+ TRACE_EVENT_FLAG_ASYNC_TTS | TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \
+ arg2_name, arg2_val)
+
+// Similar to TRACE_EVENT_NESTABLE_ASYNC_{BEGIN,END}x but with a custom
+// |timestamp| provided.
+#define TRACE_EVENT_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP0(category_group, name, \
+ id, timestamp) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+ TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, category_group, name, id, \
+ TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE)
+
+#define TRACE_EVENT_NESTABLE_ASYNC_END_WITH_TIMESTAMP0(category_group, name, \
+ id, timestamp) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+ TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, category_group, name, id, \
+ TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE)
+
+#define TRACE_EVENT_COPY_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP0( \
+ category_group, name, id, timestamp) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+ TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, category_group, name, id, \
+ TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_NESTABLE_ASYNC_END_WITH_TIMESTAMP0( \
+ category_group, name, id, timestamp) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+ TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, category_group, name, id, \
+ TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_COPY)
+
+// Records a single NESTABLE_ASYNC_INSTANT event called "name" immediately,
+// with 2 associated arguments. If the category is not enabled, then this
+// does nothing.
+#define TRACE_EVENT_NESTABLE_ASYNC_INSTANT2( \
+ category_group, name, id, arg1_name, arg1_val, arg2_name, arg2_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID( \
+ TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT, category_group, name, id, \
+ TRACE_EVENT_FLAG_NONE, 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_END_BIND_TO_ENCLOSING0(category_group, name, id) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, category_group, \
+ name, id, \
+ TRACE_EVENT_FLAG_BIND_TO_ENCLOSING)
+#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)
+
+// Records a clock sync event.
+#define TRACE_EVENT_CLOCK_SYNC_RECEIVER(sync_id) \
+ INTERNAL_TRACE_EVENT_ADD( \
+ TRACE_EVENT_PHASE_CLOCK_SYNC, "__metadata", "clock_sync", \
+ TRACE_EVENT_FLAG_NONE, "sync_id", sync_id)
+#define TRACE_EVENT_CLOCK_SYNC_ISSUER(sync_id, issue_ts, issue_end_ts) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP( \
+ TRACE_EVENT_PHASE_CLOCK_SYNC, "__metadata", "clock_sync", \
+ issue_end_ts.ToInternalValue(), TRACE_EVENT_FLAG_NONE, \
+ "sync_id", sync_id, "issue_ts", issue_ts.ToInternalValue())
+
+// 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_SNAPSHOT_WITH_ID_AND_TIMESTAMP( \
+ category_group, name, id, timestamp, snapshot) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+ TRACE_EVENT_PHASE_SNAPSHOT_OBJECT, category_group, name, \
+ TRACE_ID_DONT_MANGLE(id), TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, \
+ 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_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \
+ *ret = true; \
+ } else { \
+ *ret = false; \
+ } \
+ } while (0)
+
+// Macro to explicitly warm up a given category group. This could be useful in
+// cases where we want to initialize a category group before any trace events
+// for that category group is reported. For example, to have a category group
+// always show up in the "record categories" list for manually selecting
+// settings in about://tracing.
+#define TRACE_EVENT_WARMUP_CATEGORY(category_group) \
+ INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group)
+
+// 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)
+
+// 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_COMPLETE ('X')
+#define TRACE_EVENT_PHASE_INSTANT ('I')
+#define TRACE_EVENT_PHASE_ASYNC_BEGIN ('S')
+#define TRACE_EVENT_PHASE_ASYNC_STEP_INTO ('T')
+#define TRACE_EVENT_PHASE_ASYNC_STEP_PAST ('p')
+#define TRACE_EVENT_PHASE_ASYNC_END ('F')
+#define TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN ('b')
+#define TRACE_EVENT_PHASE_NESTABLE_ASYNC_END ('e')
+#define TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT ('n')
+#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')
+#define TRACE_EVENT_PHASE_MEMORY_DUMP ('v')
+#define TRACE_EVENT_PHASE_MARK ('R')
+#define TRACE_EVENT_PHASE_CLOCK_SYNC ('c')
+
+// Flags for changing the behavior of TRACE_EVENT_API_ADD_TRACE_EVENT.
+#define TRACE_EVENT_FLAG_NONE (static_cast<unsigned int>(0))
+#define TRACE_EVENT_FLAG_COPY (static_cast<unsigned int>(1 << 0))
+#define TRACE_EVENT_FLAG_HAS_ID (static_cast<unsigned int>(1 << 1))
+#define TRACE_EVENT_FLAG_MANGLE_ID (static_cast<unsigned int>(1 << 2))
+#define TRACE_EVENT_FLAG_SCOPE_OFFSET (static_cast<unsigned int>(1 << 3))
+#define TRACE_EVENT_FLAG_SCOPE_EXTRA (static_cast<unsigned int>(1 << 4))
+#define TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP (static_cast<unsigned int>(1 << 5))
+#define TRACE_EVENT_FLAG_ASYNC_TTS (static_cast<unsigned int>(1 << 6))
+#define TRACE_EVENT_FLAG_BIND_TO_ENCLOSING (static_cast<unsigned int>(1 << 7))
+#define TRACE_EVENT_FLAG_FLOW_IN (static_cast<unsigned int>(1 << 8))
+#define TRACE_EVENT_FLAG_FLOW_OUT (static_cast<unsigned int>(1 << 9))
+#define TRACE_EVENT_FLAG_HAS_CONTEXT_ID (static_cast<unsigned int>(1 << 10))
+#define TRACE_EVENT_FLAG_HAS_PROCESS_ID (static_cast<unsigned int>(1 << 11))
+
+#define TRACE_EVENT_FLAG_SCOPE_MASK \
+ (static_cast<unsigned int>(TRACE_EVENT_FLAG_SCOPE_OFFSET | \
+ TRACE_EVENT_FLAG_SCOPE_EXTRA))
+
+// Type values for identifying types in the TraceValue union.
+#define TRACE_VALUE_TYPE_BOOL (static_cast<unsigned char>(1))
+#define TRACE_VALUE_TYPE_UINT (static_cast<unsigned char>(2))
+#define TRACE_VALUE_TYPE_INT (static_cast<unsigned char>(3))
+#define TRACE_VALUE_TYPE_DOUBLE (static_cast<unsigned char>(4))
+#define TRACE_VALUE_TYPE_POINTER (static_cast<unsigned char>(5))
+#define TRACE_VALUE_TYPE_STRING (static_cast<unsigned char>(6))
+#define TRACE_VALUE_TYPE_COPY_STRING (static_cast<unsigned char>(7))
+#define TRACE_VALUE_TYPE_CONVERTABLE (static_cast<unsigned char>(8))
+
+// Enum reflecting the scope of an INSTANT event. Must fit within
+// TRACE_EVENT_FLAG_SCOPE_MASK.
+#define TRACE_EVENT_SCOPE_GLOBAL (static_cast<unsigned char>(0 << 3))
+#define TRACE_EVENT_SCOPE_PROCESS (static_cast<unsigned char>(1 << 3))
+#define TRACE_EVENT_SCOPE_THREAD (static_cast<unsigned char>(2 << 3))
+
+#define TRACE_EVENT_SCOPE_NAME_GLOBAL ('g')
+#define TRACE_EVENT_SCOPE_NAME_PROCESS ('p')
+#define TRACE_EVENT_SCOPE_NAME_THREAD ('t')
diff --git a/base/trace_event/etw_manifest/BUILD.gn b/base/trace_event/etw_manifest/BUILD.gn
index f62e356b11..1e16672825 100644
--- a/base/trace_event/etw_manifest/BUILD.gn
+++ b/base/trace_event/etw_manifest/BUILD.gn
@@ -2,47 +2,24 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/win/message_compiler.gni")
+
assert(is_win, "This only runs on Windows.")
-# Makes the .h/.rc files from the .man file.
-action("chrome_events_win_generate") {
- visibility = [ ":*" ]
- script = "build/message_compiler.py"
+message_compiler("chrome_events_win") {
+ visibility = [
+ "//base/*",
+ "//chrome:main_dll",
+ ]
sources = [
"chrome_events_win.man",
]
- outputs = [
- "$target_gen_dir/chrome_events_win.h",
- "$target_gen_dir/chrome_events_win.rc",
- ]
-
- args = [
- # Where to put the header.
- "-h",
- rebase_path("$target_gen_dir", root_build_dir),
-
- # Where to put the .rc file.
- "-r",
- rebase_path("$target_gen_dir", root_build_dir),
-
- # Generate the user-mode code.
- "-um",
- rebase_path("chrome_events_win.man", root_build_dir),
- ]
-}
-
-# Compile the generated files.
-source_set("chrome_events_win") {
- visibility = [
- "//base/trace_event/*",
- "//chrome:main_dll",
- ]
-
- sources = get_target_outputs(":chrome_events_win_generate")
+ user_mode_logging = true
- deps = [
- ":chrome_events_win_generate",
- ]
+ # TOOD(brucedawson) bug 569989: Enable ETW manifest and compile and link it
+ # into the proper places. Enabling as-is may add the resources to too many
+ # targets. See the bug for more information.
+ compile_generated_code = false
}
diff --git a/base/trace_event/etw_manifest/BUILD/message_compiler.py b/base/trace_event/etw_manifest/BUILD/message_compiler.py
deleted file mode 100644
index be5927d9be..0000000000
--- a/base/trace_event/etw_manifest/BUILD/message_compiler.py
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2015 The Chromium 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 the Microsoft Message Compiler (mc.exe). This Python adapter is for the
-# GN build, which can only run Python and not native binaries.
-
-import subprocess
-import sys
-
-# mc writes to stderr, so this explicily redirects to stdout and eats it.
-try:
- subprocess.check_output(["mc.exe"] + sys.argv[1:], stderr=subprocess.STDOUT)
-except subprocess.CalledProcessError as e:
- print e.output
- sys.exit(e.returncode)
diff --git a/base/trace_event/heap_profiler_allocation_context.cc b/base/trace_event/heap_profiler_allocation_context.cc
new file mode 100644
index 0000000000..dcef5bd177
--- /dev/null
+++ b/base/trace_event/heap_profiler_allocation_context.cc
@@ -0,0 +1,68 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/heap_profiler_allocation_context.h"
+
+#include <cstring>
+
+#include "base/hash.h"
+#include "base/macros.h"
+
+namespace base {
+namespace trace_event {
+
+// Constructor that does not initialize members.
+AllocationContext::AllocationContext() {}
+
+// static
+AllocationContext AllocationContext::Empty() {
+ AllocationContext ctx;
+
+ for (size_t i = 0; i < arraysize(ctx.backtrace.frames); i++)
+ ctx.backtrace.frames[i] = nullptr;
+
+ ctx.type_name = nullptr;
+
+ return ctx;
+}
+
+bool operator==(const Backtrace& lhs, const Backtrace& rhs) {
+ // Pointer equality of the stack frames is assumed, so instead of doing a deep
+ // string comparison on all of the frames, a |memcmp| suffices.
+ return std::memcmp(lhs.frames, rhs.frames, sizeof(lhs.frames)) == 0;
+}
+
+bool operator==(const AllocationContext& lhs, const AllocationContext& rhs) {
+ return (lhs.backtrace == rhs.backtrace) && (lhs.type_name == rhs.type_name);
+}
+
+} // namespace trace_event
+} // namespace base
+
+namespace BASE_HASH_NAMESPACE {
+using base::trace_event::AllocationContext;
+using base::trace_event::Backtrace;
+
+size_t hash<Backtrace>::operator()(const Backtrace& backtrace) const {
+ return base::Hash(
+ std::string(reinterpret_cast<const char*>(backtrace.frames),
+ sizeof(backtrace.frames)));
+}
+
+size_t hash<AllocationContext>::operator()(const AllocationContext& ctx) const {
+ size_t backtrace_hash = hash<Backtrace>()(ctx.backtrace);
+
+ // Multiplicative hash from [Knuth 1998]. Works best if |size_t| is 32 bits,
+ // because the magic number is a prime very close to 2^32 / golden ratio, but
+ // will still redistribute keys bijectively on 64-bit architectures because
+ // the magic number is coprime to 2^64.
+ size_t type_hash = reinterpret_cast<size_t>(ctx.type_name) * 2654435761;
+
+ // Multiply one side to break the commutativity of +. Multiplication with a
+ // number coprime to |numeric_limits<size_t>::max() + 1| is bijective so
+ // randomness is preserved.
+ return (backtrace_hash * 3) + type_hash;
+}
+
+} // BASE_HASH_NAMESPACE
diff --git a/base/trace_event/heap_profiler_allocation_context.h b/base/trace_event/heap_profiler_allocation_context.h
new file mode 100644
index 0000000000..8544c78eb2
--- /dev/null
+++ b/base/trace_event/heap_profiler_allocation_context.h
@@ -0,0 +1,97 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_CONTEXT_H_
+#define BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_CONTEXT_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/base_export.h"
+#include "base/containers/hash_tables.h"
+
+namespace base {
+namespace trace_event {
+
+// When heap profiling is enabled, tracing keeps track of the allocation
+// context for each allocation intercepted. It is generated by the
+// |AllocationContextTracker| which keeps stacks of context in TLS.
+// The tracker is initialized lazily.
+
+// The backtrace in the allocation context is a snapshot of the stack. For now,
+// this is the pseudo stack where frames are created by trace event macros. In
+// the future, we might add the option to use the native call stack. In that
+// case, |Backtrace| and |AllocationContextTracker::GetContextSnapshot| might
+// have different implementations that can be selected by a compile time flag.
+
+// The number of stack frames stored in the backtrace is a trade off between
+// memory used for tracing and accuracy. Measurements done on a prototype
+// revealed that:
+//
+// - In 60 percent of the cases, stack depth <= 7.
+// - In 87 percent of the cases, stack depth <= 9.
+// - In 95 percent of the cases, stack depth <= 11.
+//
+// See the design doc (https://goo.gl/4s7v7b) for more details.
+
+using StackFrame = const char*;
+
+struct BASE_EXPORT Backtrace {
+ // Unused backtrace frames are filled with nullptr frames. If the stack is
+ // higher than what can be stored here, the bottom frames are stored. Based
+ // on the data above, a depth of 12 captures the full stack in the vast
+ // majority of the cases.
+ StackFrame frames[12];
+};
+
+bool BASE_EXPORT operator==(const Backtrace& lhs, const Backtrace& rhs);
+
+// The |AllocationContext| is context metadata that is kept for every allocation
+// when heap profiling is enabled. To simplify memory management for book-
+// keeping, this struct has a fixed size. All |const char*|s here must have
+// static lifetime.
+struct BASE_EXPORT AllocationContext {
+ public:
+ // An allocation context with empty backtrace and unknown type.
+ static AllocationContext Empty();
+
+ Backtrace backtrace;
+
+ // Type name of the type stored in the allocated memory. A null pointer
+ // indicates "unknown type". Grouping is done by comparing pointers, not by
+ // deep string comparison. In a component build, where a type name can have a
+ // string literal in several dynamic libraries, this may distort grouping.
+ const char* type_name;
+
+ private:
+ friend class AllocationContextTracker;
+
+ // Don't allow uninitialized instances except inside the allocation context
+ // tracker. Except in tests, an |AllocationContext| should only be obtained
+ // from the tracker. In tests, paying the overhead of initializing the struct
+ // to |Empty| and then overwriting the members is not such a big deal.
+ AllocationContext();
+};
+
+bool BASE_EXPORT operator==(const AllocationContext& lhs,
+ const AllocationContext& rhs);
+
+} // namespace trace_event
+} // namespace base
+
+namespace BASE_HASH_NAMESPACE {
+
+template <>
+struct BASE_EXPORT hash<base::trace_event::Backtrace> {
+ size_t operator()(const base::trace_event::Backtrace& backtrace) const;
+};
+
+template <>
+struct BASE_EXPORT hash<base::trace_event::AllocationContext> {
+ size_t operator()(const base::trace_event::AllocationContext& context) const;
+};
+
+} // BASE_HASH_NAMESPACE
+
+#endif // BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_CONTEXT_H_
diff --git a/base/trace_event/heap_profiler_allocation_context_tracker.cc b/base/trace_event/heap_profiler_allocation_context_tracker.cc
new file mode 100644
index 0000000000..791ab7a6fe
--- /dev/null
+++ b/base/trace_event/heap_profiler_allocation_context_tracker.cc
@@ -0,0 +1,115 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/heap_profiler_allocation_context_tracker.h"
+
+#include <algorithm>
+#include <iterator>
+
+#include "base/atomicops.h"
+#include "base/threading/thread_local_storage.h"
+#include "base/trace_event/heap_profiler_allocation_context.h"
+
+namespace base {
+namespace trace_event {
+
+subtle::Atomic32 AllocationContextTracker::capture_enabled_ = 0;
+
+namespace {
+
+ThreadLocalStorage::StaticSlot g_tls_alloc_ctx_tracker = TLS_INITIALIZER;
+
+// This function is added to the TLS slot to clean up the instance when the
+// thread exits.
+void DestructAllocationContextTracker(void* alloc_ctx_tracker) {
+ delete static_cast<AllocationContextTracker*>(alloc_ctx_tracker);
+}
+
+} // namespace
+
+AllocationContextTracker::AllocationContextTracker() {}
+AllocationContextTracker::~AllocationContextTracker() {}
+
+// static
+AllocationContextTracker* AllocationContextTracker::GetThreadLocalTracker() {
+ auto tracker =
+ static_cast<AllocationContextTracker*>(g_tls_alloc_ctx_tracker.Get());
+
+ if (!tracker) {
+ tracker = new AllocationContextTracker();
+ g_tls_alloc_ctx_tracker.Set(tracker);
+ }
+
+ return tracker;
+}
+
+// static
+void AllocationContextTracker::SetCaptureEnabled(bool enabled) {
+ // When enabling capturing, also initialize the TLS slot. This does not create
+ // a TLS instance yet.
+ if (enabled && !g_tls_alloc_ctx_tracker.initialized())
+ g_tls_alloc_ctx_tracker.Initialize(DestructAllocationContextTracker);
+
+ // Release ordering ensures that when a thread observes |capture_enabled_| to
+ // be true through an acquire load, the TLS slot has been initialized.
+ subtle::Release_Store(&capture_enabled_, enabled);
+}
+
+// static
+void AllocationContextTracker::PushPseudoStackFrame(StackFrame frame) {
+ auto tracker = AllocationContextTracker::GetThreadLocalTracker();
+
+ // Impose a limit on the height to verify that every push is popped, because
+ // in practice the pseudo stack never grows higher than ~20 frames.
+ DCHECK_LT(tracker->pseudo_stack_.size(), 128u);
+ tracker->pseudo_stack_.push_back(frame);
+}
+
+// static
+void AllocationContextTracker::PopPseudoStackFrame(StackFrame frame) {
+ auto tracker = AllocationContextTracker::GetThreadLocalTracker();
+
+ // Guard for stack underflow. If tracing was started with a TRACE_EVENT in
+ // scope, the frame was never pushed, so it is possible that pop is called
+ // on an empty stack.
+ if (tracker->pseudo_stack_.empty())
+ return;
+
+ // Assert that pushes and pops are nested correctly. This DCHECK can be
+ // hit if some TRACE_EVENT macro is unbalanced (a TRACE_EVENT_END* call
+ // without a corresponding TRACE_EVENT_BEGIN).
+ DCHECK_EQ(frame, tracker->pseudo_stack_.back())
+ << "Encountered an unmatched TRACE_EVENT_END";
+
+ tracker->pseudo_stack_.pop_back();
+}
+
+// static
+AllocationContext AllocationContextTracker::GetContextSnapshot() {
+ AllocationContextTracker* tracker = GetThreadLocalTracker();
+ AllocationContext ctx;
+
+ // Fill the backtrace.
+ {
+ auto src = tracker->pseudo_stack_.begin();
+ auto dst = std::begin(ctx.backtrace.frames);
+ auto src_end = tracker->pseudo_stack_.end();
+ auto dst_end = std::end(ctx.backtrace.frames);
+
+ // Copy as much of the bottom of the pseudo stack into the backtrace as
+ // possible.
+ for (; src != src_end && dst != dst_end; src++, dst++)
+ *dst = *src;
+
+ // If there is room for more, fill the remaining slots with empty frames.
+ std::fill(dst, dst_end, nullptr);
+ }
+
+ ctx.type_name = nullptr;
+
+ return ctx;
+}
+
+} // namespace trace_event
+} // namespace base
diff --git a/base/trace_event/heap_profiler_allocation_context_tracker.h b/base/trace_event/heap_profiler_allocation_context_tracker.h
new file mode 100644
index 0000000000..9c9a3132ab
--- /dev/null
+++ b/base/trace_event/heap_profiler_allocation_context_tracker.h
@@ -0,0 +1,73 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_CONTEXT_TRACKER_H_
+#define BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_CONTEXT_TRACKER_H_
+
+#include <vector>
+
+#include "base/atomicops.h"
+#include "base/base_export.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/trace_event/heap_profiler_allocation_context.h"
+
+namespace base {
+namespace trace_event {
+
+// The allocation context tracker keeps track of thread-local context for heap
+// profiling. It includes a pseudo stack of trace events. On every allocation
+// the tracker provides a snapshot of its context in the form of an
+// |AllocationContext| that is to be stored together with the allocation
+// details.
+class BASE_EXPORT AllocationContextTracker {
+ public:
+ // Globally enables capturing allocation context.
+ // TODO(ruuda): Should this be replaced by |EnableCapturing| in the future?
+ // Or at least have something that guards agains enable -> disable -> enable?
+ static void SetCaptureEnabled(bool enabled);
+
+ // Returns whether capturing allocation context is enabled globally.
+ inline static bool capture_enabled() {
+ // A little lag after heap profiling is enabled or disabled is fine, it is
+ // more important that the check is as cheap as possible when capturing is
+ // not enabled, so do not issue a memory barrier in the fast path.
+ if (subtle::NoBarrier_Load(&capture_enabled_) == 0)
+ return false;
+
+ // In the slow path, an acquire load is required to pair with the release
+ // store in |SetCaptureEnabled|. This is to ensure that the TLS slot for
+ // the thread-local allocation context tracker has been initialized if
+ // |capture_enabled| returns true.
+ return subtle::Acquire_Load(&capture_enabled_) != 0;
+ }
+
+ // Pushes a frame onto the thread-local pseudo stack.
+ static void PushPseudoStackFrame(StackFrame frame);
+
+ // Pops a frame from the thread-local pseudo stack.
+ static void PopPseudoStackFrame(StackFrame frame);
+
+ // Returns a snapshot of the current thread-local context.
+ static AllocationContext GetContextSnapshot();
+
+ ~AllocationContextTracker();
+
+ private:
+ AllocationContextTracker();
+
+ static AllocationContextTracker* GetThreadLocalTracker();
+
+ static subtle::Atomic32 capture_enabled_;
+
+ // The pseudo stack where frames are |TRACE_EVENT| names.
+ std::vector<StackFrame> pseudo_stack_;
+
+ DISALLOW_COPY_AND_ASSIGN(AllocationContextTracker);
+};
+
+} // namespace trace_event
+} // namespace base
+
+#endif // BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_CONTEXT_TRACKER_H_
diff --git a/base/trace_event/heap_profiler_allocation_context_tracker_unittest.cc b/base/trace_event/heap_profiler_allocation_context_tracker_unittest.cc
new file mode 100644
index 0000000000..58255ad788
--- /dev/null
+++ b/base/trace_event/heap_profiler_allocation_context_tracker_unittest.cc
@@ -0,0 +1,225 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stddef.h>
+
+#include <iterator>
+
+#include "base/memory/ref_counted.h"
+#include "base/trace_event/heap_profiler_allocation_context.h"
+#include "base/trace_event/heap_profiler_allocation_context_tracker.h"
+#include "base/trace_event/trace_event.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+// Define all strings once, because the pseudo stack requires pointer equality,
+// and string interning is unreliable.
+const char kCupcake[] = "Cupcake";
+const char kDonut[] = "Donut";
+const char kEclair[] = "Eclair";
+const char kFroyo[] = "Froyo";
+const char kGingerbread[] = "Gingerbread";
+
+// Asserts that the fixed-size array |expected_backtrace| matches the backtrace
+// in |AllocationContextTracker::GetContextSnapshot|.
+template <size_t N>
+void AssertBacktraceEquals(const StackFrame(&expected_backtrace)[N]) {
+ AllocationContext ctx = AllocationContextTracker::GetContextSnapshot();
+
+ auto actual = std::begin(ctx.backtrace.frames);
+ auto actual_bottom = std::end(ctx.backtrace.frames);
+ auto expected = std::begin(expected_backtrace);
+ auto expected_bottom = std::end(expected_backtrace);
+
+ // Note that this requires the pointers to be equal, this is not doing a deep
+ // string comparison.
+ for (; actual != actual_bottom && expected != expected_bottom;
+ actual++, expected++)
+ ASSERT_EQ(*expected, *actual);
+
+ // Ensure that the height of the stacks is the same.
+ ASSERT_EQ(actual, actual_bottom);
+ ASSERT_EQ(expected, expected_bottom);
+}
+
+void AssertBacktraceEmpty() {
+ AllocationContext ctx = AllocationContextTracker::GetContextSnapshot();
+
+ for (StackFrame frame : ctx.backtrace.frames)
+ ASSERT_EQ(nullptr, frame);
+}
+
+class AllocationContextTrackerTest : public testing::Test {
+ public:
+ void SetUp() override {
+ TraceConfig config("");
+ TraceLog::GetInstance()->SetEnabled(config, TraceLog::RECORDING_MODE);
+ AllocationContextTracker::SetCaptureEnabled(true);
+ }
+
+ void TearDown() override {
+ AllocationContextTracker::SetCaptureEnabled(false);
+ TraceLog::GetInstance()->SetDisabled();
+ }
+};
+
+// Check that |TRACE_EVENT| macros push and pop to the pseudo stack correctly.
+// Also check that |GetContextSnapshot| fills the backtrace with null pointers
+// when the pseudo stack height is less than the capacity.
+TEST_F(AllocationContextTrackerTest, PseudoStackScopedTrace) {
+ StackFrame c = kCupcake;
+ StackFrame d = kDonut;
+ StackFrame e = kEclair;
+ StackFrame f = kFroyo;
+
+ AssertBacktraceEmpty();
+
+ {
+ TRACE_EVENT0("Testing", kCupcake);
+ StackFrame frame_c[] = {c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ AssertBacktraceEquals(frame_c);
+
+ {
+ TRACE_EVENT0("Testing", kDonut);
+ StackFrame frame_cd[] = {c, d, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ AssertBacktraceEquals(frame_cd);
+ }
+
+ AssertBacktraceEquals(frame_c);
+
+ {
+ TRACE_EVENT0("Testing", kEclair);
+ StackFrame frame_ce[] = {c, e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ AssertBacktraceEquals(frame_ce);
+ }
+
+ AssertBacktraceEquals(frame_c);
+ }
+
+ AssertBacktraceEmpty();
+
+ {
+ TRACE_EVENT0("Testing", kFroyo);
+ StackFrame frame_f[] = {f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ AssertBacktraceEquals(frame_f);
+ }
+
+ AssertBacktraceEmpty();
+}
+
+// Same as |PseudoStackScopedTrace|, but now test the |TRACE_EVENT_BEGIN| and
+// |TRACE_EVENT_END| macros.
+TEST_F(AllocationContextTrackerTest, PseudoStackBeginEndTrace) {
+ StackFrame c = kCupcake;
+ StackFrame d = kDonut;
+ StackFrame e = kEclair;
+ StackFrame f = kFroyo;
+
+ StackFrame frame_c[] = {c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ StackFrame frame_cd[] = {c, d, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ StackFrame frame_ce[] = {c, e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ StackFrame frame_f[] = {f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+ AssertBacktraceEmpty();
+
+ TRACE_EVENT_BEGIN0("Testing", kCupcake);
+ AssertBacktraceEquals(frame_c);
+
+ TRACE_EVENT_BEGIN0("Testing", kDonut);
+ AssertBacktraceEquals(frame_cd);
+ TRACE_EVENT_END0("Testing", kDonut);
+
+ AssertBacktraceEquals(frame_c);
+
+ TRACE_EVENT_BEGIN0("Testing", kEclair);
+ AssertBacktraceEquals(frame_ce);
+ TRACE_EVENT_END0("Testing", kEclair);
+
+ AssertBacktraceEquals(frame_c);
+ TRACE_EVENT_END0("Testing", kCupcake);
+
+ AssertBacktraceEmpty();
+
+ TRACE_EVENT_BEGIN0("Testing", kFroyo);
+ AssertBacktraceEquals(frame_f);
+ TRACE_EVENT_END0("Testing", kFroyo);
+
+ AssertBacktraceEmpty();
+}
+
+TEST_F(AllocationContextTrackerTest, PseudoStackMixedTrace) {
+ StackFrame c = kCupcake;
+ StackFrame d = kDonut;
+ StackFrame e = kEclair;
+ StackFrame f = kFroyo;
+
+ StackFrame frame_c[] = {c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ StackFrame frame_cd[] = {c, d, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ StackFrame frame_e[] = {e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ StackFrame frame_ef[] = {e, f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+ AssertBacktraceEmpty();
+
+ TRACE_EVENT_BEGIN0("Testing", kCupcake);
+ AssertBacktraceEquals(frame_c);
+
+ {
+ TRACE_EVENT0("Testing", kDonut);
+ AssertBacktraceEquals(frame_cd);
+ }
+
+ AssertBacktraceEquals(frame_c);
+ TRACE_EVENT_END0("Testing", kCupcake);
+ AssertBacktraceEmpty();
+
+ {
+ TRACE_EVENT0("Testing", kEclair);
+ AssertBacktraceEquals(frame_e);
+
+ TRACE_EVENT_BEGIN0("Testing", kFroyo);
+ AssertBacktraceEquals(frame_ef);
+ TRACE_EVENT_END0("Testing", kFroyo);
+ AssertBacktraceEquals(frame_e);
+ }
+
+ AssertBacktraceEmpty();
+}
+
+TEST_F(AllocationContextTrackerTest, BacktraceTakesTop) {
+ // Push 12 events onto the pseudo stack.
+ TRACE_EVENT0("Testing", kCupcake);
+ TRACE_EVENT0("Testing", kCupcake);
+ TRACE_EVENT0("Testing", kCupcake);
+ TRACE_EVENT0("Testing", kCupcake);
+
+ TRACE_EVENT0("Testing", kCupcake);
+ TRACE_EVENT0("Testing", kCupcake);
+ TRACE_EVENT0("Testing", kCupcake);
+ TRACE_EVENT0("Testing", kCupcake);
+
+ TRACE_EVENT0("Testing", kCupcake);
+ TRACE_EVENT0("Testing", kDonut);
+ TRACE_EVENT0("Testing", kEclair);
+ TRACE_EVENT0("Testing", kFroyo);
+
+ {
+ TRACE_EVENT0("Testing", kGingerbread);
+ AllocationContext ctx = AllocationContextTracker::GetContextSnapshot();
+
+ // The pseudo stack relies on pointer equality, not deep string comparisons.
+ ASSERT_EQ(kCupcake, ctx.backtrace.frames[0]);
+ ASSERT_EQ(kFroyo, ctx.backtrace.frames[11]);
+ }
+
+ {
+ AllocationContext ctx = AllocationContextTracker::GetContextSnapshot();
+ ASSERT_EQ(kCupcake, ctx.backtrace.frames[0]);
+ ASSERT_EQ(kFroyo, ctx.backtrace.frames[11]);
+ }
+}
+
+} // namespace trace_event
+} // namespace base
diff --git a/base/trace_event/heap_profiler_stack_frame_deduplicator.cc b/base/trace_event/heap_profiler_stack_frame_deduplicator.cc
new file mode 100644
index 0000000000..cf3d198797
--- /dev/null
+++ b/base/trace_event/heap_profiler_stack_frame_deduplicator.cc
@@ -0,0 +1,115 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/heap_profiler_stack_frame_deduplicator.h"
+
+#include <stddef.h>
+
+#include <string>
+#include <utility>
+
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/trace_event_memory_overhead.h"
+
+namespace base {
+namespace trace_event {
+
+StackFrameDeduplicator::FrameNode::FrameNode(StackFrame frame,
+ int parent_frame_index)
+ : frame(frame), parent_frame_index(parent_frame_index) {}
+StackFrameDeduplicator::FrameNode::~FrameNode() {}
+
+StackFrameDeduplicator::StackFrameDeduplicator() {}
+StackFrameDeduplicator::~StackFrameDeduplicator() {}
+
+int StackFrameDeduplicator::Insert(const StackFrame* beginFrame,
+ const StackFrame* endFrame) {
+ int frame_index = -1;
+ std::map<StackFrame, int>* nodes = &roots_;
+
+ // Loop through the frames, early out when a frame is null.
+ for (const StackFrame* it = beginFrame; it != endFrame && *it; it++) {
+ StackFrame frame = *it;
+
+ auto node = nodes->find(frame);
+ if (node == nodes->end()) {
+ // There is no tree node for this frame yet, create it. The parent node
+ // is the node associated with the previous frame.
+ FrameNode frame_node(frame, frame_index);
+
+ // The new frame node will be appended, so its index is the current size
+ // of the vector.
+ frame_index = static_cast<int>(frames_.size());
+
+ // Add the node to the trie so it will be found next time.
+ nodes->insert(std::make_pair(frame, frame_index));
+
+ // Append the node after modifying |nodes|, because the |frames_| vector
+ // might need to resize, and this invalidates the |nodes| pointer.
+ frames_.push_back(frame_node);
+ } else {
+ // A tree node for this frame exists. Look for the next one.
+ frame_index = node->second;
+ }
+
+ nodes = &frames_[frame_index].children;
+ }
+
+ return frame_index;
+}
+
+void StackFrameDeduplicator::AppendAsTraceFormat(std::string* out) const {
+ out->append("{"); // Begin the |stackFrames| dictionary.
+
+ int i = 0;
+ auto frame_node = begin();
+ auto it_end = end();
+ std::string stringify_buffer;
+
+ while (frame_node != it_end) {
+ // The |stackFrames| format is a dictionary, not an array, so the
+ // keys are stringified indices. Write the index manually, then use
+ // |TracedValue| to format the object. This is to avoid building the
+ // entire dictionary as a |TracedValue| in memory.
+ SStringPrintf(&stringify_buffer, "\"%d\":", i);
+ out->append(stringify_buffer);
+
+ scoped_refptr<TracedValue> frame_node_value = new TracedValue;
+ frame_node_value->SetString("name", frame_node->frame);
+ if (frame_node->parent_frame_index >= 0) {
+ SStringPrintf(&stringify_buffer, "%d", frame_node->parent_frame_index);
+ frame_node_value->SetString("parent", stringify_buffer);
+ }
+ frame_node_value->AppendAsTraceFormat(out);
+
+ i++;
+ frame_node++;
+
+ if (frame_node != it_end)
+ out->append(",");
+ }
+
+ out->append("}"); // End the |stackFrames| dictionary.
+}
+
+void StackFrameDeduplicator::EstimateTraceMemoryOverhead(
+ TraceEventMemoryOverhead* overhead) {
+ // The sizes here are only estimates; they fail to take into account the
+ // overhead of the tree nodes for the map, but as an estimate this should be
+ // fine.
+ size_t maps_size = roots_.size() * sizeof(std::pair<StackFrame, int>);
+ size_t frames_allocated = frames_.capacity() * sizeof(FrameNode);
+ size_t frames_resident = frames_.size() * sizeof(FrameNode);
+
+ for (const FrameNode& node : frames_)
+ maps_size += node.children.size() * sizeof(std::pair<StackFrame, int>);
+
+ overhead->Add("StackFrameDeduplicator",
+ sizeof(StackFrameDeduplicator) + maps_size + frames_allocated,
+ sizeof(StackFrameDeduplicator) + maps_size + frames_resident);
+}
+
+} // namespace trace_event
+} // namespace base
diff --git a/base/trace_event/heap_profiler_stack_frame_deduplicator.h b/base/trace_event/heap_profiler_stack_frame_deduplicator.h
new file mode 100644
index 0000000000..60df1ba8b4
--- /dev/null
+++ b/base/trace_event/heap_profiler_stack_frame_deduplicator.h
@@ -0,0 +1,79 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_HEAP_PROFILER_STACK_FRAME_DEDUPLICATOR_H_
+#define BASE_TRACE_EVENT_HEAP_PROFILER_STACK_FRAME_DEDUPLICATOR_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/macros.h"
+#include "base/trace_event/heap_profiler_allocation_context.h"
+#include "base/trace_event/trace_event_impl.h"
+
+namespace base {
+namespace trace_event {
+
+class TraceEventMemoryOverhead;
+
+// A data structure that allows grouping a set of backtraces in a space-
+// efficient manner by creating a call tree and writing it as a set of (node,
+// parent) pairs. The tree nodes reference both parent and children. The parent
+// is referenced by index into |frames_|. The children are referenced via a map
+// of |StackFrame|s to index into |frames_|. So there is a trie for bottum-up
+// lookup of a backtrace for deduplication, and a tree for compact storage in
+// the trace log.
+class BASE_EXPORT StackFrameDeduplicator : public ConvertableToTraceFormat {
+ public:
+ // A node in the call tree.
+ struct FrameNode {
+ FrameNode(StackFrame frame, int parent_frame_index);
+ ~FrameNode();
+
+ StackFrame frame;
+
+ // The index of the parent stack frame in |frames_|, or -1 if there is no
+ // parent frame (when it is at the bottom of the call stack).
+ int parent_frame_index;
+
+ // Indices into |frames_| of frames called from the current frame.
+ std::map<StackFrame, int> children;
+ };
+
+ using ConstIterator = std::vector<FrameNode>::const_iterator;
+
+ StackFrameDeduplicator();
+
+ // Inserts a backtrace where |beginFrame| is a pointer to the bottom frame
+ // (e.g. main) and |endFrame| is a pointer past the top frame (most recently
+ // called function), and returns the index of its leaf node in |frames_|.
+ // Returns -1 if the backtrace is empty.
+ int Insert(const StackFrame* beginFrame, const StackFrame* endFrame);
+
+ // Iterators over the frame nodes in the call tree.
+ ConstIterator begin() const { return frames_.begin(); }
+ ConstIterator end() const { return frames_.end(); }
+
+ // Writes the |stackFrames| dictionary as defined in https://goo.gl/GerkV8 to
+ // the trace log.
+ void AppendAsTraceFormat(std::string* out) const override;
+
+ // Estimates memory overhead including |sizeof(StackFrameDeduplicator)|.
+ void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead) override;
+
+ private:
+ ~StackFrameDeduplicator() override;
+
+ std::map<StackFrame, int> roots_;
+ std::vector<FrameNode> frames_;
+
+ DISALLOW_COPY_AND_ASSIGN(StackFrameDeduplicator);
+};
+
+} // namespace trace_event
+} // namespace base
+
+#endif // BASE_TRACE_EVENT_HEAP_PROFILER_STACK_FRAME_DEDUPLICATOR_H_
diff --git a/base/trace_event/heap_profiler_stack_frame_deduplicator_unittest.cc b/base/trace_event/heap_profiler_stack_frame_deduplicator_unittest.cc
new file mode 100644
index 0000000000..433c633ca5
--- /dev/null
+++ b/base/trace_event/heap_profiler_stack_frame_deduplicator_unittest.cc
@@ -0,0 +1,134 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <iterator>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/trace_event/heap_profiler_allocation_context.h"
+#include "base/trace_event/heap_profiler_stack_frame_deduplicator.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+// Define all strings once, because the deduplicator requires pointer equality,
+// and string interning is unreliable.
+const char kBrowserMain[] = "BrowserMain";
+const char kRendererMain[] = "RendererMain";
+const char kCreateWidget[] = "CreateWidget";
+const char kInitialize[] = "Initialize";
+const char kMalloc[] = "malloc";
+
+TEST(StackFrameDeduplicatorTest, SingleBacktrace) {
+ StackFrame bt[] = {kBrowserMain, kCreateWidget, kMalloc};
+
+ // The call tree should look like this (index in brackets).
+ //
+ // BrowserMain [0]
+ // CreateWidget [1]
+ // malloc [2]
+
+ scoped_refptr<StackFrameDeduplicator> dedup = new StackFrameDeduplicator;
+ ASSERT_EQ(2, dedup->Insert(std::begin(bt), std::end(bt)));
+
+ auto iter = dedup->begin();
+ ASSERT_EQ(kBrowserMain, (iter + 0)->frame);
+ ASSERT_EQ(-1, (iter + 0)->parent_frame_index);
+
+ ASSERT_EQ(kCreateWidget, (iter + 1)->frame);
+ ASSERT_EQ(0, (iter + 1)->parent_frame_index);
+
+ ASSERT_EQ(kMalloc, (iter + 2)->frame);
+ ASSERT_EQ(1, (iter + 2)->parent_frame_index);
+
+ ASSERT_EQ(iter + 3, dedup->end());
+}
+
+// Test that there can be different call trees (there can be multiple bottom
+// frames). Also verify that frames with the same name but a different caller
+// are represented as distinct nodes.
+TEST(StackFrameDeduplicatorTest, MultipleRoots) {
+ StackFrame bt0[] = {kBrowserMain, kCreateWidget};
+ StackFrame bt1[] = {kRendererMain, kCreateWidget};
+
+ // The call tree should look like this (index in brackets).
+ //
+ // BrowserMain [0]
+ // CreateWidget [1]
+ // RendererMain [2]
+ // CreateWidget [3]
+ //
+ // Note that there will be two instances of CreateWidget,
+ // with different parents.
+
+ scoped_refptr<StackFrameDeduplicator> dedup = new StackFrameDeduplicator;
+ ASSERT_EQ(1, dedup->Insert(std::begin(bt0), std::end(bt0)));
+ ASSERT_EQ(3, dedup->Insert(std::begin(bt1), std::end(bt1)));
+
+ auto iter = dedup->begin();
+ ASSERT_EQ(kBrowserMain, (iter + 0)->frame);
+ ASSERT_EQ(-1, (iter + 0)->parent_frame_index);
+
+ ASSERT_EQ(kCreateWidget, (iter + 1)->frame);
+ ASSERT_EQ(0, (iter + 1)->parent_frame_index);
+
+ ASSERT_EQ(kRendererMain, (iter + 2)->frame);
+ ASSERT_EQ(-1, (iter + 2)->parent_frame_index);
+
+ ASSERT_EQ(kCreateWidget, (iter + 3)->frame);
+ ASSERT_EQ(2, (iter + 3)->parent_frame_index);
+
+ ASSERT_EQ(iter + 4, dedup->end());
+}
+
+TEST(StackFrameDeduplicatorTest, Deduplication) {
+ StackFrame bt0[] = {kBrowserMain, kCreateWidget};
+ StackFrame bt1[] = {kBrowserMain, kInitialize};
+
+ // The call tree should look like this (index in brackets).
+ //
+ // BrowserMain [0]
+ // CreateWidget [1]
+ // Initialize [2]
+ //
+ // Note that BrowserMain will be re-used.
+
+ scoped_refptr<StackFrameDeduplicator> dedup = new StackFrameDeduplicator;
+ ASSERT_EQ(1, dedup->Insert(std::begin(bt0), std::end(bt0)));
+ ASSERT_EQ(2, dedup->Insert(std::begin(bt1), std::end(bt1)));
+
+ auto iter = dedup->begin();
+ ASSERT_EQ(kBrowserMain, (iter + 0)->frame);
+ ASSERT_EQ(-1, (iter + 0)->parent_frame_index);
+
+ ASSERT_EQ(kCreateWidget, (iter + 1)->frame);
+ ASSERT_EQ(0, (iter + 1)->parent_frame_index);
+
+ ASSERT_EQ(kInitialize, (iter + 2)->frame);
+ ASSERT_EQ(0, (iter + 2)->parent_frame_index);
+
+ ASSERT_EQ(iter + 3, dedup->end());
+
+ // Inserting the same backtrace again should return the index of the existing
+ // node.
+ ASSERT_EQ(1, dedup->Insert(std::begin(bt0), std::end(bt0)));
+ ASSERT_EQ(2, dedup->Insert(std::begin(bt1), std::end(bt1)));
+ ASSERT_EQ(dedup->begin() + 3, dedup->end());
+}
+
+TEST(StackFrameDeduplicatorTest, NullPaddingIsRemoved) {
+ StackFrame bt0[] = {kBrowserMain, nullptr, nullptr, nullptr};
+
+ scoped_refptr<StackFrameDeduplicator> dedup = new StackFrameDeduplicator;
+
+ // There are four frames in the backtrace, but the null pointers should be
+ // skipped, so only one frame is inserted, which will have index 0.
+ ASSERT_EQ(4u, arraysize(bt0));
+ ASSERT_EQ(0, dedup->Insert(std::begin(bt0), std::end(bt0)));
+ ASSERT_EQ(dedup->begin() + 1, dedup->end());
+}
+
+} // namespace trace_event
+} // namespace base
diff --git a/base/trace_event/heap_profiler_type_name_deduplicator.cc b/base/trace_event/heap_profiler_type_name_deduplicator.cc
new file mode 100644
index 0000000000..e7f57c8ae0
--- /dev/null
+++ b/base/trace_event/heap_profiler_type_name_deduplicator.cc
@@ -0,0 +1,76 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/heap_profiler_type_name_deduplicator.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string>
+#include <utility>
+
+#include "base/json/string_escape.h"
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event_memory_overhead.h"
+
+namespace base {
+namespace trace_event {
+
+TypeNameDeduplicator::TypeNameDeduplicator() {
+ // A null pointer has type ID 0 ("unknown type");
+ type_ids_.insert(std::make_pair(nullptr, 0));
+}
+
+TypeNameDeduplicator::~TypeNameDeduplicator() {}
+
+int TypeNameDeduplicator::Insert(const char* type_name) {
+ auto result = type_ids_.insert(std::make_pair(type_name, 0));
+ auto& elem = result.first;
+ bool did_not_exist_before = result.second;
+
+ if (did_not_exist_before) {
+ // The type IDs are assigned sequentially and they are zero-based, so
+ // |size() - 1| is the ID of the new element.
+ elem->second = static_cast<int>(type_ids_.size() - 1);
+ }
+
+ return elem->second;
+}
+
+void TypeNameDeduplicator::AppendAsTraceFormat(std::string* out) const {
+ out->append("{"); // Begin the type names dictionary.
+
+ auto it = type_ids_.begin();
+ std::string buffer;
+
+ // Write the first entry manually; the null pointer must not be dereferenced.
+ // (The first entry is the null pointer because a |std::map| is ordered.)
+ it++;
+ out->append("\"0\":\"[unknown]\"");
+
+ for (; it != type_ids_.end(); it++) {
+ // Type IDs in the trace are strings, write them as stringified keys of
+ // a dictionary.
+ SStringPrintf(&buffer, ",\"%d\":", it->second);
+
+ // |EscapeJSONString| appends, it does not overwrite |buffer|.
+ bool put_in_quotes = true;
+ EscapeJSONString(it->first, put_in_quotes, &buffer);
+ out->append(buffer);
+ }
+
+ out->append("}"); // End the type names dictionary.
+}
+
+void TypeNameDeduplicator::EstimateTraceMemoryOverhead(
+ TraceEventMemoryOverhead* overhead) {
+ // The size here is only an estimate; it fails to take into account the size
+ // of the tree nodes for the map, but as an estimate this should be fine.
+ size_t map_size = type_ids_.size() * sizeof(std::pair<const char*, int>);
+
+ overhead->Add("TypeNameDeduplicator",
+ sizeof(TypeNameDeduplicator) + map_size);
+}
+
+} // namespace trace_event
+} // namespace base
diff --git a/base/trace_event/heap_profiler_type_name_deduplicator.h b/base/trace_event/heap_profiler_type_name_deduplicator.h
new file mode 100644
index 0000000000..317ea5ee1e
--- /dev/null
+++ b/base/trace_event/heap_profiler_type_name_deduplicator.h
@@ -0,0 +1,46 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_HEAP_PROFILER_TYPE_NAME_DEDUPLICATOR_H_
+#define BASE_TRACE_EVENT_HEAP_PROFILER_TYPE_NAME_DEDUPLICATOR_H_
+
+#include <map>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/macros.h"
+#include "base/trace_event/trace_event_impl.h"
+
+namespace base {
+namespace trace_event {
+
+class TraceEventMemoryOverhead;
+
+// Data structure that assigns a unique numeric ID to |const char*|s.
+class BASE_EXPORT TypeNameDeduplicator : public ConvertableToTraceFormat {
+ public:
+ TypeNameDeduplicator();
+
+ // Inserts a type name and returns its ID.
+ int Insert(const char* type_name);
+
+ // Estimates memory overhead including |sizeof(TypeNameDeduplicator)|.
+ void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead) override;
+
+ private:
+ ~TypeNameDeduplicator() override;
+
+ // Writes the type ID -> type name mapping to the trace log.
+ void AppendAsTraceFormat(std::string* out) const override;
+
+ // Map from type name to type ID.
+ std::map<const char*, int> type_ids_;
+
+ DISALLOW_COPY_AND_ASSIGN(TypeNameDeduplicator);
+};
+
+} // namespace trace_event
+} // namespace base
+
+#endif // BASE_TRACE_EVENT_HEAP_PROFILER_TYPE_NAME_DEDUPLICATOR_H_
diff --git a/base/trace_event/heap_profiler_type_name_deduplicator_unittest.cc b/base/trace_event/heap_profiler_type_name_deduplicator_unittest.cc
new file mode 100644
index 0000000000..82c8fb505e
--- /dev/null
+++ b/base/trace_event/heap_profiler_type_name_deduplicator_unittest.cc
@@ -0,0 +1,71 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+
+#include "base/json/json_reader.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/trace_event/heap_profiler_type_name_deduplicator.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+// Define all strings once, because the deduplicator requires pointer equality,
+// and string interning is unreliable.
+const char kInt[] = "int";
+const char kBool[] = "bool";
+const char kString[] = "string";
+const char kNeedsEscape[] = "\"quotes\"";
+
+scoped_ptr<Value> DumpAndReadBack(const ConvertableToTraceFormat& convertable) {
+ std::string json;
+ convertable.AppendAsTraceFormat(&json);
+ return JSONReader::Read(json);
+}
+
+TEST(TypeNameDeduplicatorTest, Deduplication) {
+ // The type IDs should be like this:
+ // 0: [unknown]
+ // 1: int
+ // 2: bool
+ // 3: string
+
+ scoped_refptr<TypeNameDeduplicator> dedup = new TypeNameDeduplicator;
+ ASSERT_EQ(1, dedup->Insert(kInt));
+ ASSERT_EQ(2, dedup->Insert(kBool));
+ ASSERT_EQ(3, dedup->Insert(kString));
+
+ // Inserting again should return the same IDs.
+ ASSERT_EQ(2, dedup->Insert(kBool));
+ ASSERT_EQ(1, dedup->Insert(kInt));
+ ASSERT_EQ(3, dedup->Insert(kString));
+
+ // A null pointer should yield type ID 0.
+ ASSERT_EQ(0, dedup->Insert(nullptr));
+}
+
+TEST(TypeNameDeduplicatorTest, EscapeTypeName) {
+ scoped_refptr<TypeNameDeduplicator> dedup = new TypeNameDeduplicator;
+ ASSERT_EQ(1, dedup->Insert(kNeedsEscape));
+
+ // Reading json should not fail, because the type name should have been
+ // escaped properly.
+ scoped_ptr<Value> type_names = DumpAndReadBack(*dedup);
+ ASSERT_NE(nullptr, type_names);
+
+ const DictionaryValue* dictionary;
+ ASSERT_TRUE(type_names->GetAsDictionary(&dictionary));
+
+ // When the type name was inserted, it got ID 1. The exported key "1"
+ // should contain the name, with quotes.
+ std::string type_name;
+ ASSERT_TRUE(dictionary->GetString("1", &type_name));
+ ASSERT_EQ("\"quotes\"", type_name);
+}
+
+} // namespace trace_event
+} // namespace base
diff --git a/base/trace_event/malloc_dump_provider.cc b/base/trace_event/malloc_dump_provider.cc
index 92d513f99d..064752bc5b 100644
--- a/base/trace_event/malloc_dump_provider.cc
+++ b/base/trace_event/malloc_dump_provider.cc
@@ -4,9 +4,17 @@
#include "base/trace_event/malloc_dump_provider.h"
-#include <malloc.h>
+#include <stddef.h>
+#include "base/allocator/allocator_extension.h"
#include "base/trace_event/process_memory_dump.h"
+#include "build/build_config.h"
+
+#if defined(OS_MACOSX)
+#include <malloc/malloc.h>
+#else
+#include <malloc.h>
+#endif
namespace base {
namespace trace_event {
@@ -20,32 +28,73 @@ MallocDumpProvider* MallocDumpProvider::GetInstance() {
LeakySingletonTraits<MallocDumpProvider>>::get();
}
-MallocDumpProvider::MallocDumpProvider() {
-}
+MallocDumpProvider::MallocDumpProvider() {}
-MallocDumpProvider::~MallocDumpProvider() {
-}
+MallocDumpProvider::~MallocDumpProvider() {}
// Called at trace dump point time. Creates a snapshot the memory counters for
// the current process.
-bool MallocDumpProvider::OnMemoryDump(ProcessMemoryDump* pmd) {
+bool MallocDumpProvider::OnMemoryDump(const MemoryDumpArgs& /* args */,
+ ProcessMemoryDump* pmd) {
+ size_t total_virtual_size = 0;
+ size_t resident_size = 0;
+ size_t allocated_objects_size = 0;
+#if defined(USE_TCMALLOC)
+ bool res =
+ allocator::GetNumericProperty("generic.heap_size", &total_virtual_size);
+ DCHECK(res);
+ res = allocator::GetNumericProperty("generic.total_physical_bytes",
+ &resident_size);
+ DCHECK(res);
+ res = allocator::GetNumericProperty("generic.current_allocated_bytes",
+ &allocated_objects_size);
+ DCHECK(res);
+#elif defined(OS_MACOSX) || defined(OS_IOS)
+ malloc_statistics_t stats = {0};
+ malloc_zone_statistics(nullptr, &stats);
+ total_virtual_size = stats.size_allocated;
+ allocated_objects_size = stats.size_in_use;
+
+ // The resident size is approximated to the max size in use, which would count
+ // the total size of all regions other than the free bytes at the end of each
+ // region. In each allocation region the allocations are rounded off to a
+ // fixed quantum, so the excess region will not be resident.
+ // See crrev.com/1531463004 for detailed explanation.
+ resident_size = stats.max_size_in_use;
+#else
struct mallinfo info = mallinfo();
DCHECK_GE(info.arena + info.hblkhd, info.uordblks);
- // When the system allocator is implemented by tcmalloc, the total physical
- // size is given by |arena| and |hblkhd| is 0. In case of Android's jemalloc
- // |arena| is 0 and the outer pages size is reported by |hblkhd|. In case of
- // dlmalloc the total is given by |arena| + |hblkhd|.
- // For more details see link: http://goo.gl/fMR8lF.
+ // In case of Android's jemalloc |arena| is 0 and the outer pages size is
+ // reported by |hblkhd|. In case of dlmalloc the total is given by
+ // |arena| + |hblkhd|. For more details see link: http://goo.gl/fMR8lF.
+ total_virtual_size = info.arena + info.hblkhd;
+ resident_size = info.uordblks;
+ allocated_objects_size = info.uordblks;
+#endif
+
MemoryAllocatorDump* outer_dump = pmd->CreateAllocatorDump("malloc");
+ outer_dump->AddScalar("virtual_size", MemoryAllocatorDump::kUnitsBytes,
+ total_virtual_size);
outer_dump->AddScalar(MemoryAllocatorDump::kNameSize,
- MemoryAllocatorDump::kUnitsBytes,
- info.arena + info.hblkhd);
+ MemoryAllocatorDump::kUnitsBytes, resident_size);
// Total allocated space is given by |uordblks|.
MemoryAllocatorDump* inner_dump = pmd->CreateAllocatorDump(kAllocatedObjects);
inner_dump->AddScalar(MemoryAllocatorDump::kNameSize,
- MemoryAllocatorDump::kUnitsBytes, info.uordblks);
+ MemoryAllocatorDump::kUnitsBytes,
+ allocated_objects_size);
+
+ if (resident_size - allocated_objects_size > 0) {
+ // Explicitly specify why is extra memory resident. In tcmalloc it accounts
+ // for free lists and caches. In mac and ios it accounts for the
+ // fragmentation and metadata.
+ MemoryAllocatorDump* other_dump =
+ pmd->CreateAllocatorDump("malloc/metadata_fragmentation_caches");
+ other_dump->AddScalar(MemoryAllocatorDump::kNameSize,
+ MemoryAllocatorDump::kUnitsBytes,
+ resident_size - allocated_objects_size);
+ }
return true;
}
diff --git a/base/trace_event/malloc_dump_provider.h b/base/trace_event/malloc_dump_provider.h
index 0a51ff75da..63fc1b0826 100644
--- a/base/trace_event/malloc_dump_provider.h
+++ b/base/trace_event/malloc_dump_provider.h
@@ -7,8 +7,15 @@
#include <istream>
+#include "base/macros.h"
#include "base/memory/singleton.h"
#include "base/trace_event/memory_dump_provider.h"
+#include "build/build_config.h"
+
+#if defined(OS_LINUX) || defined(OS_ANDROID) || \
+ (defined(OS_MACOSX) && !defined(OS_IOS))
+#define MALLOC_MEMORY_TRACING_SUPPORTED
+#endif
namespace base {
namespace trace_event {
@@ -23,7 +30,8 @@ class BASE_EXPORT MallocDumpProvider : public MemoryDumpProvider {
static MallocDumpProvider* GetInstance();
// MemoryDumpProvider implementation.
- bool OnMemoryDump(ProcessMemoryDump* pmd) override;
+ bool OnMemoryDump(const MemoryDumpArgs& args,
+ ProcessMemoryDump* pmd) override;
private:
friend struct DefaultSingletonTraits<MallocDumpProvider>;
diff --git a/base/trace_event/memory_allocator_dump.cc b/base/trace_event/memory_allocator_dump.cc
index 4037f946c9..5c5af7ee45 100644
--- a/base/trace_event/memory_allocator_dump.cc
+++ b/base/trace_event/memory_allocator_dump.cc
@@ -16,7 +16,7 @@ namespace base {
namespace trace_event {
const char MemoryAllocatorDump::kNameSize[] = "size";
-const char MemoryAllocatorDump::kNameObjectsCount[] = "objects_count";
+const char MemoryAllocatorDump::kNameObjectCount[] = "object_count";
const char MemoryAllocatorDump::kTypeScalar[] = "scalar";
const char MemoryAllocatorDump::kTypeString[] = "string";
const char MemoryAllocatorDump::kUnitsBytes[] = "bytes";
@@ -35,10 +35,6 @@ MemoryAllocatorDump::MemoryAllocatorDump(const std::string& absolute_name,
// The |absolute_name| can contain slash separator, but not leading or
// trailing ones.
DCHECK(absolute_name[0] != '/' && *absolute_name.rbegin() != '/');
-
- // Dots are not allowed anywhere as the underlying base::DictionaryValue
- // would treat them magically and split in sub-nodes, which is not intended.
- DCHECK_EQ(std::string::npos, absolute_name.find_first_of('.'));
}
// If the caller didn't provide a guid, make one up by hashing the
@@ -61,7 +57,7 @@ MemoryAllocatorDump::~MemoryAllocatorDump() {
void MemoryAllocatorDump::AddScalar(const char* name,
const char* units,
- uint64 value) {
+ uint64_t value) {
SStringPrintf(&string_conversion_buffer_, "%" PRIx64, value);
attributes_->BeginDictionary(name);
attributes_->SetString("type", kTypeScalar);
diff --git a/base/trace_event/memory_allocator_dump.h b/base/trace_event/memory_allocator_dump.h
index c5297a5ca5..6c514fa6a6 100644
--- a/base/trace_event/memory_allocator_dump.h
+++ b/base/trace_event/memory_allocator_dump.h
@@ -5,11 +5,13 @@
#ifndef BASE_TRACE_EVENT_MEMORY_ALLOCATOR_DUMP_H_
#define BASE_TRACE_EVENT_MEMORY_ALLOCATOR_DUMP_H_
+#include <stdint.h>
+
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/trace_event/memory_allocator_dump_guid.h"
#include "base/values.h"
@@ -32,25 +34,32 @@ class BASE_EXPORT MemoryAllocatorDump {
ProcessMemoryDump* process_memory_dump);
~MemoryAllocatorDump();
- // Standard attribute name to model allocated space.
- static const char kNameSize[];
-
- // Standard attribute name to model the number of objects allocated.
- static const char kNameObjectsCount[];
+ // Standard attribute |name|s for the AddScalar and AddString() methods.
+ static const char kNameSize[]; // To represent allocated space.
+ static const char kNameObjectCount[]; // To represent number of objects.
- static const char kTypeScalar[]; // Type name for scalar attributes.
- static const char kTypeString[]; // Type name for string attributes.
+ // Standard attribute |unit|s for the AddScalar and AddString() methods.
static const char kUnitsBytes[]; // Unit name to represent bytes.
static const char kUnitsObjects[]; // Unit name to represent #objects.
- // Absolute name, unique within the scope of an entire ProcessMemoryDump.
- const std::string& absolute_name() const { return absolute_name_; }
-
- // Helper setter for scalar attributes.
- void AddScalar(const char* name, const char* units, uint64 value);
+ // Constants used only internally and by tests.
+ static const char kTypeScalar[]; // Type name for scalar attributes.
+ static const char kTypeString[]; // Type name for string attributes.
+
+ // Setters for scalar attributes. Some examples:
+ // - "size" column (all dumps are expected to have at least this one):
+ // AddScalar(kNameSize, kUnitsBytes, 1234);
+ // - Some extra-column reporting internal details of the subsystem:
+ // AddScalar("number_of_freelist_entires", kUnitsObjects, 42)
+ // - Other informational column (will not be auto-added in the UI)
+ // AddScalarF("kittens_ratio", "ratio", 42.0f)
+ void AddScalar(const char* name, const char* units, uint64_t value);
void AddScalarF(const char* name, const char* units, double value);
void AddString(const char* name, const char* units, const std::string& value);
+ // Absolute name, unique within the scope of an entire ProcessMemoryDump.
+ const std::string& absolute_name() const { return absolute_name_; }
+
// Called at trace generation time to populate the TracedValue.
void AsValueInto(TracedValue* value) const;
diff --git a/base/trace_event/memory_allocator_dump_guid.cc b/base/trace_event/memory_allocator_dump_guid.cc
index a4ea50d416..bf4389a4c7 100644
--- a/base/trace_event/memory_allocator_dump_guid.cc
+++ b/base/trace_event/memory_allocator_dump_guid.cc
@@ -5,21 +5,29 @@
#include "base/trace_event/memory_allocator_dump_guid.h"
#include "base/format_macros.h"
-#include "base/hash.h"
+#include "base/sha1.h"
#include "base/strings/stringprintf.h"
namespace base {
namespace trace_event {
-MemoryAllocatorDumpGuid::MemoryAllocatorDumpGuid(uint64 guid) : guid_(guid) {
+namespace {
+uint64_t HashString(const std::string& str) {
+ uint64_t hash[(kSHA1Length + sizeof(uint64_t) - 1) / sizeof(uint64_t)] = {0};
+ SHA1HashBytes(reinterpret_cast<const unsigned char*>(str.data()), str.size(),
+ reinterpret_cast<unsigned char*>(hash));
+ return hash[0];
}
+} // namespace
+
+MemoryAllocatorDumpGuid::MemoryAllocatorDumpGuid(uint64_t guid) : guid_(guid) {}
MemoryAllocatorDumpGuid::MemoryAllocatorDumpGuid()
: MemoryAllocatorDumpGuid(0u) {
}
MemoryAllocatorDumpGuid::MemoryAllocatorDumpGuid(const std::string& guid_str)
- : MemoryAllocatorDumpGuid(Hash(guid_str)) {
+ : MemoryAllocatorDumpGuid(HashString(guid_str)) {
}
std::string MemoryAllocatorDumpGuid::ToString() const {
diff --git a/base/trace_event/memory_allocator_dump_guid.h b/base/trace_event/memory_allocator_dump_guid.h
index 84c12ef037..b6472c6612 100644
--- a/base/trace_event/memory_allocator_dump_guid.h
+++ b/base/trace_event/memory_allocator_dump_guid.h
@@ -5,10 +5,11 @@
#ifndef BASE_TRACE_EVENT_MEMORY_ALLOCATOR_DUMP_GUID_H_
#define BASE_TRACE_EVENT_MEMORY_ALLOCATOR_DUMP_GUID_H_
+#include <stdint.h>
+
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
namespace base {
namespace trace_event {
@@ -16,13 +17,15 @@ namespace trace_event {
class BASE_EXPORT MemoryAllocatorDumpGuid {
public:
MemoryAllocatorDumpGuid();
- explicit MemoryAllocatorDumpGuid(uint64 guid);
+ explicit MemoryAllocatorDumpGuid(uint64_t guid);
// Utility ctor to hash a GUID if the caller prefers a string. The caller
// still has to ensure that |guid_str| is unique, per snapshot, within the
// global scope of all the traced processes.
explicit MemoryAllocatorDumpGuid(const std::string& guid_str);
+ uint64_t ToUint64() const { return guid_; }
+
// Returns a (hex-encoded) string representation of the guid.
std::string ToString() const;
@@ -37,7 +40,7 @@ class BASE_EXPORT MemoryAllocatorDumpGuid {
}
private:
- uint64 guid_;
+ uint64_t guid_;
// Deliberately copy-able.
};
diff --git a/base/trace_event/memory_allocator_dump_unittest.cc b/base/trace_event/memory_allocator_dump_unittest.cc
index 85b98d6551..d1cfe91a4f 100644
--- a/base/trace_event/memory_allocator_dump_unittest.cc
+++ b/base/trace_event/memory_allocator_dump_unittest.cc
@@ -4,6 +4,8 @@
#include "base/trace_event/memory_allocator_dump.h"
+#include <stdint.h>
+
#include "base/format_macros.h"
#include "base/strings/stringprintf.h"
#include "base/trace_event/memory_allocator_dump_guid.h"
@@ -12,6 +14,7 @@
#include "base/trace_event/process_memory_dump.h"
#include "base/trace_event/trace_event_argument.h"
#include "base/values.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
@@ -21,13 +24,14 @@ namespace {
class FakeMemoryAllocatorDumpProvider : public MemoryDumpProvider {
public:
- bool OnMemoryDump(ProcessMemoryDump* pmd) override {
+ bool OnMemoryDump(const MemoryDumpArgs& args,
+ ProcessMemoryDump* pmd) override {
MemoryAllocatorDump* root_heap =
pmd->CreateAllocatorDump("foobar_allocator");
root_heap->AddScalar(MemoryAllocatorDump::kNameSize,
MemoryAllocatorDump::kUnitsBytes, 4096);
- root_heap->AddScalar(MemoryAllocatorDump::kNameObjectsCount,
+ root_heap->AddScalar(MemoryAllocatorDump::kNameObjectCount,
MemoryAllocatorDump::kUnitsObjects, 42);
root_heap->AddScalar("attr1", "units1", 1234);
root_heap->AddString("attr2", "units2", "string_value");
@@ -37,7 +41,7 @@ class FakeMemoryAllocatorDumpProvider : public MemoryDumpProvider {
pmd->CreateAllocatorDump("foobar_allocator/sub_heap");
sub_heap->AddScalar(MemoryAllocatorDump::kNameSize,
MemoryAllocatorDump::kUnitsBytes, 1);
- sub_heap->AddScalar(MemoryAllocatorDump::kNameObjectsCount,
+ sub_heap->AddScalar(MemoryAllocatorDump::kNameObjectCount,
MemoryAllocatorDump::kUnitsObjects, 3);
pmd->CreateAllocatorDump("foobar_allocator/sub_heap/empty");
@@ -81,7 +85,7 @@ void CheckString(const MemoryAllocatorDump* dump,
void CheckScalar(const MemoryAllocatorDump* dump,
const std::string& name,
const char* expected_units,
- uint64 expected_value) {
+ uint64_t expected_value) {
CheckString(dump, name, MemoryAllocatorDump::kTypeScalar, expected_units,
StringPrintf("%" PRIx64, expected_value));
}
@@ -124,9 +128,10 @@ TEST(MemoryAllocatorDumpTest, GuidGeneration) {
TEST(MemoryAllocatorDumpTest, DumpIntoProcessMemoryDump) {
FakeMemoryAllocatorDumpProvider fmadp;
- ProcessMemoryDump pmd(make_scoped_refptr(new MemoryDumpSessionState()));
+ ProcessMemoryDump pmd(new MemoryDumpSessionState(nullptr, nullptr));
+ MemoryDumpArgs dump_args = {MemoryDumpLevelOfDetail::DETAILED};
- fmadp.OnMemoryDump(&pmd);
+ fmadp.OnMemoryDump(dump_args, &pmd);
ASSERT_EQ(3u, pmd.allocator_dumps().size());
@@ -136,7 +141,7 @@ TEST(MemoryAllocatorDumpTest, DumpIntoProcessMemoryDump) {
EXPECT_EQ("foobar_allocator", root_heap->absolute_name());
CheckScalar(root_heap, MemoryAllocatorDump::kNameSize,
MemoryAllocatorDump::kUnitsBytes, 4096);
- CheckScalar(root_heap, MemoryAllocatorDump::kNameObjectsCount,
+ CheckScalar(root_heap, MemoryAllocatorDump::kNameObjectCount,
MemoryAllocatorDump::kUnitsObjects, 42);
CheckScalar(root_heap, "attr1", "units1", 1234);
CheckString(root_heap, "attr2", MemoryAllocatorDump::kTypeString, "units2",
@@ -149,7 +154,7 @@ TEST(MemoryAllocatorDumpTest, DumpIntoProcessMemoryDump) {
EXPECT_EQ("foobar_allocator/sub_heap", sub_heap->absolute_name());
CheckScalar(sub_heap, MemoryAllocatorDump::kNameSize,
MemoryAllocatorDump::kUnitsBytes, 1);
- CheckScalar(sub_heap, MemoryAllocatorDump::kNameObjectsCount,
+ CheckScalar(sub_heap, MemoryAllocatorDump::kNameObjectCount,
MemoryAllocatorDump::kUnitsObjects, 3);
const MemoryAllocatorDump* empty_sub_heap =
pmd.GetAllocatorDump("foobar_allocator/sub_heap/empty");
@@ -159,7 +164,7 @@ TEST(MemoryAllocatorDumpTest, DumpIntoProcessMemoryDump) {
DictionaryValue* attrs = nullptr;
ASSERT_TRUE(raw_attrs->GetAsDictionary(&attrs));
ASSERT_FALSE(attrs->HasKey(MemoryAllocatorDump::kNameSize));
- ASSERT_FALSE(attrs->HasKey(MemoryAllocatorDump::kNameObjectsCount));
+ ASSERT_FALSE(attrs->HasKey(MemoryAllocatorDump::kNameObjectCount));
// Check that the AsValueInfo doesn't hit any DCHECK.
scoped_refptr<TracedValue> traced_value(new TracedValue());
@@ -170,7 +175,7 @@ TEST(MemoryAllocatorDumpTest, DumpIntoProcessMemoryDump) {
#if !defined(NDEBUG) && !defined(OS_ANDROID) && !defined(OS_IOS)
TEST(MemoryAllocatorDumpTest, ForbidDuplicatesDeathTest) {
FakeMemoryAllocatorDumpProvider fmadp;
- ProcessMemoryDump pmd(make_scoped_refptr(new MemoryDumpSessionState()));
+ ProcessMemoryDump pmd(new MemoryDumpSessionState(nullptr, nullptr));
pmd.CreateAllocatorDump("foo_allocator");
pmd.CreateAllocatorDump("bar_allocator/heap");
ASSERT_DEATH(pmd.CreateAllocatorDump("foo_allocator"), "");
diff --git a/base/trace_event/memory_dump_manager.cc b/base/trace_event/memory_dump_manager.cc
index 1e0a36a44e..aa81e00a5d 100644
--- a/base/trace_event/memory_dump_manager.cc
+++ b/base/trace_event/memory_dump_manager.cc
@@ -5,9 +5,18 @@
#include "base/trace_event/memory_dump_manager.h"
#include <algorithm>
+#include <utility>
#include "base/atomic_sequence_num.h"
+#include "base/base_switches.h"
+#include "base/command_line.h"
#include "base/compiler_specific.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/thread.h"
+#include "base/trace_event/heap_profiler_allocation_context_tracker.h"
+#include "base/trace_event/heap_profiler_stack_frame_deduplicator.h"
+#include "base/trace_event/heap_profiler_type_name_deduplicator.h"
+#include "base/trace_event/malloc_dump_provider.h"
#include "base/trace_event/memory_dump_provider.h"
#include "base/trace_event/memory_dump_session_state.h"
#include "base/trace_event/process_memory_dump.h"
@@ -19,7 +28,6 @@
#endif
#if defined(OS_LINUX) || defined(OS_ANDROID)
-#include "base/trace_event/malloc_dump_provider.h"
#include "base/trace_event/process_memory_maps_dump_provider.h"
#endif
@@ -36,116 +44,68 @@ namespace trace_event {
namespace {
-// TODO(primiano): this should be smarter and should do something similar to
-// trace event synthetic delays.
-const char kTraceCategory[] = TRACE_DISABLED_BY_DEFAULT("memory-infra");
-
-// Throttle mmaps at a rate of once every kHeavyMmapsDumpsRate standard dumps.
-const int kHeavyMmapsDumpsRate = 8; // 250 ms * 8 = 2000 ms.
-const int kDumpIntervalMs = 250;
const int kTraceEventNumArgs = 1;
const char* kTraceEventArgNames[] = {"dumps"};
const unsigned char kTraceEventArgTypes[] = {TRACE_VALUE_TYPE_CONVERTABLE};
StaticAtomicSequenceNumber g_next_guid;
-uint32 g_periodic_dumps_count = 0;
+uint32_t g_periodic_dumps_count = 0;
+uint32_t g_heavy_dumps_rate = 0;
MemoryDumpManager* g_instance_for_testing = nullptr;
-MemoryDumpProvider* g_mmaps_dump_provider = nullptr;
-
-const char* MemoryDumpTypeToString(const MemoryDumpType& dump_type) {
- switch (dump_type) {
- case MemoryDumpType::TASK_BEGIN:
- return "TASK_BEGIN";
- case MemoryDumpType::TASK_END:
- return "TASK_END";
- case MemoryDumpType::PERIODIC_INTERVAL:
- return "PERIODIC_INTERVAL";
- case MemoryDumpType::PERIODIC_INTERVAL_WITH_MMAPS:
- return "PERIODIC_INTERVAL_WITH_MMAPS";
- case MemoryDumpType::EXPLICITLY_TRIGGERED:
- return "EXPLICITLY_TRIGGERED";
- }
- NOTREACHED();
- return "UNKNOWN";
-}
-// Internal class used to hold details about ProcessMemoryDump requests for the
-// current process.
-class ProcessMemoryDumpHolder
- : public RefCountedThreadSafe<ProcessMemoryDumpHolder> {
- public:
- ProcessMemoryDumpHolder(
- MemoryDumpRequestArgs req_args,
- const scoped_refptr<MemoryDumpSessionState>& session_state,
- MemoryDumpCallback callback)
- : process_memory_dump(session_state),
- req_args(req_args),
- callback(callback),
- task_runner(MessageLoop::current()->task_runner()),
- num_pending_async_requests(0) {}
-
- ProcessMemoryDump process_memory_dump;
- const MemoryDumpRequestArgs req_args;
-
- // Callback passed to the initial call to CreateProcessDump().
- MemoryDumpCallback callback;
-
- // Thread on which FinalizeDumpAndAddToTrace() should be called, which is the
- // same that invoked the initial CreateProcessDump().
- const scoped_refptr<SingleThreadTaskRunner> task_runner;
-
- // Number of pending ContinueAsyncProcessDump() calls.
- int num_pending_async_requests;
-
- private:
- friend class RefCountedThreadSafe<ProcessMemoryDumpHolder>;
- virtual ~ProcessMemoryDumpHolder() {}
- DISALLOW_COPY_AND_ASSIGN(ProcessMemoryDumpHolder);
-};
-
-void FinalizeDumpAndAddToTrace(
- const scoped_refptr<ProcessMemoryDumpHolder>& pmd_holder) {
- DCHECK_EQ(0, pmd_holder->num_pending_async_requests);
-
- if (!pmd_holder->task_runner->BelongsToCurrentThread()) {
- pmd_holder->task_runner->PostTask(
- FROM_HERE, Bind(&FinalizeDumpAndAddToTrace, pmd_holder));
- return;
+void RequestPeriodicGlobalDump() {
+ MemoryDumpLevelOfDetail level_of_detail;
+ if (g_heavy_dumps_rate == 0) {
+ level_of_detail = MemoryDumpLevelOfDetail::LIGHT;
+ } else {
+ level_of_detail = g_periodic_dumps_count == 0
+ ? MemoryDumpLevelOfDetail::DETAILED
+ : MemoryDumpLevelOfDetail::LIGHT;
+
+ if (++g_periodic_dumps_count == g_heavy_dumps_rate)
+ g_periodic_dumps_count = 0;
}
- scoped_refptr<ConvertableToTraceFormat> event_value(new TracedValue());
- pmd_holder->process_memory_dump.AsValueInto(
- static_cast<TracedValue*>(event_value.get()));
- const char* const event_name =
- MemoryDumpTypeToString(pmd_holder->req_args.dump_type);
-
- TRACE_EVENT_API_ADD_TRACE_EVENT(
- TRACE_EVENT_PHASE_MEMORY_DUMP,
- TraceLog::GetCategoryGroupEnabled(kTraceCategory), event_name,
- pmd_holder->req_args.dump_guid, kTraceEventNumArgs, kTraceEventArgNames,
- kTraceEventArgTypes, nullptr /* arg_values */, &event_value,
- TRACE_EVENT_FLAG_HAS_ID);
-
- if (!pmd_holder->callback.is_null()) {
- pmd_holder->callback.Run(pmd_holder->req_args.dump_guid, true);
- pmd_holder->callback.Reset();
- }
+ MemoryDumpManager::GetInstance()->RequestGlobalDump(
+ MemoryDumpType::PERIODIC_INTERVAL, level_of_detail);
}
-void RequestPeriodicGlobalDump() {
- MemoryDumpType dump_type = g_periodic_dumps_count == 0
- ? MemoryDumpType::PERIODIC_INTERVAL_WITH_MMAPS
- : MemoryDumpType::PERIODIC_INTERVAL;
- if (++g_periodic_dumps_count == kHeavyMmapsDumpsRate)
- g_periodic_dumps_count = 0;
-
- MemoryDumpManager::GetInstance()->RequestGlobalDump(dump_type);
+// Callback wrapper to hook upon the completion of RequestGlobalDump() and
+// inject trace markers.
+void OnGlobalDumpDone(MemoryDumpCallback wrapped_callback,
+ uint64_t dump_guid,
+ bool success) {
+ TRACE_EVENT_NESTABLE_ASYNC_END1(
+ MemoryDumpManager::kTraceCategory, "GlobalMemoryDump",
+ TRACE_ID_MANGLE(dump_guid), "success", success);
+
+ if (!wrapped_callback.is_null()) {
+ wrapped_callback.Run(dump_guid, success);
+ wrapped_callback.Reset();
+ }
}
} // namespace
// static
-const char* const MemoryDumpManager::kTraceCategoryForTesting = kTraceCategory;
+const char* const MemoryDumpManager::kTraceCategory =
+ TRACE_DISABLED_BY_DEFAULT("memory-infra");
+
+// static
+const int MemoryDumpManager::kMaxConsecutiveFailuresCount = 3;
+
+// static
+const uint64_t MemoryDumpManager::kInvalidTracingProcessId = 0;
+
+// static
+const char* const MemoryDumpManager::kSystemAllocatorPoolName =
+#if defined(MALLOC_MEMORY_TRACING_SUPPORTED)
+ MallocDumpProvider::kAllocatedObjects;
+#elif defined(OS_WIN)
+ WinHeapDumpProvider::kAllocatedObjects;
+#else
+ nullptr;
+#endif
// static
MemoryDumpManager* MemoryDumpManager::GetInstance() {
@@ -158,266 +118,548 @@ MemoryDumpManager* MemoryDumpManager::GetInstance() {
// static
void MemoryDumpManager::SetInstanceForTesting(MemoryDumpManager* instance) {
- if (instance)
- instance->skip_core_dumpers_auto_registration_for_testing_ = true;
g_instance_for_testing = instance;
}
MemoryDumpManager::MemoryDumpManager()
: delegate_(nullptr),
+ is_coordinator_(false),
memory_tracing_enabled_(0),
- skip_core_dumpers_auto_registration_for_testing_(false) {
+ tracing_process_id_(kInvalidTracingProcessId),
+ dumper_registrations_ignored_for_testing_(false) {
g_next_guid.GetNext(); // Make sure that first guid is not zero.
+
+ heap_profiling_enabled_ = CommandLine::InitializedForCurrentProcess()
+ ? CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableHeapProfiling)
+ : false;
+
+ if (heap_profiling_enabled_)
+ AllocationContextTracker::SetCaptureEnabled(true);
}
MemoryDumpManager::~MemoryDumpManager() {
- base::trace_event::TraceLog::GetInstance()->RemoveEnabledStateObserver(this);
+ TraceLog::GetInstance()->RemoveEnabledStateObserver(this);
}
-void MemoryDumpManager::Initialize() {
- TRACE_EVENT0(kTraceCategory, "init"); // Add to trace-viewer category list.
- trace_event::TraceLog::GetInstance()->AddEnabledStateObserver(this);
-
- if (skip_core_dumpers_auto_registration_for_testing_)
- return;
+void MemoryDumpManager::Initialize(MemoryDumpManagerDelegate* delegate,
+ bool is_coordinator) {
+ {
+ AutoLock lock(lock_);
+ DCHECK(delegate);
+ DCHECK(!delegate_);
+ delegate_ = delegate;
+ is_coordinator_ = is_coordinator;
+ }
- // Enable the core dump providers.
+// Enable the core dump providers.
#if !defined(OS_NACL)
- RegisterDumpProvider(ProcessMemoryTotalsDumpProvider::GetInstance());
+ RegisterDumpProvider(ProcessMemoryTotalsDumpProvider::GetInstance(),
+ "ProcessMemoryTotals", nullptr);
+#endif
+
+#if defined(MALLOC_MEMORY_TRACING_SUPPORTED)
+ RegisterDumpProvider(MallocDumpProvider::GetInstance(), "Malloc", nullptr);
#endif
#if defined(OS_LINUX) || defined(OS_ANDROID)
- g_mmaps_dump_provider = ProcessMemoryMapsDumpProvider::GetInstance();
- RegisterDumpProvider(g_mmaps_dump_provider);
- RegisterDumpProvider(MallocDumpProvider::GetInstance());
+ RegisterDumpProvider(ProcessMemoryMapsDumpProvider::GetInstance(),
+ "ProcessMemoryMaps", nullptr);
#endif
#if defined(OS_ANDROID)
- RegisterDumpProvider(JavaHeapDumpProvider::GetInstance());
+ RegisterDumpProvider(JavaHeapDumpProvider::GetInstance(), "JavaHeap",
+ nullptr);
#endif
#if defined(OS_WIN)
- RegisterDumpProvider(WinHeapDumpProvider::GetInstance());
+ RegisterDumpProvider(WinHeapDumpProvider::GetInstance(), "WinHeap", nullptr);
#endif
+
+ // If tracing was enabled before initializing MemoryDumpManager, we missed the
+ // OnTraceLogEnabled() event. Synthetize it so we can late-join the party.
+ bool is_tracing_already_enabled = TraceLog::GetInstance()->IsEnabled();
+ TRACE_EVENT0(kTraceCategory, "init"); // Add to trace-viewer category list.
+ TraceLog::GetInstance()->AddEnabledStateObserver(this);
+ if (is_tracing_already_enabled)
+ OnTraceLogEnabled();
}
-void MemoryDumpManager::SetDelegate(MemoryDumpManagerDelegate* delegate) {
- AutoLock lock(lock_);
- DCHECK_EQ(static_cast<MemoryDumpManagerDelegate*>(nullptr), delegate_);
- delegate_ = delegate;
+void MemoryDumpManager::RegisterDumpProvider(
+ MemoryDumpProvider* mdp,
+ const char* name,
+ const scoped_refptr<SingleThreadTaskRunner>& task_runner,
+ const MemoryDumpProvider::Options& options) {
+ if (dumper_registrations_ignored_for_testing_)
+ return;
+
+ scoped_refptr<MemoryDumpProviderInfo> mdpinfo =
+ new MemoryDumpProviderInfo(mdp, name, task_runner, options);
+
+ {
+ AutoLock lock(lock_);
+ bool already_registered = !dump_providers_.insert(mdpinfo).second;
+ // This actually happens in some tests which don't have a clean tear-down
+ // path for RenderThreadImpl::Init().
+ if (already_registered)
+ return;
+ }
+
+ if (heap_profiling_enabled_)
+ mdp->OnHeapProfilingEnabled(true);
}
void MemoryDumpManager::RegisterDumpProvider(
MemoryDumpProvider* mdp,
+ const char* name,
const scoped_refptr<SingleThreadTaskRunner>& task_runner) {
- MemoryDumpProviderInfo mdp_info(task_runner);
- AutoLock lock(lock_);
- dump_providers_.insert(std::make_pair(mdp, mdp_info));
+ RegisterDumpProvider(mdp, name, task_runner, MemoryDumpProvider::Options());
}
-void MemoryDumpManager::RegisterDumpProvider(MemoryDumpProvider* mdp) {
- RegisterDumpProvider(mdp, nullptr);
+void MemoryDumpManager::UnregisterDumpProvider(MemoryDumpProvider* mdp) {
+ UnregisterDumpProviderInternal(mdp, false /* delete_async */);
}
-void MemoryDumpManager::UnregisterDumpProvider(MemoryDumpProvider* mdp) {
+void MemoryDumpManager::UnregisterAndDeleteDumpProviderSoon(
+ scoped_ptr<MemoryDumpProvider> mdp) {
+ UnregisterDumpProviderInternal(mdp.release(), true /* delete_async */);
+}
+
+void MemoryDumpManager::UnregisterDumpProviderInternal(
+ MemoryDumpProvider* mdp,
+ bool take_mdp_ownership_and_delete_async) {
+ scoped_ptr<MemoryDumpProvider> owned_mdp;
+ if (take_mdp_ownership_and_delete_async)
+ owned_mdp.reset(mdp);
+
AutoLock lock(lock_);
- auto it = dump_providers_.find(mdp);
- if (it == dump_providers_.end())
- return;
+ auto mdp_iter = dump_providers_.begin();
+ for (; mdp_iter != dump_providers_.end(); ++mdp_iter) {
+ if ((*mdp_iter)->dump_provider == mdp)
+ break;
+ }
- const MemoryDumpProviderInfo& mdp_info = it->second;
- // Unregistration of a MemoryDumpProvider while tracing is ongoing is safe
- // only if the MDP has specified a thread affinity (via task_runner()) AND
- // the unregistration happens on the same thread (so the MDP cannot unregister
- // and OnMemoryDump() at the same time).
- // Otherwise, it is not possible to guarantee that its unregistration is
- // race-free. If you hit this DCHECK, your MDP has a bug.
- DCHECK_IMPLIES(
- subtle::NoBarrier_Load(&memory_tracing_enabled_),
- mdp_info.task_runner && mdp_info.task_runner->BelongsToCurrentThread())
- << "The MemoryDumpProvider attempted to unregister itself in a racy way. "
- << " Please file a crbug.";
-
- // Remove from the enabled providers list. This is to deal with the case that
- // UnregisterDumpProvider is called while the trace is enabled.
- dump_providers_.erase(it);
+ if (mdp_iter == dump_providers_.end())
+ return; // Not registered / already unregistered.
+
+ if (take_mdp_ownership_and_delete_async) {
+ // The MDP will be deleted whenever the MDPInfo struct will, that is either:
+ // - At the end of this function, if no dump is in progress.
+ // - In the prologue of the ContinueAsyncProcessDump().
+ DCHECK(!(*mdp_iter)->owned_dump_provider);
+ (*mdp_iter)->owned_dump_provider = std::move(owned_mdp);
+ } else if (subtle::NoBarrier_Load(&memory_tracing_enabled_)) {
+ // If you hit this DCHECK, your dump provider has a bug.
+ // Unregistration of a MemoryDumpProvider is safe only if:
+ // - The MDP has specified a thread affinity (via task_runner()) AND
+ // the unregistration happens on the same thread (so the MDP cannot
+ // unregister and be in the middle of a OnMemoryDump() at the same time.
+ // - The MDP has NOT specified a thread affinity and its ownership is
+ // transferred via UnregisterAndDeleteDumpProviderSoon().
+ // In all the other cases, it is not possible to guarantee that the
+ // unregistration will not race with OnMemoryDump() calls.
+ DCHECK((*mdp_iter)->task_runner &&
+ (*mdp_iter)->task_runner->BelongsToCurrentThread())
+ << "MemoryDumpProvider \"" << (*mdp_iter)->name << "\" attempted to "
+ << "unregister itself in a racy way. Please file a crbug.";
+ }
+
+ // The MDPInfo instance can still be referenced by the
+ // |ProcessMemoryDumpAsyncState.pending_dump_providers|. For this reason
+ // the MDPInfo is flagged as disabled. It will cause ContinueAsyncProcessDump
+ // to just skip it, without actually invoking the |mdp|, which might be
+ // destroyed by the caller soon after this method returns.
+ (*mdp_iter)->disabled = true;
+ dump_providers_.erase(mdp_iter);
}
void MemoryDumpManager::RequestGlobalDump(
MemoryDumpType dump_type,
+ MemoryDumpLevelOfDetail level_of_detail,
const MemoryDumpCallback& callback) {
// Bail out immediately if tracing is not enabled at all.
- if (!UNLIKELY(subtle::NoBarrier_Load(&memory_tracing_enabled_)))
+ if (!UNLIKELY(subtle::NoBarrier_Load(&memory_tracing_enabled_))) {
+ if (!callback.is_null())
+ callback.Run(0u /* guid */, false /* success */);
return;
+ }
- const uint64 guid =
+ const uint64_t guid =
TraceLog::GetInstance()->MangleEventId(g_next_guid.GetNext());
- // The delegate_ is supposed to be thread safe, immutable and long lived.
- // No need to keep the lock after we ensure that a delegate has been set.
+ // Creates an async event to keep track of the global dump evolution.
+ // The |wrapped_callback| will generate the ASYNC_END event and then invoke
+ // the real |callback| provided by the caller.
+ TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(kTraceCategory, "GlobalMemoryDump",
+ TRACE_ID_MANGLE(guid));
+ MemoryDumpCallback wrapped_callback = Bind(&OnGlobalDumpDone, callback);
+
+ // Technically there is no need to grab the |lock_| here as the delegate is
+ // long-lived and can only be set by Initialize(), which is locked and
+ // necessarily happens before memory_tracing_enabled_ == true.
+ // Not taking the |lock_|, though, is lakely make TSan barf and, at this point
+ // (memory-infra is enabled) we're not in the fast-path anymore.
MemoryDumpManagerDelegate* delegate;
{
AutoLock lock(lock_);
delegate = delegate_;
}
- if (delegate) {
- // The delegate is in charge to coordinate the request among all the
- // processes and call the CreateLocalDumpPoint on the local process.
- MemoryDumpRequestArgs args = {guid, dump_type};
- delegate->RequestGlobalMemoryDump(args, callback);
- } else if (!callback.is_null()) {
- callback.Run(guid, false /* success */);
- }
+ // The delegate will coordinate the IPC broadcast and at some point invoke
+ // CreateProcessDump() to get a dump for the current process.
+ MemoryDumpRequestArgs args = {guid, dump_type, level_of_detail};
+ delegate->RequestGlobalMemoryDump(args, wrapped_callback);
}
-void MemoryDumpManager::RequestGlobalDump(MemoryDumpType dump_type) {
- RequestGlobalDump(dump_type, MemoryDumpCallback());
+void MemoryDumpManager::RequestGlobalDump(
+ MemoryDumpType dump_type,
+ MemoryDumpLevelOfDetail level_of_detail) {
+ RequestGlobalDump(dump_type, level_of_detail, MemoryDumpCallback());
}
-// Creates a memory dump for the current process and appends it to the trace.
void MemoryDumpManager::CreateProcessDump(const MemoryDumpRequestArgs& args,
const MemoryDumpCallback& callback) {
- scoped_refptr<ProcessMemoryDumpHolder> pmd_holder(
- new ProcessMemoryDumpHolder(args, session_state_, callback));
- ProcessMemoryDump* pmd = &pmd_holder->process_memory_dump;
- bool did_any_provider_dump = false;
-
- // Iterate over the active dump providers and invoke OnMemoryDump(pmd).
- // The MDM guarantees linearity (at most one MDP is active within one
- // process) and thread-safety (MDM enforces the right locking when entering /
- // leaving the MDP.OnMemoryDump() call). This is to simplify the clients'
- // design
- // and not let the MDPs worry about locking.
- // As regards thread affinity, depending on the MDP configuration (see
- // memory_dump_provider.h), the OnMemoryDump() invocation can happen:
- // - Synchronousy on the MDM thread, when MDP.task_runner() is not set.
- // - Posted on MDP.task_runner(), when MDP.task_runner() is set.
+ TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(kTraceCategory, "ProcessMemoryDump",
+ TRACE_ID_MANGLE(args.dump_guid));
+
+ scoped_ptr<ProcessMemoryDumpAsyncState> pmd_async_state;
{
AutoLock lock(lock_);
- for (auto it = dump_providers_.begin(); it != dump_providers_.end(); ++it) {
- MemoryDumpProvider* mdp = it->first;
- MemoryDumpProviderInfo* mdp_info = &it->second;
- // Mmaps dumping is very heavyweight and cannot be performed at the same
- // rate of other dumps. TODO(primiano): this is a hack and should be
- // cleaned up as part of crbug.com/499731.
- if (mdp == g_mmaps_dump_provider &&
- args.dump_type != MemoryDumpType::PERIODIC_INTERVAL_WITH_MMAPS) {
- continue;
- }
- if (mdp_info->disabled)
- continue;
- if (mdp_info->task_runner) {
- // The OnMemoryDump() call must be posted.
- bool did_post_async_task = mdp_info->task_runner->PostTask(
- FROM_HERE, Bind(&MemoryDumpManager::ContinueAsyncProcessDump,
- Unretained(this), Unretained(mdp), pmd_holder));
- // The thread underlying the TaskRunner might have gone away.
- if (did_post_async_task)
- ++pmd_holder->num_pending_async_requests;
- } else {
- // Invoke the dump provider synchronously.
- did_any_provider_dump |= InvokeDumpProviderLocked(mdp, pmd);
- }
- }
- } // AutoLock
+ pmd_async_state.reset(
+ new ProcessMemoryDumpAsyncState(args, dump_providers_, session_state_,
+ callback, dump_thread_->task_runner()));
+ }
- // If at least one synchronous provider did dump and there are no pending
- // asynchronous requests, add the dump to the trace and invoke the callback
- // straight away (FinalizeDumpAndAddToTrace() takes care of the callback).
- if (did_any_provider_dump && pmd_holder->num_pending_async_requests == 0)
- FinalizeDumpAndAddToTrace(pmd_holder);
-}
+ TRACE_EVENT_WITH_FLOW0(kTraceCategory, "MemoryDumpManager::CreateProcessDump",
+ TRACE_ID_MANGLE(args.dump_guid),
+ TRACE_EVENT_FLAG_FLOW_OUT);
-// Invokes the MemoryDumpProvider.OnMemoryDump(), taking care of the fail-safe
-// logic which disables the dumper when failing (crbug.com/461788).
-bool MemoryDumpManager::InvokeDumpProviderLocked(MemoryDumpProvider* mdp,
- ProcessMemoryDump* pmd) {
- lock_.AssertAcquired();
- bool dump_successful = mdp->OnMemoryDump(pmd);
- if (!dump_successful) {
- LOG(ERROR) << "The memory dumper failed, possibly due to sandboxing "
- "(crbug.com/461788), disabling it for current process. Try "
- "restarting chrome with the --no-sandbox switch.";
- dump_providers_.find(mdp)->second.disabled = true;
- }
- return dump_successful;
+ // Start the thread hop. |dump_providers_| are kept sorted by thread, so
+ // ContinueAsyncProcessDump will hop at most once per thread (w.r.t. thread
+ // affinity specified by the MemoryDumpProvider(s) in RegisterDumpProvider()).
+ ContinueAsyncProcessDump(pmd_async_state.release());
}
-// This is posted to arbitrary threads as a continuation of CreateProcessDump(),
-// when one or more MemoryDumpProvider(s) require the OnMemoryDump() call to
-// happen on a different thread.
+// At most one ContinueAsyncProcessDump() can be active at any time for a given
+// PMD, regardless of status of the |lock_|. |lock_| is used here purely to
+// ensure consistency w.r.t. (un)registrations of |dump_providers_|.
+// The linearization of dump providers' OnMemoryDump invocations is achieved by
+// means of subsequent PostTask(s).
+//
+// 1) Prologue:
+// - If this was the last hop, create a trace event, add it to the trace
+// and finalize (invoke callback).
+// - Check if we are on the right thread. If not hop and continue there.
+// - Check if the dump provider is disabled, if so skip the dump.
+// 2) Invoke the dump provider's OnMemoryDump() (unless skipped).
+// 3) Epilogue:
+// - Unregister the dump provider if it failed too many times consecutively.
+// - Pop() the MDP from the |pending_dump_providers| list, eventually
+// destroying the MDPInfo if that was unregistered in the meantime.
void MemoryDumpManager::ContinueAsyncProcessDump(
- MemoryDumpProvider* mdp,
- scoped_refptr<ProcessMemoryDumpHolder> pmd_holder) {
- bool should_finalize_dump = false;
+ ProcessMemoryDumpAsyncState* owned_pmd_async_state) {
+ // Initalizes the ThreadLocalEventBuffer to guarantee that the TRACE_EVENTs
+ // in the PostTask below don't end up registering their own dump providers
+ // (for discounting trace memory overhead) while holding the |lock_|.
+ TraceLog::GetInstance()->InitializeThreadLocalEventBufferIfSupported();
+
+ // In theory |owned_pmd_async_state| should be a scoped_ptr. The only reason
+ // why it isn't is because of the corner case logic of |did_post_task| below,
+ // which needs to take back the ownership of the |pmd_async_state| when a
+ // thread goes away and consequently the PostTask() fails.
+ // Unfortunately, PostTask() destroys the scoped_ptr arguments upon failure
+ // to prevent accidental leaks. Using a scoped_ptr would prevent us to to
+ // skip the hop and move on. Hence the manual naked -> scoped ptr juggling.
+ auto pmd_async_state = make_scoped_ptr(owned_pmd_async_state);
+ owned_pmd_async_state = nullptr;
+
+ if (pmd_async_state->pending_dump_providers.empty())
+ return FinalizeDumpAndAddToTrace(std::move(pmd_async_state));
+
+ // Read MemoryDumpProviderInfo thread safety considerations in
+ // memory_dump_manager.h when accessing |mdpinfo| fields.
+ MemoryDumpProviderInfo* mdpinfo =
+ pmd_async_state->pending_dump_providers.back().get();
+
+ // If the dump provider did not specify a thread affinity, dump on
+ // |dump_thread_|. Note that |dump_thread_| might have been Stop()-ed at this
+ // point (if tracing was disabled in the meanwhile). In such case the
+ // PostTask() below will fail, but |task_runner| should always be non-null.
+ SingleThreadTaskRunner* task_runner = mdpinfo->task_runner.get();
+ if (!task_runner)
+ task_runner = pmd_async_state->dump_thread_task_runner.get();
+
+ bool post_task_failed = false;
+ if (!task_runner->BelongsToCurrentThread()) {
+ // It's time to hop onto another thread.
+ post_task_failed = !task_runner->PostTask(
+ FROM_HERE, Bind(&MemoryDumpManager::ContinueAsyncProcessDump,
+ Unretained(this), Unretained(pmd_async_state.get())));
+ if (!post_task_failed) {
+ // Ownership is tranferred to the next ContinueAsyncProcessDump().
+ ignore_result(pmd_async_state.release());
+ return;
+ }
+ }
+
+ // At this point either:
+ // - The MDP has a task runner affinity and we are on the right thread.
+ // - The MDP has a task runner affinity but the underlying thread is gone,
+ // hence the above |post_task_failed| == true.
+ // - The MDP does NOT have a task runner affinity. A locked access is required
+ // to R/W |disabled| (for the UnregisterAndDeleteDumpProviderSoon() case).
+ bool should_dump;
+ const char* disabled_reason = nullptr;
{
- // The lock here is to guarantee that different asynchronous dumps on
- // different threads are still serialized, so that the MemoryDumpProvider
- // has a consistent view of the |pmd| argument passed.
AutoLock lock(lock_);
- ProcessMemoryDump* pmd = &pmd_holder->process_memory_dump;
-
- // Check if the MemoryDumpProvider is still there. It might have been
- // destroyed and unregistered while hopping threads.
- if (dump_providers_.count(mdp))
- InvokeDumpProviderLocked(mdp, pmd);
-
- // Finalize the dump appending it to the trace if this was the last
- // asynchronous request pending.
- --pmd_holder->num_pending_async_requests;
- if (pmd_holder->num_pending_async_requests == 0)
- should_finalize_dump = true;
- } // AutoLock(lock_)
-
- if (should_finalize_dump)
- FinalizeDumpAndAddToTrace(pmd_holder);
+ if (!mdpinfo->disabled) {
+ if (mdpinfo->consecutive_failures >= kMaxConsecutiveFailuresCount) {
+ mdpinfo->disabled = true;
+ disabled_reason =
+ "Dump failure, possibly related with sandboxing (crbug.com/461788)."
+ " Try --no-sandbox.";
+ } else if (post_task_failed) {
+ disabled_reason = "The thread it was meant to dump onto is gone.";
+ mdpinfo->disabled = true;
+ }
+ }
+ should_dump = !mdpinfo->disabled;
+ }
+
+ if (disabled_reason) {
+ LOG(ERROR) << "Disabling MemoryDumpProvider \"" << mdpinfo->name << "\". "
+ << disabled_reason;
+ }
+
+ if (should_dump) {
+ // Invoke the dump provider.
+ TRACE_EVENT_WITH_FLOW1(kTraceCategory,
+ "MemoryDumpManager::ContinueAsyncProcessDump",
+ TRACE_ID_MANGLE(pmd_async_state->req_args.dump_guid),
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
+ "dump_provider.name", mdpinfo->name);
+
+ // Pid of the target process being dumped. Often kNullProcessId (= current
+ // process), non-zero when the coordinator process creates dumps on behalf
+ // of child processes (see crbug.com/461788).
+ ProcessId target_pid = mdpinfo->options.target_pid;
+ ProcessMemoryDump* pmd =
+ pmd_async_state->GetOrCreateMemoryDumpContainerForProcess(target_pid);
+ MemoryDumpArgs args = {pmd_async_state->req_args.level_of_detail};
+ bool dump_successful = mdpinfo->dump_provider->OnMemoryDump(args, pmd);
+ mdpinfo->consecutive_failures =
+ dump_successful ? 0 : mdpinfo->consecutive_failures + 1;
+ } // if (!mdpinfo->disabled)
+
+ pmd_async_state->pending_dump_providers.pop_back();
+ ContinueAsyncProcessDump(pmd_async_state.release());
+}
+
+// static
+void MemoryDumpManager::FinalizeDumpAndAddToTrace(
+ scoped_ptr<ProcessMemoryDumpAsyncState> pmd_async_state) {
+ DCHECK(pmd_async_state->pending_dump_providers.empty());
+ const uint64_t dump_guid = pmd_async_state->req_args.dump_guid;
+ if (!pmd_async_state->callback_task_runner->BelongsToCurrentThread()) {
+ scoped_refptr<SingleThreadTaskRunner> callback_task_runner =
+ pmd_async_state->callback_task_runner;
+ callback_task_runner->PostTask(
+ FROM_HERE, Bind(&MemoryDumpManager::FinalizeDumpAndAddToTrace,
+ Passed(&pmd_async_state)));
+ return;
+ }
+
+ TRACE_EVENT_WITH_FLOW0(kTraceCategory,
+ "MemoryDumpManager::FinalizeDumpAndAddToTrace",
+ TRACE_ID_MANGLE(dump_guid), TRACE_EVENT_FLAG_FLOW_IN);
+
+ for (const auto& kv : pmd_async_state->process_dumps) {
+ ProcessId pid = kv.first; // kNullProcessId for the current process.
+ ProcessMemoryDump* process_memory_dump = kv.second.get();
+ TracedValue* traced_value = new TracedValue();
+ scoped_refptr<ConvertableToTraceFormat> event_value(traced_value);
+ process_memory_dump->AsValueInto(traced_value);
+ traced_value->SetString("level_of_detail",
+ MemoryDumpLevelOfDetailToString(
+ pmd_async_state->req_args.level_of_detail));
+ const char* const event_name =
+ MemoryDumpTypeToString(pmd_async_state->req_args.dump_type);
+
+ TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_PROCESS_ID(
+ TRACE_EVENT_PHASE_MEMORY_DUMP,
+ TraceLog::GetCategoryGroupEnabled(kTraceCategory), event_name,
+ dump_guid, pid, kTraceEventNumArgs, kTraceEventArgNames,
+ kTraceEventArgTypes, nullptr /* arg_values */, &event_value,
+ TRACE_EVENT_FLAG_HAS_ID);
+ }
+
+ if (!pmd_async_state->callback.is_null()) {
+ pmd_async_state->callback.Run(dump_guid, true /* success */);
+ pmd_async_state->callback.Reset();
+ }
+
+ TRACE_EVENT_NESTABLE_ASYNC_END0(kTraceCategory, "ProcessMemoryDump",
+ TRACE_ID_MANGLE(dump_guid));
}
void MemoryDumpManager::OnTraceLogEnabled() {
- // TODO(primiano): at this point we query TraceLog::GetCurrentCategoryFilter
- // to figure out (and cache) which dumpers should be enabled or not.
- // For the moment piggy back everything on the generic "memory" category.
bool enabled;
TRACE_EVENT_CATEGORY_GROUP_ENABLED(kTraceCategory, &enabled);
+ if (!enabled)
+ return;
- AutoLock lock(lock_);
+ // Initialize the TraceLog for the current thread. This is to avoid that the
+ // TraceLog memory dump provider is registered lazily in the PostTask() below
+ // while the |lock_| is taken;
+ TraceLog::GetInstance()->InitializeThreadLocalEventBufferIfSupported();
- // There is no point starting the tracing without a delegate.
- if (!enabled || !delegate_) {
- // Disable all the providers.
- for (auto it = dump_providers_.begin(); it != dump_providers_.end(); ++it)
- it->second.disabled = true;
+ // Spin-up the thread used to invoke unbound dump providers.
+ scoped_ptr<Thread> dump_thread(new Thread("MemoryInfra"));
+ if (!dump_thread->Start()) {
+ LOG(ERROR) << "Failed to start the memory-infra thread for tracing";
return;
}
- session_state_ = new MemoryDumpSessionState();
- for (auto it = dump_providers_.begin(); it != dump_providers_.end(); ++it)
- it->second.disabled = false;
+ AutoLock lock(lock_);
+
+ DCHECK(delegate_); // At this point we must have a delegate.
+
+ scoped_refptr<StackFrameDeduplicator> stack_frame_deduplicator = nullptr;
+ scoped_refptr<TypeNameDeduplicator> type_name_deduplicator = nullptr;
+
+ if (heap_profiling_enabled_) {
+ // If heap profiling is enabled, the stack frame deduplicator and type name
+ // deduplicator will be in use. Add a metadata events to write the frames
+ // and type IDs.
+ stack_frame_deduplicator = new StackFrameDeduplicator;
+ type_name_deduplicator = new TypeNameDeduplicator;
+ TRACE_EVENT_API_ADD_METADATA_EVENT(
+ "stackFrames", "stackFrames",
+ scoped_refptr<ConvertableToTraceFormat>(stack_frame_deduplicator));
+ TRACE_EVENT_API_ADD_METADATA_EVENT(
+ "typeNames", "typeNames",
+ scoped_refptr<ConvertableToTraceFormat>(type_name_deduplicator));
+ }
+
+ DCHECK(!dump_thread_);
+ dump_thread_ = std::move(dump_thread);
+ session_state_ = new MemoryDumpSessionState(stack_frame_deduplicator,
+ type_name_deduplicator);
subtle::NoBarrier_Store(&memory_tracing_enabled_, 1);
- if (delegate_->IsCoordinatorProcess()) {
- g_periodic_dumps_count = 0;
- periodic_dump_timer_.Start(FROM_HERE,
- TimeDelta::FromMilliseconds(kDumpIntervalMs),
- base::Bind(&RequestPeriodicGlobalDump));
+ // TODO(primiano): This is a temporary hack to disable periodic memory dumps
+ // when running memory benchmarks until telemetry uses TraceConfig to
+ // enable/disable periodic dumps. See crbug.com/529184 .
+ if (!is_coordinator_ ||
+ CommandLine::ForCurrentProcess()->HasSwitch(
+ "enable-memory-benchmarking")) {
+ return;
+ }
+
+ // Enable periodic dumps. At the moment the periodic support is limited to at
+ // most one low-detail periodic dump and at most one high-detail periodic
+ // dump. If both are specified the high-detail period must be an integer
+ // multiple of the low-level one.
+ g_periodic_dumps_count = 0;
+ const TraceConfig trace_config =
+ TraceLog::GetInstance()->GetCurrentTraceConfig();
+ const TraceConfig::MemoryDumpConfig& config_list =
+ trace_config.memory_dump_config();
+ if (config_list.empty())
+ return;
+
+ uint32_t min_timer_period_ms = std::numeric_limits<uint32_t>::max();
+ uint32_t heavy_dump_period_ms = 0;
+ DCHECK_LE(config_list.size(), 2u);
+ for (const TraceConfig::MemoryDumpTriggerConfig& config : config_list) {
+ DCHECK(config.periodic_interval_ms);
+ if (config.level_of_detail == MemoryDumpLevelOfDetail::DETAILED)
+ heavy_dump_period_ms = config.periodic_interval_ms;
+ min_timer_period_ms =
+ std::min(min_timer_period_ms, config.periodic_interval_ms);
}
+ DCHECK_EQ(0u, heavy_dump_period_ms % min_timer_period_ms);
+ g_heavy_dumps_rate = heavy_dump_period_ms / min_timer_period_ms;
+
+ periodic_dump_timer_.Start(FROM_HERE,
+ TimeDelta::FromMilliseconds(min_timer_period_ms),
+ base::Bind(&RequestPeriodicGlobalDump));
}
void MemoryDumpManager::OnTraceLogDisabled() {
- AutoLock lock(lock_);
- periodic_dump_timer_.Stop();
subtle::NoBarrier_Store(&memory_tracing_enabled_, 0);
- session_state_ = nullptr;
+ scoped_ptr<Thread> dump_thread;
+ {
+ AutoLock lock(lock_);
+ dump_thread = std::move(dump_thread_);
+ session_state_ = nullptr;
+ }
+
+ // Thread stops are blocking and must be performed outside of the |lock_|
+ // or will deadlock (e.g., if ContinueAsyncProcessDump() tries to acquire it).
+ periodic_dump_timer_.Stop();
+ if (dump_thread)
+ dump_thread->Stop();
+}
+
+uint64_t MemoryDumpManager::GetTracingProcessId() const {
+ return delegate_->GetTracingProcessId();
}
MemoryDumpManager::MemoryDumpProviderInfo::MemoryDumpProviderInfo(
- const scoped_refptr<SingleThreadTaskRunner>& task_runner)
- : task_runner(task_runner), disabled(false) {
+ MemoryDumpProvider* dump_provider,
+ const char* name,
+ const scoped_refptr<SingleThreadTaskRunner>& task_runner,
+ const MemoryDumpProvider::Options& options)
+ : dump_provider(dump_provider),
+ name(name),
+ task_runner(task_runner),
+ options(options),
+ consecutive_failures(0),
+ disabled(false) {}
+
+MemoryDumpManager::MemoryDumpProviderInfo::~MemoryDumpProviderInfo() {}
+
+bool MemoryDumpManager::MemoryDumpProviderInfo::Comparator::operator()(
+ const scoped_refptr<MemoryDumpManager::MemoryDumpProviderInfo>& a,
+ const scoped_refptr<MemoryDumpManager::MemoryDumpProviderInfo>& b) const {
+ if (!a || !b)
+ return a.get() < b.get();
+ // Ensure that unbound providers (task_runner == nullptr) always run last.
+ // Rationale: some unbound dump providers are known to be slow, keep them last
+ // to avoid skewing timings of the other dump providers.
+ return std::tie(a->task_runner, a->dump_provider) >
+ std::tie(b->task_runner, b->dump_provider);
}
-MemoryDumpManager::MemoryDumpProviderInfo::~MemoryDumpProviderInfo() {
+
+MemoryDumpManager::ProcessMemoryDumpAsyncState::ProcessMemoryDumpAsyncState(
+ MemoryDumpRequestArgs req_args,
+ const MemoryDumpProviderInfo::OrderedSet& dump_providers,
+ const scoped_refptr<MemoryDumpSessionState>& session_state,
+ MemoryDumpCallback callback,
+ const scoped_refptr<SingleThreadTaskRunner>& dump_thread_task_runner)
+ : req_args(req_args),
+ session_state(session_state),
+ callback(callback),
+ callback_task_runner(MessageLoop::current()->task_runner()),
+ dump_thread_task_runner(dump_thread_task_runner) {
+ pending_dump_providers.reserve(dump_providers.size());
+ pending_dump_providers.assign(dump_providers.rbegin(), dump_providers.rend());
+}
+
+MemoryDumpManager::ProcessMemoryDumpAsyncState::~ProcessMemoryDumpAsyncState() {
+}
+
+ProcessMemoryDump* MemoryDumpManager::ProcessMemoryDumpAsyncState::
+ GetOrCreateMemoryDumpContainerForProcess(ProcessId pid) {
+ auto iter = process_dumps.find(pid);
+ if (iter == process_dumps.end()) {
+ scoped_ptr<ProcessMemoryDump> new_pmd(new ProcessMemoryDump(session_state));
+ iter = process_dumps.insert(std::make_pair(pid, std::move(new_pmd))).first;
+ }
+ return iter->second.get();
}
} // namespace trace_event
diff --git a/base/trace_event/memory_dump_manager.h b/base/trace_event/memory_dump_manager.h
index 3645ac18ba..b3880afdf4 100644
--- a/base/trace_event/memory_dump_manager.h
+++ b/base/trace_event/memory_dump_manager.h
@@ -5,30 +5,33 @@
#ifndef BASE_TRACE_EVENT_MEMORY_DUMP_MANAGER_H_
#define BASE_TRACE_EVENT_MEMORY_DUMP_MANAGER_H_
+#include <stdint.h>
+
+#include <map>
+#include <memory>
+#include <set>
#include <vector>
#include "base/atomicops.h"
#include "base/containers/hash_tables.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/singleton.h"
#include "base/synchronization/lock.h"
#include "base/timer/timer.h"
#include "base/trace_event/memory_dump_request_args.h"
+#include "base/trace_event/process_memory_dump.h"
#include "base/trace_event/trace_event.h"
namespace base {
class SingleThreadTaskRunner;
+class Thread;
namespace trace_event {
-namespace {
-class ProcessMemoryDumpHolder;
-}
-
class MemoryDumpManagerDelegate;
class MemoryDumpProvider;
-class ProcessMemoryDump;
class MemoryDumpSessionState;
// This is the interface exposed to the rest of the codebase to deal with
@@ -36,28 +39,60 @@ class MemoryDumpSessionState;
// RequestDumpPoint(). The extension by Un(RegisterDumpProvider).
class BASE_EXPORT MemoryDumpManager : public TraceLog::EnabledStateObserver {
public:
- static const char* const kTraceCategoryForTesting;
+ static const char* const kTraceCategory;
- static MemoryDumpManager* GetInstance();
+ // This value is returned as the tracing id of the child processes by
+ // GetTracingProcessId() when tracing is not enabled.
+ static const uint64_t kInvalidTracingProcessId;
- // Invoked once per process to register the TraceLog observer.
- void Initialize();
-
- // See the lifetime and thread-safety requirements on the delegate below in
- // the |MemoryDumpManagerDelegate| docstring.
- void SetDelegate(MemoryDumpManagerDelegate* delegate);
+ static MemoryDumpManager* GetInstance();
- // MemoryDumpManager does NOT take memory ownership of |mdp|, which is
- // expected to either be a singleton or unregister itself.
- // If the optional |task_runner| argument is non-null, all the calls to the
- // |mdp| will be issues on the given thread. Otherwise, the |mdp| should be
- // able to handle calls on arbitrary threads.
+ // Invoked once per process to listen to trace begin / end events.
+ // Initialization can happen after (Un)RegisterMemoryDumpProvider() calls
+ // and the MemoryDumpManager guarantees to support this.
+ // On the other side, the MemoryDumpManager will not be fully operational
+ // (i.e. will NACK any RequestGlobalMemoryDump()) until initialized.
+ // Arguments:
+ // is_coordinator: if true this MemoryDumpManager instance will act as a
+ // coordinator and schedule periodic dumps (if enabled via TraceConfig);
+ // false when the MemoryDumpManager is initialized in a slave process.
+ // delegate: inversion-of-control interface for embedder-specific behaviors
+ // (multiprocess handshaking). See the lifetime and thread-safety
+ // requirements in the |MemoryDumpManagerDelegate| docstring.
+ void Initialize(MemoryDumpManagerDelegate* delegate, bool is_coordinator);
+
+ // (Un)Registers a MemoryDumpProvider instance.
+ // Args:
+ // - mdp: the MemoryDumpProvider instance to be registered. MemoryDumpManager
+ // does NOT take memory ownership of |mdp|, which is expected to either
+ // be a singleton or unregister itself.
+ // - name: a friendly name (duplicates allowed). Used for debugging and
+ // run-time profiling of memory-infra internals. Must be a long-lived
+ // C string.
+ // - task_runner: if non-null, all the calls to |mdp| will be
+ // issued on the given thread. Otherwise, |mdp| should be able to
+ // handle calls on arbitrary threads.
+ // - options: extra optional arguments. See memory_dump_provider.h.
void RegisterDumpProvider(
MemoryDumpProvider* mdp,
+ const char* name,
const scoped_refptr<SingleThreadTaskRunner>& task_runner);
- void RegisterDumpProvider(MemoryDumpProvider* mdp);
+ void RegisterDumpProvider(
+ MemoryDumpProvider* mdp,
+ const char* name,
+ const scoped_refptr<SingleThreadTaskRunner>& task_runner,
+ const MemoryDumpProvider::Options& options);
void UnregisterDumpProvider(MemoryDumpProvider* mdp);
+ // Unregisters an unbound dump provider and takes care about its deletion
+ // asynchronously. Can be used only for for dump providers with no
+ // task-runner affinity.
+ // This method takes ownership of the dump provider and guarantees that:
+ // - The |mdp| will be deleted at some point in the near future.
+ // - Its deletion will not happen concurrently with the OnMemoryDump() call.
+ // Note that OnMemoryDump() calls can still happen after this method returns.
+ void UnregisterAndDeleteDumpProviderSoon(scoped_ptr<MemoryDumpProvider> mdp);
+
// Requests a memory dump. The dump might happen or not depending on the
// filters and categories specified when enabling tracing.
// The optional |callback| is executed asynchronously, on an arbitrary thread,
@@ -65,10 +100,12 @@ class BASE_EXPORT MemoryDumpManager : public TraceLog::EnabledStateObserver {
// processes have dumped) and its success (true iff all the dumps were
// successful).
void RequestGlobalDump(MemoryDumpType dump_type,
+ MemoryDumpLevelOfDetail level_of_detail,
const MemoryDumpCallback& callback);
// Same as above (still asynchronous), but without callback.
- void RequestGlobalDump(MemoryDumpType dump_type);
+ void RequestGlobalDump(MemoryDumpType dump_type,
+ MemoryDumpLevelOfDetail level_of_detail);
// TraceLog::EnabledStateObserver implementation.
void OnTraceLogEnabled() override;
@@ -81,27 +118,151 @@ class BASE_EXPORT MemoryDumpManager : public TraceLog::EnabledStateObserver {
return session_state_;
}
+ // Returns a unique id for identifying the processes. The id can be
+ // retrieved by child processes only when tracing is enabled. This is
+ // intended to express cross-process sharing of memory dumps on the
+ // child-process side, without having to know its own child process id.
+ uint64_t GetTracingProcessId() const;
+
+ // Returns the name for a the allocated_objects dump. Use this to declare
+ // suballocator dumps from other dump providers.
+ // It will return nullptr if there is no dump provider for the system
+ // allocator registered (which is currently the case for Mac OS).
+ const char* system_allocator_pool_name() const {
+ return kSystemAllocatorPoolName;
+ };
+
+ // When set to true, calling |RegisterMemoryDumpProvider| is a no-op.
+ void set_dumper_registrations_ignored_for_testing(bool ignored) {
+ dumper_registrations_ignored_for_testing_ = ignored;
+ }
+
private:
- // Descriptor struct used to hold information about registered MDPs. It is
- // deliberately copyable, in order to allow to be used as hash_map value.
- struct MemoryDumpProviderInfo {
+ friend std::default_delete<MemoryDumpManager>; // For the testing instance.
+ friend struct DefaultSingletonTraits<MemoryDumpManager>;
+ friend class MemoryDumpManagerDelegate;
+ friend class MemoryDumpManagerTest;
+
+ // Descriptor used to hold information about registered MDPs.
+ // Some important considerations about lifetime of this object:
+ // - In nominal conditions, all the MemoryDumpProviderInfo instances live in
+ // the |dump_providers_| collection (% unregistration while dumping).
+ // - Upon each dump they (actually their scoped_refptr-s) are copied into
+ // the ProcessMemoryDumpAsyncState. This is to allow removal (see below).
+ // - When the MDP.OnMemoryDump() is invoked, the corresponding MDPInfo copy
+ // inside ProcessMemoryDumpAsyncState is removed.
+ // - In most cases, the MDPInfo is destroyed within UnregisterDumpProvider().
+ // - If UnregisterDumpProvider() is called while a dump is in progress, the
+ // MDPInfo is destroyed in the epilogue of ContinueAsyncProcessDump(), when
+ // the copy inside ProcessMemoryDumpAsyncState is erase()-d.
+ // - The non-const fields of MemoryDumpProviderInfo are safe to access only
+ // in the |task_runner| thread, unless the thread has been destroyed.
+ struct MemoryDumpProviderInfo
+ : public RefCountedThreadSafe<MemoryDumpProviderInfo> {
+ // Define a total order based on the thread (i.e. |task_runner|) affinity,
+ // so that all MDP belonging to the same thread are adjacent in the set.
+ struct Comparator {
+ bool operator()(const scoped_refptr<MemoryDumpProviderInfo>& a,
+ const scoped_refptr<MemoryDumpProviderInfo>& b) const;
+ };
+ using OrderedSet =
+ std::set<scoped_refptr<MemoryDumpProviderInfo>, Comparator>;
+
MemoryDumpProviderInfo(
- const scoped_refptr<SingleThreadTaskRunner>& task_runner);
+ MemoryDumpProvider* dump_provider,
+ const char* name,
+ const scoped_refptr<SingleThreadTaskRunner>& task_runner,
+ const MemoryDumpProvider::Options& options);
+
+ MemoryDumpProvider* const dump_provider;
+
+ // Used to transfer ownership for UnregisterAndDeleteDumpProviderSoon().
+ // nullptr in all other cases.
+ scoped_ptr<MemoryDumpProvider> owned_dump_provider;
+
+ // Human readable name, for debugging and testing. Not necessarily unique.
+ const char* const name;
+
+ // The task_runner affinity. Can be nullptr, in which case the dump provider
+ // will be invoked on |dump_thread_|.
+ const scoped_refptr<SingleThreadTaskRunner> task_runner;
+
+ // The |options| arg passed to RegisterDumpProvider().
+ const MemoryDumpProvider::Options options;
+
+ // For fail-safe logic (auto-disable failing MDPs).
+ int consecutive_failures;
+
+ // Flagged either by the auto-disable logic or during unregistration.
+ bool disabled;
+
+ private:
+ friend class base::RefCountedThreadSafe<MemoryDumpProviderInfo>;
~MemoryDumpProviderInfo();
- scoped_refptr<SingleThreadTaskRunner> task_runner; // Optional.
- bool disabled; // For fail-safe logic (auto-disable failing MDPs).
+ DISALLOW_COPY_AND_ASSIGN(MemoryDumpProviderInfo);
};
- friend struct DefaultDeleter<MemoryDumpManager>; // For the testing instance.
- friend struct DefaultSingletonTraits<MemoryDumpManager>;
- friend class MemoryDumpManagerDelegate;
- friend class MemoryDumpManagerTest;
+ // Holds the state of a process memory dump that needs to be carried over
+ // across threads in order to fulfil an asynchronous CreateProcessDump()
+ // request. At any time exactly one thread owns a ProcessMemoryDumpAsyncState.
+ struct ProcessMemoryDumpAsyncState {
+ ProcessMemoryDumpAsyncState(
+ MemoryDumpRequestArgs req_args,
+ const MemoryDumpProviderInfo::OrderedSet& dump_providers,
+ const scoped_refptr<MemoryDumpSessionState>& session_state,
+ MemoryDumpCallback callback,
+ const scoped_refptr<SingleThreadTaskRunner>& dump_thread_task_runner);
+ ~ProcessMemoryDumpAsyncState();
+
+ // Gets or creates the memory dump container for the given target process.
+ ProcessMemoryDump* GetOrCreateMemoryDumpContainerForProcess(ProcessId pid);
+
+ // A map of ProcessId -> ProcessMemoryDump, one for each target process
+ // being dumped from the current process. Typically each process dumps only
+ // for itself, unless dump providers specify a different |target_process| in
+ // MemoryDumpProvider::Options.
+ std::map<ProcessId, scoped_ptr<ProcessMemoryDump>> process_dumps;
+
+ // The arguments passed to the initial CreateProcessDump() request.
+ const MemoryDumpRequestArgs req_args;
+
+ // An ordered sequence of dump providers that have to be invoked to complete
+ // the dump. This is a copy of |dump_providers_| at the beginning of a dump
+ // and becomes empty at the end, when all dump providers have been invoked.
+ std::vector<scoped_refptr<MemoryDumpProviderInfo>> pending_dump_providers;
+
+ // The trace-global session state.
+ scoped_refptr<MemoryDumpSessionState> session_state;
+
+ // Callback passed to the initial call to CreateProcessDump().
+ MemoryDumpCallback callback;
+
+ // The thread on which FinalizeDumpAndAddToTrace() (and hence |callback|)
+ // should be invoked. This is the thread on which the initial
+ // CreateProcessDump() request was called.
+ const scoped_refptr<SingleThreadTaskRunner> callback_task_runner;
+
+ // The thread on which unbound dump providers should be invoked.
+ // This is essentially |dump_thread_|.task_runner() but needs to be kept
+ // as a separate variable as it needs to be accessed by arbitrary dumpers'
+ // threads outside of the lock_ to avoid races when disabling tracing.
+ // It is immutable for all the duration of a tracing session.
+ const scoped_refptr<SingleThreadTaskRunner> dump_thread_task_runner;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ProcessMemoryDumpAsyncState);
+ };
- static void SetInstanceForTesting(MemoryDumpManager* instance);
+ static const int kMaxConsecutiveFailuresCount;
+ static const char* const kSystemAllocatorPoolName;
MemoryDumpManager();
- virtual ~MemoryDumpManager();
+ ~MemoryDumpManager() override;
+
+ static void SetInstanceForTesting(MemoryDumpManager* instance);
+ static void FinalizeDumpAndAddToTrace(
+ scoped_ptr<ProcessMemoryDumpAsyncState> pmd_async_state);
// Internal, used only by MemoryDumpManagerDelegate.
// Creates a memory dump for the current process and appends it to the trace.
@@ -110,19 +271,27 @@ class BASE_EXPORT MemoryDumpManager : public TraceLog::EnabledStateObserver {
void CreateProcessDump(const MemoryDumpRequestArgs& args,
const MemoryDumpCallback& callback);
- bool InvokeDumpProviderLocked(MemoryDumpProvider* mdp,
- ProcessMemoryDump* pmd);
+ // Continues the ProcessMemoryDump started by CreateProcessDump(), hopping
+ // across threads as needed as specified by MDPs in RegisterDumpProvider().
void ContinueAsyncProcessDump(
- MemoryDumpProvider* mdp,
- scoped_refptr<ProcessMemoryDumpHolder> pmd_holder);
+ ProcessMemoryDumpAsyncState* owned_pmd_async_state);
+
+ // Helper for the public UnregisterDumpProvider* functions.
+ void UnregisterDumpProviderInternal(MemoryDumpProvider* mdp,
+ bool take_mdp_ownership_and_delete_async);
- hash_map<MemoryDumpProvider*, MemoryDumpProviderInfo> dump_providers_;
+ // An ordererd set of registered MemoryDumpProviderInfo(s), sorted by thread
+ // affinity (MDPs belonging to the same thread are adjacent).
+ MemoryDumpProviderInfo::OrderedSet dump_providers_;
// Shared among all the PMDs to keep state scoped to the tracing session.
scoped_refptr<MemoryDumpSessionState> session_state_;
MemoryDumpManagerDelegate* delegate_; // Not owned.
+ // When true, this instance is in charge of coordinating periodic dumps.
+ bool is_coordinator_;
+
// Protects from concurrent accesses to the |dump_providers_*| and |delegate_|
// to guard against disabling logging while dumping on another thread.
Lock lock_;
@@ -132,10 +301,20 @@ class BASE_EXPORT MemoryDumpManager : public TraceLog::EnabledStateObserver {
subtle::AtomicWord memory_tracing_enabled_;
// For time-triggered periodic dumps.
- RepeatingTimer<MemoryDumpManager> periodic_dump_timer_;
+ RepeatingTimer periodic_dump_timer_;
+
+ // Thread used for MemoryDumpProviders which don't specify a thread affinity.
+ scoped_ptr<Thread> dump_thread_;
+
+ // The unique id of the child process. This is created only for tracing and is
+ // expected to be valid only when tracing is enabled.
+ uint64_t tracing_process_id_;
+
+ // When true, calling |RegisterMemoryDumpProvider| is a no-op.
+ bool dumper_registrations_ignored_for_testing_;
- // Skips the auto-registration of the core dumpers during Initialize().
- bool skip_core_dumpers_auto_registration_for_testing_;
+ // Whether new memory dump providers should be told to enable heap profiling.
+ bool heap_profiling_enabled_;
DISALLOW_COPY_AND_ASSIGN(MemoryDumpManager);
};
@@ -147,9 +326,9 @@ class BASE_EXPORT MemoryDumpManagerDelegate {
virtual void RequestGlobalMemoryDump(const MemoryDumpRequestArgs& args,
const MemoryDumpCallback& callback) = 0;
- // Determines whether the MemoryDumpManager instance should be the master
- // (the ones which initiates and coordinates the multiprocess dumps) or not.
- virtual bool IsCoordinatorProcess() const = 0;
+ // Returns tracing process id of the current process. This is used by
+ // MemoryDumpManager::GetTracingProcessId.
+ virtual uint64_t GetTracingProcessId() const = 0;
protected:
MemoryDumpManagerDelegate() {}
diff --git a/base/trace_event/memory_dump_manager_unittest.cc b/base/trace_event/memory_dump_manager_unittest.cc
index 3112615c79..03b3afa32e 100644
--- a/base/trace_event/memory_dump_manager_unittest.cc
+++ b/base/trace_event/memory_dump_manager_unittest.cc
@@ -4,238 +4,419 @@
#include "base/trace_event/memory_dump_manager.h"
+#include <stdint.h>
+
+#include <vector>
+
#include "base/bind_helpers.h"
-#include "base/memory/scoped_vector.h"
+#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
+#include "base/strings/stringprintf.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/test/test_io_thread.h"
+#include "base/test/trace_event_analyzer.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/platform_thread.h"
#include "base/threading/thread.h"
#include "base/trace_event/memory_dump_provider.h"
#include "base/trace_event/process_memory_dump.h"
+#include "base/trace_event/trace_buffer.h"
+#include "base/trace_event/trace_config_memory_test_util.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::_;
+using testing::AnyNumber;
+using testing::AtMost;
+using testing::Between;
using testing::Invoke;
using testing::Return;
namespace base {
namespace trace_event {
-// Testing MemoryDumpManagerDelegate which short-circuits dump requests locally
-// instead of performing IPC dances.
+// GTest matchers for MemoryDumpRequestArgs arguments.
+MATCHER(IsDetailedDump, "") {
+ return arg.level_of_detail == MemoryDumpLevelOfDetail::DETAILED;
+}
+
+MATCHER(IsLightDump, "") {
+ return arg.level_of_detail == MemoryDumpLevelOfDetail::LIGHT;
+}
+
+namespace {
+
+void RegisterDumpProvider(
+ MemoryDumpProvider* mdp,
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+ const MemoryDumpProvider::Options& options) {
+ MemoryDumpManager* mdm = MemoryDumpManager::GetInstance();
+ mdm->set_dumper_registrations_ignored_for_testing(false);
+ mdm->RegisterDumpProvider(mdp, "TestDumpProvider", task_runner, options);
+ mdm->set_dumper_registrations_ignored_for_testing(true);
+}
+
+void RegisterDumpProvider(MemoryDumpProvider* mdp) {
+ RegisterDumpProvider(mdp, nullptr, MemoryDumpProvider::Options());
+}
+
+void OnTraceDataCollected(Closure quit_closure,
+ trace_event::TraceResultBuffer* buffer,
+ const scoped_refptr<RefCountedString>& json,
+ bool has_more_events) {
+ buffer->AddFragment(json->data());
+ if (!has_more_events)
+ quit_closure.Run();
+}
+
+} // namespace
+
+// Testing MemoryDumpManagerDelegate which, by default, short-circuits dump
+// requests locally to the MemoryDumpManager instead of performing IPC dances.
class MemoryDumpManagerDelegateForTesting : public MemoryDumpManagerDelegate {
public:
- void RequestGlobalMemoryDump(
- const base::trace_event::MemoryDumpRequestArgs& args,
- const MemoryDumpCallback& callback) override {
- CreateProcessDump(args, callback);
+ MemoryDumpManagerDelegateForTesting() {
+ ON_CALL(*this, RequestGlobalMemoryDump(_, _))
+ .WillByDefault(Invoke(
+ this, &MemoryDumpManagerDelegateForTesting::CreateProcessDump));
}
- bool IsCoordinatorProcess() const override { return false; }
+ MOCK_METHOD2(RequestGlobalMemoryDump,
+ void(const MemoryDumpRequestArgs& args,
+ const MemoryDumpCallback& callback));
+
+ uint64_t GetTracingProcessId() const override {
+ NOTREACHED();
+ return MemoryDumpManager::kInvalidTracingProcessId;
+ }
+};
+
+class MockMemoryDumpProvider : public MemoryDumpProvider {
+ public:
+ MOCK_METHOD0(Destructor, void());
+ MOCK_METHOD2(OnMemoryDump,
+ bool(const MemoryDumpArgs& args, ProcessMemoryDump* pmd));
+
+ MockMemoryDumpProvider() : enable_mock_destructor(false) {}
+ ~MockMemoryDumpProvider() override {
+ if (enable_mock_destructor)
+ Destructor();
+ }
+
+ bool enable_mock_destructor;
};
class MemoryDumpManagerTest : public testing::Test {
public:
+ MemoryDumpManagerTest() : testing::Test(), kDefaultOptions() {}
+
void SetUp() override {
+ last_callback_success_ = false;
message_loop_.reset(new MessageLoop());
mdm_.reset(new MemoryDumpManager());
MemoryDumpManager::SetInstanceForTesting(mdm_.get());
- ASSERT_EQ(mdm_, MemoryDumpManager::GetInstance());
- MemoryDumpManager::GetInstance()->Initialize();
- MemoryDumpManager::GetInstance()->SetDelegate(&delegate_);
+ ASSERT_EQ(mdm_.get(), MemoryDumpManager::GetInstance());
+ delegate_.reset(new MemoryDumpManagerDelegateForTesting);
}
void TearDown() override {
MemoryDumpManager::SetInstanceForTesting(nullptr);
mdm_.reset();
+ delegate_.reset();
message_loop_.reset();
TraceLog::DeleteForTesting();
}
+ // Turns a Closure into a MemoryDumpCallback, keeping track of the callback
+ // result and taking care of posting the closure on the correct task runner.
void DumpCallbackAdapter(scoped_refptr<SingleThreadTaskRunner> task_runner,
Closure closure,
- uint64 dump_guid,
+ uint64_t dump_guid,
bool success) {
+ last_callback_success_ = success;
task_runner->PostTask(FROM_HERE, closure);
}
protected:
- const char* kTraceCategory = MemoryDumpManager::kTraceCategoryForTesting;
+ void InitializeMemoryDumpManager(bool is_coordinator) {
+ mdm_->set_dumper_registrations_ignored_for_testing(true);
+ mdm_->Initialize(delegate_.get(), is_coordinator);
+ }
- void EnableTracing(const char* category) {
- TraceLog::GetInstance()->SetEnabled(
- TraceConfig(category, ""), TraceLog::RECORDING_MODE);
+ void RequestGlobalDumpAndWait(MemoryDumpType dump_type,
+ MemoryDumpLevelOfDetail level_of_detail) {
+ RunLoop run_loop;
+ MemoryDumpCallback callback =
+ Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this),
+ MessageLoop::current()->task_runner(), run_loop.QuitClosure());
+ mdm_->RequestGlobalDump(dump_type, level_of_detail, callback);
+ run_loop.Run();
+ }
+
+ void EnableTracingWithLegacyCategories(const char* category) {
+ TraceLog::GetInstance()->SetEnabled(TraceConfig(category, ""),
+ TraceLog::RECORDING_MODE);
+ }
+
+ void EnableTracingWithTraceConfig(const std::string& trace_config) {
+ TraceLog::GetInstance()->SetEnabled(TraceConfig(trace_config),
+ TraceLog::RECORDING_MODE);
}
void DisableTracing() { TraceLog::GetInstance()->SetDisabled(); }
+ bool IsPeriodicDumpingEnabled() const {
+ return mdm_->periodic_dump_timer_.IsRunning();
+ }
+
+ int GetMaxConsecutiveFailuresCount() const {
+ return MemoryDumpManager::kMaxConsecutiveFailuresCount;
+ }
+
+ const MemoryDumpProvider::Options kDefaultOptions;
scoped_ptr<MemoryDumpManager> mdm_;
+ scoped_ptr<MemoryDumpManagerDelegateForTesting> delegate_;
+ bool last_callback_success_;
private:
scoped_ptr<MessageLoop> message_loop_;
- MemoryDumpManagerDelegateForTesting delegate_;
// We want our singleton torn down after each test.
ShadowingAtExitManager at_exit_manager_;
};
-class MockDumpProvider : public MemoryDumpProvider {
- public:
- MockDumpProvider() : last_session_state_(nullptr) {}
-
- // Ctor used by the RespectTaskRunnerAffinity test.
- explicit MockDumpProvider(
- const scoped_refptr<SingleThreadTaskRunner>& task_runner)
- : last_session_state_(nullptr), task_runner_(task_runner) {}
-
- virtual ~MockDumpProvider() {}
-
- MOCK_METHOD1(OnMemoryDump, bool(ProcessMemoryDump* pmd));
-
- // OnMemoryDump() override for the RespectTaskRunnerAffinity test.
- bool OnMemoryDump_CheckTaskRunner(ProcessMemoryDump* pmd) {
- EXPECT_TRUE(task_runner_->RunsTasksOnCurrentThread());
- return true;
- }
-
- // OnMemoryDump() override for the SharedSessionState test.
- bool OnMemoryDump_CheckSessionState(ProcessMemoryDump* pmd) {
- MemoryDumpSessionState* cur_session_state = pmd->session_state().get();
- if (last_session_state_)
- EXPECT_EQ(last_session_state_, cur_session_state);
- last_session_state_ = cur_session_state;
- return true;
- }
-
- private:
- MemoryDumpSessionState* last_session_state_;
- scoped_refptr<SingleThreadTaskRunner> task_runner_;
-};
-
+// Basic sanity checks. Registers a memory dump provider and checks that it is
+// called, but only when memory-infra is enabled.
TEST_F(MemoryDumpManagerTest, SingleDumper) {
- MockDumpProvider mdp;
- mdm_->RegisterDumpProvider(&mdp);
+ InitializeMemoryDumpManager(false /* is_coordinator */);
+ MockMemoryDumpProvider mdp;
+ RegisterDumpProvider(&mdp);
// Check that the dumper is not called if the memory category is not enabled.
- EnableTracing("foo-and-bar-but-not-memory");
- EXPECT_CALL(mdp, OnMemoryDump(_)).Times(0);
- mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+ EnableTracingWithLegacyCategories("foobar-but-not-memory");
+ EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(0);
+ EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
DisableTracing();
// Now repeat enabling the memory category and check that the dumper is
// invoked this time.
- EnableTracing(kTraceCategory);
- EXPECT_CALL(mdp, OnMemoryDump(_)).Times(3).WillRepeatedly(Return(true));
+ EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+ EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(3);
+ EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(3).WillRepeatedly(Return(true));
for (int i = 0; i < 3; ++i)
- mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
DisableTracing();
mdm_->UnregisterDumpProvider(&mdp);
- // Finally check the unregister logic (no calls to the mdp after unregister).
- EnableTracing(kTraceCategory);
- EXPECT_CALL(mdp, OnMemoryDump(_)).Times(0);
- mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
- TraceLog::GetInstance()->SetDisabled();
+ // Finally check the unregister logic: the delegate will be invoked but not
+ // the dump provider, as it has been unregistered.
+ EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+ EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(3);
+ EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
+
+ for (int i = 0; i < 3; ++i) {
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
+ }
+ DisableTracing();
}
-TEST_F(MemoryDumpManagerTest, SharedSessionState) {
- MockDumpProvider mdp1;
- MockDumpProvider mdp2;
- mdm_->RegisterDumpProvider(&mdp1);
- mdm_->RegisterDumpProvider(&mdp2);
+// Checks that requesting dumps with high level of detail actually propagates
+// the level of the detail properly to OnMemoryDump() call on dump providers.
+TEST_F(MemoryDumpManagerTest, CheckMemoryDumpArgs) {
+ InitializeMemoryDumpManager(false /* is_coordinator */);
+ MockMemoryDumpProvider mdp;
+
+ RegisterDumpProvider(&mdp);
+ EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+ EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+ EXPECT_CALL(mdp, OnMemoryDump(IsDetailedDump(), _)).WillOnce(Return(true));
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
+ DisableTracing();
+ mdm_->UnregisterDumpProvider(&mdp);
+
+ // Check that requesting dumps with low level of detail actually propagates to
+ // OnMemoryDump() call on dump providers.
+ RegisterDumpProvider(&mdp);
+ EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+ EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+ EXPECT_CALL(mdp, OnMemoryDump(IsLightDump(), _)).WillOnce(Return(true));
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::LIGHT);
+ DisableTracing();
+ mdm_->UnregisterDumpProvider(&mdp);
+}
- EnableTracing(kTraceCategory);
- EXPECT_CALL(mdp1, OnMemoryDump(_))
+// Checks that the SharedSessionState object is acqually shared over time.
+TEST_F(MemoryDumpManagerTest, SharedSessionState) {
+ InitializeMemoryDumpManager(false /* is_coordinator */);
+ MockMemoryDumpProvider mdp1;
+ MockMemoryDumpProvider mdp2;
+ RegisterDumpProvider(&mdp1);
+ RegisterDumpProvider(&mdp2);
+
+ EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+ const MemoryDumpSessionState* session_state = mdm_->session_state().get();
+ EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(2);
+ EXPECT_CALL(mdp1, OnMemoryDump(_, _))
.Times(2)
- .WillRepeatedly(
- Invoke(&mdp1, &MockDumpProvider::OnMemoryDump_CheckSessionState));
- EXPECT_CALL(mdp2, OnMemoryDump(_))
+ .WillRepeatedly(Invoke([session_state](const MemoryDumpArgs&,
+ ProcessMemoryDump* pmd) -> bool {
+ EXPECT_EQ(session_state, pmd->session_state().get());
+ return true;
+ }));
+ EXPECT_CALL(mdp2, OnMemoryDump(_, _))
.Times(2)
- .WillRepeatedly(
- Invoke(&mdp2, &MockDumpProvider::OnMemoryDump_CheckSessionState));
-
- for (int i = 0; i < 2; ++i)
- mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+ .WillRepeatedly(Invoke([session_state](const MemoryDumpArgs&,
+ ProcessMemoryDump* pmd) -> bool {
+ EXPECT_EQ(session_state, pmd->session_state().get());
+ return true;
+ }));
+
+ for (int i = 0; i < 2; ++i) {
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
+ }
DisableTracing();
}
+// Checks that the (Un)RegisterDumpProvider logic behaves sanely.
TEST_F(MemoryDumpManagerTest, MultipleDumpers) {
- MockDumpProvider mdp1;
- MockDumpProvider mdp2;
+ InitializeMemoryDumpManager(false /* is_coordinator */);
+ MockMemoryDumpProvider mdp1;
+ MockMemoryDumpProvider mdp2;
// Enable only mdp1.
- mdm_->RegisterDumpProvider(&mdp1);
- EnableTracing(kTraceCategory);
- EXPECT_CALL(mdp1, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(true));
- EXPECT_CALL(mdp2, OnMemoryDump(_)).Times(0);
- mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+ RegisterDumpProvider(&mdp1);
+ EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+ EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+ EXPECT_CALL(mdp1, OnMemoryDump(_, _)).WillOnce(Return(true));
+ EXPECT_CALL(mdp2, OnMemoryDump(_, _)).Times(0);
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
DisableTracing();
// Invert: enable mdp1 and disable mdp2.
mdm_->UnregisterDumpProvider(&mdp1);
- mdm_->RegisterDumpProvider(&mdp2);
- EnableTracing(kTraceCategory);
- EXPECT_CALL(mdp1, OnMemoryDump(_)).Times(0);
- EXPECT_CALL(mdp2, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(true));
- mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+ RegisterDumpProvider(&mdp2);
+ EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+ EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+ EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(0);
+ EXPECT_CALL(mdp2, OnMemoryDump(_, _)).WillOnce(Return(true));
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
DisableTracing();
// Enable both mdp1 and mdp2.
- mdm_->RegisterDumpProvider(&mdp1);
- EnableTracing(kTraceCategory);
- EXPECT_CALL(mdp1, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(true));
- EXPECT_CALL(mdp2, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(true));
- mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+ RegisterDumpProvider(&mdp1);
+ EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+ EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+ EXPECT_CALL(mdp1, OnMemoryDump(_, _)).WillOnce(Return(true));
+ EXPECT_CALL(mdp2, OnMemoryDump(_, _)).WillOnce(Return(true));
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
DisableTracing();
}
-// Fails on Linux TSan. http://crbug.com/499983
-#if defined(OS_LINUX)
-#define MAYBE_RespectTaskRunnerAffinity DISABLED_RespectTaskRunnerAffinity
-#else
-#define MAYBE_RespectTaskRunnerAffinity RespectTaskRunnerAffinity
-#endif
+// Checks that the dump provider invocations depend only on the current
+// registration state and not on previous registrations and dumps.
+TEST_F(MemoryDumpManagerTest, RegistrationConsistency) {
+ InitializeMemoryDumpManager(false /* is_coordinator */);
+ MockMemoryDumpProvider mdp;
+
+ RegisterDumpProvider(&mdp);
+
+ {
+ EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+ EXPECT_CALL(mdp, OnMemoryDump(_, _)).WillOnce(Return(true));
+ EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
+ DisableTracing();
+ }
+
+ mdm_->UnregisterDumpProvider(&mdp);
+
+ {
+ EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+ EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
+ EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
+ DisableTracing();
+ }
+
+ RegisterDumpProvider(&mdp);
+ mdm_->UnregisterDumpProvider(&mdp);
+
+ {
+ EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+ EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
+ EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
+ DisableTracing();
+ }
+
+ RegisterDumpProvider(&mdp);
+ mdm_->UnregisterDumpProvider(&mdp);
+ RegisterDumpProvider(&mdp);
+
+ {
+ EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+ EXPECT_CALL(mdp, OnMemoryDump(_, _)).WillOnce(Return(true));
+ EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
+ DisableTracing();
+ }
+}
// Checks that the MemoryDumpManager respects the thread affinity when a
// MemoryDumpProvider specifies a task_runner(). The test starts creating 8
// threads and registering a MemoryDumpProvider on each of them. At each
// iteration, one thread is removed, to check the live unregistration logic.
-TEST_F(MemoryDumpManagerTest, MAYBE_RespectTaskRunnerAffinity) {
- const uint32 kNumInitialThreads = 8;
+TEST_F(MemoryDumpManagerTest, RespectTaskRunnerAffinity) {
+ InitializeMemoryDumpManager(false /* is_coordinator */);
+ const uint32_t kNumInitialThreads = 8;
- ScopedVector<Thread> threads;
- ScopedVector<MockDumpProvider> mdps;
+ std::vector<scoped_ptr<Thread>> threads;
+ std::vector<scoped_ptr<MockMemoryDumpProvider>> mdps;
// Create the threads and setup the expectations. Given that at each iteration
// we will pop out one thread/MemoryDumpProvider, each MDP is supposed to be
// invoked a number of times equal to its index.
- for (uint32 i = kNumInitialThreads; i > 0; --i) {
- threads.push_back(new Thread("test thread"));
- threads.back()->Start();
- mdps.push_back(new MockDumpProvider(threads.back()->task_runner()));
- MockDumpProvider* mdp = mdps.back();
- mdm_->RegisterDumpProvider(mdp, threads.back()->task_runner());
- EXPECT_CALL(*mdp, OnMemoryDump(_))
+ for (uint32_t i = kNumInitialThreads; i > 0; --i) {
+ threads.push_back(make_scoped_ptr(new Thread("test thread")));
+ auto thread = threads.back().get();
+ thread->Start();
+ scoped_refptr<SingleThreadTaskRunner> task_runner = thread->task_runner();
+ mdps.push_back(make_scoped_ptr(new MockMemoryDumpProvider()));
+ auto mdp = mdps.back().get();
+ RegisterDumpProvider(mdp, task_runner, kDefaultOptions);
+ EXPECT_CALL(*mdp, OnMemoryDump(_, _))
.Times(i)
- .WillRepeatedly(
- Invoke(mdp, &MockDumpProvider::OnMemoryDump_CheckTaskRunner));
+ .WillRepeatedly(Invoke(
+ [task_runner](const MemoryDumpArgs&, ProcessMemoryDump*) -> bool {
+ EXPECT_TRUE(task_runner->RunsTasksOnCurrentThread());
+ return true;
+ }));
}
-
- EnableTracing(kTraceCategory);
+ EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
while (!threads.empty()) {
- {
- RunLoop run_loop;
- MemoryDumpCallback callback =
- Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this),
- MessageLoop::current()->task_runner(), run_loop.QuitClosure());
- mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, callback);
- // This nested message loop (|run_loop|) will be quit if and only if
- // the RequestGlobalDump callback is invoked.
- run_loop.Run();
- }
+ last_callback_success_ = false;
+ EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
+ EXPECT_TRUE(last_callback_success_);
// Unregister a MDP and destroy one thread at each iteration to check the
// live unregistration logic. The unregistration needs to happen on the same
@@ -244,7 +425,7 @@ TEST_F(MemoryDumpManagerTest, MAYBE_RespectTaskRunnerAffinity) {
RunLoop run_loop;
Closure unregistration =
Bind(&MemoryDumpManager::UnregisterDumpProvider,
- Unretained(mdm_.get()), Unretained(mdps.back()));
+ Unretained(mdm_.get()), Unretained(mdps.back().get()));
threads.back()->task_runner()->PostTaskAndReply(FROM_HERE, unregistration,
run_loop.QuitClosure());
run_loop.Run();
@@ -257,25 +438,519 @@ TEST_F(MemoryDumpManagerTest, MAYBE_RespectTaskRunnerAffinity) {
DisableTracing();
}
-// Enable both dump providers, make mdp1 fail and assert that only mdp2 is
-// invoked the 2nd time.
-// FIXME(primiano): remove once crbug.com/461788 gets fixed.
+// Checks that providers get disabled after 3 consecutive failures, but not
+// otherwise (e.g., if interleaved).
TEST_F(MemoryDumpManagerTest, DisableFailingDumpers) {
- MockDumpProvider mdp1;
- MockDumpProvider mdp2;
+ InitializeMemoryDumpManager(false /* is_coordinator */);
+ MockMemoryDumpProvider mdp1;
+ MockMemoryDumpProvider mdp2;
+
+ RegisterDumpProvider(&mdp1);
+ RegisterDumpProvider(&mdp2);
+ EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+
+ const int kNumDumps = 2 * GetMaxConsecutiveFailuresCount();
+ EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(kNumDumps);
+
+ EXPECT_CALL(mdp1, OnMemoryDump(_, _))
+ .Times(GetMaxConsecutiveFailuresCount())
+ .WillRepeatedly(Return(false));
+
+ EXPECT_CALL(mdp2, OnMemoryDump(_, _))
+ .WillOnce(Return(false))
+ .WillOnce(Return(true))
+ .WillOnce(Return(false))
+ .WillOnce(Return(false))
+ .WillOnce(Return(true))
+ .WillOnce(Return(false));
+
+ for (int i = 0; i < kNumDumps; i++) {
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
+ }
+
+ DisableTracing();
+}
+
+// Sneakily registers an extra memory dump provider while an existing one is
+// dumping and expect it to take part in the already active tracing session.
+TEST_F(MemoryDumpManagerTest, RegisterDumperWhileDumping) {
+ InitializeMemoryDumpManager(false /* is_coordinator */);
+ MockMemoryDumpProvider mdp1;
+ MockMemoryDumpProvider mdp2;
+
+ RegisterDumpProvider(&mdp1);
+ EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+
+ EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(4);
+
+ EXPECT_CALL(mdp1, OnMemoryDump(_, _))
+ .Times(4)
+ .WillOnce(Return(true))
+ .WillOnce(
+ Invoke([&mdp2](const MemoryDumpArgs&, ProcessMemoryDump*) -> bool {
+ RegisterDumpProvider(&mdp2);
+ return true;
+ }))
+ .WillRepeatedly(Return(true));
+
+ // Depending on the insertion order (before or after mdp1), mdp2 might be
+ // called also immediately after it gets registered.
+ EXPECT_CALL(mdp2, OnMemoryDump(_, _))
+ .Times(Between(2, 3))
+ .WillRepeatedly(Return(true));
+
+ for (int i = 0; i < 4; i++) {
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
+ }
+
+ DisableTracing();
+}
+
+// Like RegisterDumperWhileDumping, but unregister the dump provider instead.
+TEST_F(MemoryDumpManagerTest, UnregisterDumperWhileDumping) {
+ InitializeMemoryDumpManager(false /* is_coordinator */);
+ MockMemoryDumpProvider mdp1;
+ MockMemoryDumpProvider mdp2;
+
+ RegisterDumpProvider(&mdp1, ThreadTaskRunnerHandle::Get(), kDefaultOptions);
+ RegisterDumpProvider(&mdp2, ThreadTaskRunnerHandle::Get(), kDefaultOptions);
+ EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+
+ EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(4);
+
+ EXPECT_CALL(mdp1, OnMemoryDump(_, _))
+ .Times(4)
+ .WillOnce(Return(true))
+ .WillOnce(
+ Invoke([&mdp2](const MemoryDumpArgs&, ProcessMemoryDump*) -> bool {
+ MemoryDumpManager::GetInstance()->UnregisterDumpProvider(&mdp2);
+ return true;
+ }))
+ .WillRepeatedly(Return(true));
+
+ // Depending on the insertion order (before or after mdp1), mdp2 might have
+ // been already called when UnregisterDumpProvider happens.
+ EXPECT_CALL(mdp2, OnMemoryDump(_, _))
+ .Times(Between(1, 2))
+ .WillRepeatedly(Return(true));
+
+ for (int i = 0; i < 4; i++) {
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
+ }
+
+ DisableTracing();
+}
+
+// Checks that the dump does not abort when unregistering a provider while
+// dumping from a different thread than the dumping thread.
+TEST_F(MemoryDumpManagerTest, UnregisterDumperFromThreadWhileDumping) {
+ InitializeMemoryDumpManager(false /* is_coordinator */);
+ std::vector<scoped_ptr<TestIOThread>> threads;
+ std::vector<scoped_ptr<MockMemoryDumpProvider>> mdps;
+
+ for (int i = 0; i < 2; i++) {
+ threads.push_back(
+ make_scoped_ptr(new TestIOThread(TestIOThread::kAutoStart)));
+ mdps.push_back(make_scoped_ptr(new MockMemoryDumpProvider()));
+ RegisterDumpProvider(mdps.back().get(), threads.back()->task_runner(),
+ kDefaultOptions);
+ }
+
+ int on_memory_dump_call_count = 0;
+
+ // When OnMemoryDump is called on either of the dump providers, it will
+ // unregister the other one.
+ for (const scoped_ptr<MockMemoryDumpProvider>& mdp : mdps) {
+ int other_idx = (mdps.front() == mdp);
+ TestIOThread* other_thread = threads[other_idx].get();
+ MockMemoryDumpProvider* other_mdp = mdps[other_idx].get();
+ auto on_dump = [this, other_thread, other_mdp, &on_memory_dump_call_count](
+ const MemoryDumpArgs& args, ProcessMemoryDump* pmd) {
+ other_thread->PostTaskAndWait(
+ FROM_HERE, base::Bind(&MemoryDumpManager::UnregisterDumpProvider,
+ base::Unretained(&*mdm_), other_mdp));
+ on_memory_dump_call_count++;
+ return true;
+ };
+
+ // OnMemoryDump is called once for the provider that dumps first, and zero
+ // times for the other provider.
+ EXPECT_CALL(*mdp, OnMemoryDump(_, _))
+ .Times(AtMost(1))
+ .WillOnce(Invoke(on_dump));
+ }
+
+ last_callback_success_ = false;
+ EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+ EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
+ ASSERT_EQ(1, on_memory_dump_call_count);
+ ASSERT_TRUE(last_callback_success_);
+
+ DisableTracing();
+}
+
+// If a thread (with a dump provider living on it) is torn down during a dump
+// its dump provider should be skipped but the dump itself should succeed.
+TEST_F(MemoryDumpManagerTest, TearDownThreadWhileDumping) {
+ InitializeMemoryDumpManager(false /* is_coordinator */);
+ std::vector<scoped_ptr<TestIOThread>> threads;
+ std::vector<scoped_ptr<MockMemoryDumpProvider>> mdps;
+
+ for (int i = 0; i < 2; i++) {
+ threads.push_back(
+ make_scoped_ptr(new TestIOThread(TestIOThread::kAutoStart)));
+ mdps.push_back(make_scoped_ptr(new MockMemoryDumpProvider()));
+ RegisterDumpProvider(mdps.back().get(), threads.back()->task_runner(),
+ kDefaultOptions);
+ }
+
+ int on_memory_dump_call_count = 0;
+
+ // When OnMemoryDump is called on either of the dump providers, it will
+ // tear down the thread of the other one.
+ for (const scoped_ptr<MockMemoryDumpProvider>& mdp : mdps) {
+ int other_idx = (mdps.front() == mdp);
+ TestIOThread* other_thread = threads[other_idx].get();
+ auto on_dump = [other_thread, &on_memory_dump_call_count](
+ const MemoryDumpArgs& args, ProcessMemoryDump* pmd) {
+ other_thread->Stop();
+ on_memory_dump_call_count++;
+ return true;
+ };
+
+ // OnMemoryDump is called once for the provider that dumps first, and zero
+ // times for the other provider.
+ EXPECT_CALL(*mdp, OnMemoryDump(_, _))
+ .Times(AtMost(1))
+ .WillOnce(Invoke(on_dump));
+ }
+
+ last_callback_success_ = false;
+ EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+ EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
+ ASSERT_EQ(1, on_memory_dump_call_count);
+ ASSERT_TRUE(last_callback_success_);
+
+ DisableTracing();
+}
+
+// Checks that a NACK callback is invoked if RequestGlobalDump() is called when
+// tracing is not enabled.
+TEST_F(MemoryDumpManagerTest, CallbackCalledOnFailure) {
+ InitializeMemoryDumpManager(false /* is_coordinator */);
+ MockMemoryDumpProvider mdp1;
+ RegisterDumpProvider(&mdp1);
+
+ EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(0);
+ EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(0);
+
+ last_callback_success_ = true;
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
+ EXPECT_FALSE(last_callback_success_);
+}
+
+// Checks that is the MemoryDumpManager is initialized after tracing already
+// began, it will still late-join the party (real use case: startup tracing).
+TEST_F(MemoryDumpManagerTest, InitializedAfterStartOfTracing) {
+ MockMemoryDumpProvider mdp;
+ RegisterDumpProvider(&mdp);
+ EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+
+ // First check that a RequestGlobalDump() issued before the MemoryDumpManager
+ // initialization gets NACK-ed cleanly.
+ {
+ EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
+ EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(0);
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
+ EXPECT_FALSE(last_callback_success_);
+ }
+
+ // Now late-initialize the MemoryDumpManager and check that the
+ // RequestGlobalDump completes successfully.
+ {
+ EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(1);
+ EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+ InitializeMemoryDumpManager(false /* is_coordinator */);
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
+ EXPECT_TRUE(last_callback_success_);
+ }
+ DisableTracing();
+}
+
+// This test (and the MemoryDumpManagerTestCoordinator below) crystallizes the
+// expectations of the chrome://tracing UI and chrome telemetry w.r.t. periodic
+// dumps in memory-infra, handling gracefully the transition between the legacy
+// and the new-style (JSON-based) TraceConfig.
+TEST_F(MemoryDumpManagerTest, TraceConfigExpectations) {
+ InitializeMemoryDumpManager(false /* is_coordinator */);
+ MemoryDumpManagerDelegateForTesting& delegate = *delegate_;
+
+ // Don't trigger the default behavior of the mock delegate in this test,
+ // which would short-circuit the dump request to the actual
+ // CreateProcessDump().
+ // We don't want to create any dump in this test, only check whether the dumps
+ // are requested or not.
+ ON_CALL(delegate, RequestGlobalMemoryDump(_, _)).WillByDefault(Return());
+
+ // Enabling memory-infra in a non-coordinator process should not trigger any
+ // periodic dumps.
+ EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+ EXPECT_FALSE(IsPeriodicDumpingEnabled());
+ DisableTracing();
+
+ // Enabling memory-infra with the new (JSON) TraceConfig in a non-coordinator
+ // process with a fully defined trigger config should NOT enable any periodic
+ // dumps.
+ EnableTracingWithTraceConfig(
+ TraceConfigMemoryTestUtil::GetTraceConfig_PeriodicTriggers(1, 5));
+ EXPECT_FALSE(IsPeriodicDumpingEnabled());
+ DisableTracing();
+}
+
+TEST_F(MemoryDumpManagerTest, TraceConfigExpectationsWhenIsCoordinator) {
+ InitializeMemoryDumpManager(true /* is_coordinator */);
+ MemoryDumpManagerDelegateForTesting& delegate = *delegate_;
+ ON_CALL(delegate, RequestGlobalMemoryDump(_, _)).WillByDefault(Return());
+
+ // Enabling memory-infra with the legacy TraceConfig (category filter) in
+ // a coordinator process should enable periodic dumps.
+ EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+ EXPECT_TRUE(IsPeriodicDumpingEnabled());
+ DisableTracing();
+
+ // Enabling memory-infra with the new (JSON) TraceConfig in a coordinator
+ // process without specifying any "memory_dump_config" section should enable
+ // periodic dumps. This is to preserve the behavior chrome://tracing UI, that
+ // is: ticking memory-infra should dump periodically with the default config.
+ EnableTracingWithTraceConfig(
+ TraceConfigMemoryTestUtil::GetTraceConfig_NoTriggers());
+ EXPECT_TRUE(IsPeriodicDumpingEnabled());
+ DisableTracing();
+
+ // Enabling memory-infra with the new (JSON) TraceConfig in a coordinator
+ // process with an empty "memory_dump_config" should NOT enable periodic
+ // dumps. This is the way telemetry is supposed to use memory-infra with
+ // only explicitly triggered dumps.
+ EnableTracingWithTraceConfig(
+ TraceConfigMemoryTestUtil::GetTraceConfig_EmptyTriggers());
+ EXPECT_FALSE(IsPeriodicDumpingEnabled());
+ DisableTracing();
+
+ // Enabling memory-infra with the new (JSON) TraceConfig in a coordinator
+ // process with a fully defined trigger config should cause periodic dumps to
+ // be performed in the correct order.
+ RunLoop run_loop;
+ auto quit_closure = run_loop.QuitClosure();
+
+ const int kHeavyDumpRate = 5;
+ const int kLightDumpPeriodMs = 1;
+ const int kHeavyDumpPeriodMs = kHeavyDumpRate * kLightDumpPeriodMs;
+ // The expected sequence with light=1ms, heavy=5ms is H,L,L,L,L,H,...
+ testing::InSequence sequence;
+ EXPECT_CALL(delegate, RequestGlobalMemoryDump(IsDetailedDump(), _));
+ EXPECT_CALL(delegate, RequestGlobalMemoryDump(IsLightDump(), _))
+ .Times(kHeavyDumpRate - 1);
+ EXPECT_CALL(delegate, RequestGlobalMemoryDump(IsDetailedDump(), _));
+ EXPECT_CALL(delegate, RequestGlobalMemoryDump(IsLightDump(), _))
+ .Times(kHeavyDumpRate - 2);
+ EXPECT_CALL(delegate, RequestGlobalMemoryDump(IsLightDump(), _))
+ .WillOnce(Invoke([quit_closure](const MemoryDumpRequestArgs& args,
+ const MemoryDumpCallback& callback) {
+ ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, quit_closure);
+ }));
+
+ // Swallow all the final spurious calls until tracing gets disabled.
+ EXPECT_CALL(delegate, RequestGlobalMemoryDump(_, _)).Times(AnyNumber());
+
+ EnableTracingWithTraceConfig(
+ TraceConfigMemoryTestUtil::GetTraceConfig_PeriodicTriggers(
+ kLightDumpPeriodMs, kHeavyDumpPeriodMs));
+ run_loop.Run();
+ DisableTracing();
+}
+
+// Tests against race conditions that might arise when disabling tracing in the
+// middle of a global memory dump.
+TEST_F(MemoryDumpManagerTest, DisableTracingWhileDumping) {
+ base::WaitableEvent tracing_disabled_event(false, false);
+ InitializeMemoryDumpManager(false /* is_coordinator */);
+
+ // Register a bound dump provider.
+ scoped_ptr<Thread> mdp_thread(new Thread("test thread"));
+ mdp_thread->Start();
+ MockMemoryDumpProvider mdp_with_affinity;
+ RegisterDumpProvider(&mdp_with_affinity, mdp_thread->task_runner(),
+ kDefaultOptions);
+
+ // Register also an unbound dump provider. Unbound dump providers are always
+ // invoked after bound ones.
+ MockMemoryDumpProvider unbound_mdp;
+ RegisterDumpProvider(&unbound_mdp, nullptr, kDefaultOptions);
+
+ EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+ EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+ EXPECT_CALL(mdp_with_affinity, OnMemoryDump(_, _))
+ .Times(1)
+ .WillOnce(
+ Invoke([&tracing_disabled_event](const MemoryDumpArgs&,
+ ProcessMemoryDump* pmd) -> bool {
+ tracing_disabled_event.Wait();
+
+ // At this point tracing has been disabled and the
+ // MemoryDumpManager.dump_thread_ has been shut down.
+ return true;
+ }));
+
+ // |unbound_mdp| should never be invoked because the thread for unbound dump
+ // providers has been shutdown in the meanwhile.
+ EXPECT_CALL(unbound_mdp, OnMemoryDump(_, _)).Times(0);
+
+ last_callback_success_ = true;
+ RunLoop run_loop;
+ MemoryDumpCallback callback =
+ Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this),
+ MessageLoop::current()->task_runner(), run_loop.QuitClosure());
+ mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED, callback);
+ DisableTracing();
+ tracing_disabled_event.Signal();
+ run_loop.Run();
+
+ // RequestGlobalMemoryDump() should still suceed even if some threads were
+ // torn down during the dump.
+ EXPECT_TRUE(last_callback_success_);
+}
+
+TEST_F(MemoryDumpManagerTest, DumpOnBehalfOfOtherProcess) {
+ using trace_analyzer::Query;
+
+ InitializeMemoryDumpManager(false /* is_coordinator */);
+
+ // Standard provider with default options (create dump for current process).
+ MemoryDumpProvider::Options options;
+ MockMemoryDumpProvider mdp1;
+ RegisterDumpProvider(&mdp1, nullptr, options);
+
+ // Provider with out-of-process dumping.
+ MockMemoryDumpProvider mdp2;
+ options.target_pid = 123;
+ RegisterDumpProvider(&mdp2, nullptr, options);
+
+ // Another provider with out-of-process dumping.
+ MockMemoryDumpProvider mdp3;
+ options.target_pid = 456;
+ RegisterDumpProvider(&mdp3, nullptr, options);
+
+ EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+ EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+ EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(1).WillRepeatedly(Return(true));
+ EXPECT_CALL(mdp2, OnMemoryDump(_, _)).Times(1).WillRepeatedly(Return(true));
+ EXPECT_CALL(mdp3, OnMemoryDump(_, _)).Times(1).WillRepeatedly(Return(true));
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
+ DisableTracing();
- mdm_->RegisterDumpProvider(&mdp1);
- mdm_->RegisterDumpProvider(&mdp2);
- EnableTracing(kTraceCategory);
+ // Flush the trace into JSON.
+ trace_event::TraceResultBuffer buffer;
+ TraceResultBuffer::SimpleOutput trace_output;
+ buffer.SetOutputCallback(trace_output.GetCallback());
+ RunLoop run_loop;
+ buffer.Start();
+ trace_event::TraceLog::GetInstance()->Flush(
+ Bind(&OnTraceDataCollected, run_loop.QuitClosure(), Unretained(&buffer)));
+ run_loop.Run();
+ buffer.Finish();
+
+ // Analyze the JSON.
+ scoped_ptr<trace_analyzer::TraceAnalyzer> analyzer = make_scoped_ptr(
+ trace_analyzer::TraceAnalyzer::Create(trace_output.json_output));
+ trace_analyzer::TraceEventVector events;
+ analyzer->FindEvents(Query::EventPhaseIs(TRACE_EVENT_PHASE_MEMORY_DUMP),
+ &events);
+
+ ASSERT_EQ(3u, events.size());
+ ASSERT_EQ(1u, trace_analyzer::CountMatches(events, Query::EventPidIs(123)));
+ ASSERT_EQ(1u, trace_analyzer::CountMatches(events, Query::EventPidIs(456)));
+ ASSERT_EQ(1u, trace_analyzer::CountMatches(
+ events, Query::EventPidIs(GetCurrentProcId())));
+ ASSERT_EQ(events[0]->id, events[1]->id);
+ ASSERT_EQ(events[0]->id, events[2]->id);
+}
- EXPECT_CALL(mdp1, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(false));
- EXPECT_CALL(mdp2, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(true));
- mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+// Tests the basics of the UnregisterAndDeleteDumpProviderSoon(): the
+// unregistration should actually delete the providers and not leak them.
+TEST_F(MemoryDumpManagerTest, UnregisterAndDeleteDumpProviderSoon) {
+ InitializeMemoryDumpManager(false /* is_coordinator */);
+ static const int kNumProviders = 3;
+ int dtor_count = 0;
+ std::vector<scoped_ptr<MemoryDumpProvider>> mdps;
+ for (int i = 0; i < kNumProviders; ++i) {
+ scoped_ptr<MockMemoryDumpProvider> mdp(new MockMemoryDumpProvider);
+ mdp->enable_mock_destructor = true;
+ EXPECT_CALL(*mdp, Destructor())
+ .WillOnce(Invoke([&dtor_count]() { dtor_count++; }));
+ RegisterDumpProvider(mdp.get(), nullptr, kDefaultOptions);
+ mdps.push_back(std::move(mdp));
+ }
- EXPECT_CALL(mdp1, OnMemoryDump(_)).Times(0);
- EXPECT_CALL(mdp2, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(false));
- mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+ while (!mdps.empty()) {
+ mdm_->UnregisterAndDeleteDumpProviderSoon(std::move(mdps.back()));
+ mdps.pop_back();
+ }
+ ASSERT_EQ(kNumProviders, dtor_count);
+}
+
+// This test checks against races when unregistering an unbound dump provider
+// from another thread while dumping. It registers one MDP and, when
+// OnMemoryDump() is called, it invokes UnregisterAndDeleteDumpProviderSoon()
+// from another thread. The OnMemoryDump() and the dtor call are expected to
+// happen on the same thread (the MemoryDumpManager utility thread).
+TEST_F(MemoryDumpManagerTest, UnregisterAndDeleteDumpProviderSoonDuringDump) {
+ InitializeMemoryDumpManager(false /* is_coordinator */);
+ scoped_ptr<MockMemoryDumpProvider> mdp(new MockMemoryDumpProvider);
+ mdp->enable_mock_destructor = true;
+ RegisterDumpProvider(mdp.get(), nullptr, kDefaultOptions);
+
+ base::PlatformThreadRef thread_ref;
+ auto self_unregister_from_another_thread = [&mdp, &thread_ref](
+ const MemoryDumpArgs&, ProcessMemoryDump*) -> bool {
+ thread_ref = PlatformThread::CurrentRef();
+ TestIOThread thread_for_unregistration(TestIOThread::kAutoStart);
+ thread_for_unregistration.PostTaskAndWait(
+ FROM_HERE,
+ base::Bind(
+ &MemoryDumpManager::UnregisterAndDeleteDumpProviderSoon,
+ base::Unretained(MemoryDumpManager::GetInstance()),
+ base::Passed(scoped_ptr<MemoryDumpProvider>(std::move(mdp)))));
+ thread_for_unregistration.Stop();
+ return true;
+ };
+ EXPECT_CALL(*mdp, OnMemoryDump(_, _))
+ .Times(1)
+ .WillOnce(Invoke(self_unregister_from_another_thread));
+ EXPECT_CALL(*mdp, Destructor())
+ .Times(1)
+ .WillOnce(Invoke([&thread_ref]() {
+ EXPECT_EQ(thread_ref, PlatformThread::CurrentRef());
+ }));
+
+ EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+ EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(2);
+ for (int i = 0; i < 2; ++i) {
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
+ }
DisableTracing();
}
diff --git a/base/trace_event/memory_dump_provider.h b/base/trace_event/memory_dump_provider.h
index 6e6551cc03..2ce919d833 100644
--- a/base/trace_event/memory_dump_provider.h
+++ b/base/trace_event/memory_dump_provider.h
@@ -7,25 +7,53 @@
#include "base/base_export.h"
#include "base/macros.h"
+#include "base/process/process_handle.h"
+#include "base/trace_event/memory_dump_request_args.h"
namespace base {
namespace trace_event {
class ProcessMemoryDump;
+// Args passed to OnMemoryDump(). This is to avoid rewriting all the subclasses
+// in the codebase when extending the MemoryDumpProvider API.
+struct MemoryDumpArgs {
+ MemoryDumpLevelOfDetail level_of_detail;
+};
+
// The contract interface that memory dump providers must implement.
class BASE_EXPORT MemoryDumpProvider {
public:
+ // Optional arguments for MemoryDumpManager::RegisterDumpProvider().
+ struct Options {
+ Options() : target_pid(kNullProcessId) {}
+ explicit Options(ProcessId target_pid) : target_pid(target_pid) {}
+
+ // If the dump provider generates dumps on behalf of another process,
+ // |target_process| contains the pid of that process.
+ // The default value is kNullProcessId, which means that the dump provider
+ // generates dumps for the current process.
+ ProcessId target_pid;
+ };
+
+ virtual ~MemoryDumpProvider() {}
+
// Called by the MemoryDumpManager when generating memory dumps.
- // The embedder should return true if the |pmd| was successfully populated,
- // false if something went wrong and the dump should be considered invalid.
+ // The |args| specify if the embedder should generate light/heavy dumps on
+ // dump requests. The embedder should return true if the |pmd| was
+ // successfully populated, false if something went wrong and the dump should
+ // be considered invalid.
// (Note, the MemoryDumpManager has a fail-safe logic which will disable the
// MemoryDumpProvider for the entire trace session if it fails consistently).
- virtual bool OnMemoryDump(ProcessMemoryDump* pmd) = 0;
+ virtual bool OnMemoryDump(const MemoryDumpArgs& args,
+ ProcessMemoryDump* pmd) = 0;
+
+ // Called by the MemoryDumpManager when an allocator should start or stop
+ // collecting extensive allocation data, if supported.
+ virtual void OnHeapProfilingEnabled(bool /* enabled */) {}
protected:
MemoryDumpProvider() {}
- virtual ~MemoryDumpProvider() {}
DISALLOW_COPY_AND_ASSIGN(MemoryDumpProvider);
};
diff --git a/base/trace_event/memory_dump_request_args.cc b/base/trace_event/memory_dump_request_args.cc
new file mode 100644
index 0000000000..48b5ba6d2c
--- /dev/null
+++ b/base/trace_event/memory_dump_request_args.cc
@@ -0,0 +1,51 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/memory_dump_request_args.h"
+
+#include "base/logging.h"
+
+namespace base {
+namespace trace_event {
+
+// static
+const char* MemoryDumpTypeToString(const MemoryDumpType& dump_type) {
+ switch (dump_type) {
+ case MemoryDumpType::TASK_BEGIN:
+ return "task_begin";
+ case MemoryDumpType::TASK_END:
+ return "task_end";
+ case MemoryDumpType::PERIODIC_INTERVAL:
+ return "periodic_interval";
+ case MemoryDumpType::EXPLICITLY_TRIGGERED:
+ return "explicitly_triggered";
+ }
+ NOTREACHED();
+ return "unknown";
+}
+
+const char* MemoryDumpLevelOfDetailToString(
+ const MemoryDumpLevelOfDetail& level_of_detail) {
+ switch (level_of_detail) {
+ case MemoryDumpLevelOfDetail::LIGHT:
+ return "light";
+ case MemoryDumpLevelOfDetail::DETAILED:
+ return "detailed";
+ }
+ NOTREACHED();
+ return "unknown";
+}
+
+MemoryDumpLevelOfDetail StringToMemoryDumpLevelOfDetail(
+ const std::string& str) {
+ if (str == "light")
+ return MemoryDumpLevelOfDetail::LIGHT;
+ if (str == "detailed")
+ return MemoryDumpLevelOfDetail::DETAILED;
+ NOTREACHED();
+ return MemoryDumpLevelOfDetail::LAST;
+}
+
+} // namespace trace_event
+} // namespace base
diff --git a/base/trace_event/memory_dump_request_args.h b/base/trace_event/memory_dump_request_args.h
index 6507972f1b..00d560ec6a 100644
--- a/base/trace_event/memory_dump_request_args.h
+++ b/base/trace_event/memory_dump_request_args.h
@@ -8,6 +8,9 @@
// This file defines the types and structs used to issue memory dump requests.
// These are also used in the IPCs for coordinating inter-process memory dumps.
+#include <stdint.h>
+#include <string>
+
#include "base/base_export.h"
#include "base/callback.h"
@@ -20,23 +23,42 @@ enum class MemoryDumpType {
TASK_BEGIN, // Dumping memory at the beginning of a message-loop task.
TASK_END, // Dumping memory at the ending of a message-loop task.
PERIODIC_INTERVAL, // Dumping memory at periodic intervals.
- PERIODIC_INTERVAL_WITH_MMAPS, // As above but w/ heavyweight mmaps dumps.
- // Temporary workaround for crbug.com/499731.
EXPLICITLY_TRIGGERED, // Non maskable dump request.
LAST = EXPLICITLY_TRIGGERED // For IPC macros.
};
-using MemoryDumpCallback = Callback<void(uint64 dump_guid, bool success)>;
+// Tells the MemoryDumpProvider(s) how much detailed their dumps should be.
+// MemoryDumpProvider instances must guarantee that level of detail does not
+// affect the total size reported in the root node, but only the granularity of
+// the child MemoryAllocatorDump(s).
+enum class MemoryDumpLevelOfDetail {
+ LIGHT, // Few entries, typically a fixed number, per dump.
+ DETAILED, // Unrestricted amount of entries per dump.
+ LAST = DETAILED // For IPC Macros.
+};
+// Initial request arguments for a global memory dump. (see
+// MemoryDumpManager::RequestGlobalMemoryDump()).
struct BASE_EXPORT MemoryDumpRequestArgs {
// Globally unique identifier. In multi-process dumps, all processes issue a
// local dump with the same guid. This allows the trace importers to
// reconstruct the global dump.
- uint64 dump_guid;
+ uint64_t dump_guid;
MemoryDumpType dump_type;
+ MemoryDumpLevelOfDetail level_of_detail;
};
+using MemoryDumpCallback = Callback<void(uint64_t dump_guid, bool success)>;
+
+BASE_EXPORT const char* MemoryDumpTypeToString(const MemoryDumpType& dump_type);
+
+BASE_EXPORT const char* MemoryDumpLevelOfDetailToString(
+ const MemoryDumpLevelOfDetail& level_of_detail);
+
+BASE_EXPORT MemoryDumpLevelOfDetail
+StringToMemoryDumpLevelOfDetail(const std::string& str);
+
} // namespace trace_event
} // namespace base
diff --git a/base/trace_event/memory_dump_session_state.cc b/base/trace_event/memory_dump_session_state.cc
index 433ac14cbf..5aa79b1c78 100644
--- a/base/trace_event/memory_dump_session_state.cc
+++ b/base/trace_event/memory_dump_session_state.cc
@@ -7,8 +7,11 @@
namespace base {
namespace trace_event {
-MemoryDumpSessionState::MemoryDumpSessionState() {
-}
+MemoryDumpSessionState::MemoryDumpSessionState(
+ const scoped_refptr<StackFrameDeduplicator>& stack_frame_deduplicator,
+ const scoped_refptr<TypeNameDeduplicator>& type_name_deduplicator)
+ : stack_frame_deduplicator_(stack_frame_deduplicator),
+ type_name_deduplicator_(type_name_deduplicator) {}
MemoryDumpSessionState::~MemoryDumpSessionState() {
}
diff --git a/base/trace_event/memory_dump_session_state.h b/base/trace_event/memory_dump_session_state.h
index cf29b85559..6834471b9a 100644
--- a/base/trace_event/memory_dump_session_state.h
+++ b/base/trace_event/memory_dump_session_state.h
@@ -5,10 +5,10 @@
#ifndef BASE_TRACE_EVENT_MEMORY_DUMP_SESSION_STATE_H_
#define BASE_TRACE_EVENT_MEMORY_DUMP_SESSION_STATE_H_
-#include <string>
-
#include "base/base_export.h"
#include "base/memory/ref_counted.h"
+#include "base/trace_event/heap_profiler_stack_frame_deduplicator.h"
+#include "base/trace_event/heap_profiler_type_name_deduplicator.h"
namespace base {
namespace trace_event {
@@ -18,11 +18,33 @@ namespace trace_event {
class BASE_EXPORT MemoryDumpSessionState
: public RefCountedThreadSafe<MemoryDumpSessionState> {
public:
- MemoryDumpSessionState();
+ MemoryDumpSessionState(
+ const scoped_refptr<StackFrameDeduplicator>& stack_frame_deduplicator,
+ const scoped_refptr<TypeNameDeduplicator>& type_name_deduplicator);
+
+ // Returns the stack frame deduplicator that should be used by memory dump
+ // providers when doing a heap dump.
+ StackFrameDeduplicator* stack_frame_deduplicator() {
+ return stack_frame_deduplicator_.get();
+ }
+
+ // Returns the type name deduplicator that should be used by memory dump
+ // providers when doing a heap dump.
+ TypeNameDeduplicator* type_name_deduplicator() {
+ return type_name_deduplicator_.get();
+ }
private:
friend class RefCountedThreadSafe<MemoryDumpSessionState>;
~MemoryDumpSessionState();
+
+ // Deduplicates backtraces in heap dumps so they can be written once when the
+ // trace is finalized.
+ scoped_refptr<StackFrameDeduplicator> stack_frame_deduplicator_;
+
+ // Deduplicates type names in heap dumps so they can be written once when the
+ // trace is finalized.
+ scoped_refptr<TypeNameDeduplicator> type_name_deduplicator_;
};
} // namespace trace_event
diff --git a/base/trace_event/process_memory_dump.cc b/base/trace_event/process_memory_dump.cc
index 46ae1fc611..ae60bb06b1 100644
--- a/base/trace_event/process_memory_dump.cc
+++ b/base/trace_event/process_memory_dump.cc
@@ -4,21 +4,90 @@
#include "base/trace_event/process_memory_dump.h"
+#include <errno.h>
+#include <vector>
+
+#include "base/process/process_metrics.h"
#include "base/trace_event/process_memory_totals.h"
#include "base/trace_event/trace_event_argument.h"
+#include "build/build_config.h"
+
+#if defined(OS_POSIX)
+#include <sys/mman.h>
+#endif
namespace base {
namespace trace_event {
namespace {
+
const char kEdgeTypeOwnership[] = "ownership";
std::string GetSharedGlobalAllocatorDumpName(
const MemoryAllocatorDumpGuid& guid) {
return "global/" + guid.ToString();
}
+
} // namespace
+#if defined(COUNT_RESIDENT_BYTES_SUPPORTED)
+// static
+size_t ProcessMemoryDump::CountResidentBytes(void* start_address,
+ size_t mapped_size) {
+ const size_t page_size = GetPageSize();
+ const uintptr_t start_pointer = reinterpret_cast<uintptr_t>(start_address);
+ DCHECK_EQ(0u, start_pointer % page_size);
+
+ // This function allocates a char vector of size number of pages in the given
+ // mapped_size. To avoid allocating a large array, the memory is split into
+ // chunks. Maximum size of vector allocated, will be
+ // kPageChunkSize / page_size.
+ const size_t kMaxChunkSize = 32 * 1024 * 1024;
+ size_t offset = 0;
+ size_t total_resident_size = 0;
+ int result = 0;
+ while (offset < mapped_size) {
+ void* chunk_start = reinterpret_cast<void*>(start_pointer + offset);
+ const size_t chunk_size = std::min(mapped_size - offset, kMaxChunkSize);
+ const size_t page_count = (chunk_size + page_size - 1) / page_size;
+ size_t resident_page_count = 0;
+
+#if defined(OS_MACOSX) || defined(OS_IOS)
+ std::vector<char> vec(page_count + 1);
+ // mincore in MAC does not fail with EAGAIN.
+ result = mincore(chunk_start, chunk_size, vec.data());
+ if (result)
+ break;
+
+ for (size_t i = 0; i < page_count; i++)
+ resident_page_count += vec[i] & MINCORE_INCORE ? 1 : 0;
+#else // defined(OS_MACOSX) || defined(OS_IOS)
+ std::vector<unsigned char> vec(page_count + 1);
+ int error_counter = 0;
+ // HANDLE_EINTR tries for 100 times. So following the same pattern.
+ do {
+ result = mincore(chunk_start, chunk_size, vec.data());
+ } while (result == -1 && errno == EAGAIN && error_counter++ < 100);
+ if (result)
+ break;
+
+ for (size_t i = 0; i < page_count; i++)
+ resident_page_count += vec[i];
+#endif // defined(OS_MACOSX) || defined(OS_IOS)
+
+ total_resident_size += resident_page_count * page_size;
+ offset += kMaxChunkSize;
+ }
+
+ DCHECK_EQ(0, result);
+ if (result) {
+ total_resident_size = 0;
+ LOG(ERROR) << "mincore() call failed. The resident size is invalid";
+ }
+ return total_resident_size;
+}
+#endif // defined(COUNT_RESIDENT_BYTES_SUPPORTED)
+
ProcessMemoryDump::ProcessMemoryDump(
const scoped_refptr<MemoryDumpSessionState>& session_state)
: has_process_totals_(false),
@@ -56,9 +125,20 @@ MemoryAllocatorDump* ProcessMemoryDump::GetAllocatorDump(
return it == allocator_dumps_.end() ? nullptr : it->second;
}
+MemoryAllocatorDump* ProcessMemoryDump::GetOrCreateAllocatorDump(
+ const std::string& absolute_name) {
+ MemoryAllocatorDump* mad = GetAllocatorDump(absolute_name);
+ return mad ? mad : CreateAllocatorDump(absolute_name);
+}
+
MemoryAllocatorDump* ProcessMemoryDump::CreateSharedGlobalAllocatorDump(
const MemoryAllocatorDumpGuid& guid) {
- return CreateAllocatorDump(GetSharedGlobalAllocatorDumpName(guid), guid);
+ // A shared allocator dump can be shared within a process and the guid could
+ // have been created already.
+ MemoryAllocatorDump* allocator_dump = GetSharedGlobalAllocatorDump(guid);
+ return allocator_dump ? allocator_dump
+ : CreateAllocatorDump(
+ GetSharedGlobalAllocatorDumpName(guid), guid);
}
MemoryAllocatorDump* ProcessMemoryDump::GetSharedGlobalAllocatorDump(
@@ -66,6 +146,12 @@ MemoryAllocatorDump* ProcessMemoryDump::GetSharedGlobalAllocatorDump(
return GetAllocatorDump(GetSharedGlobalAllocatorDumpName(guid));
}
+void ProcessMemoryDump::AddHeapDump(const std::string& absolute_name,
+ scoped_refptr<TracedValue> heap_dump) {
+ DCHECK_EQ(0ul, heap_dumps_.count(absolute_name));
+ heap_dumps_[absolute_name] = heap_dump;
+}
+
void ProcessMemoryDump::Clear() {
if (has_process_totals_) {
process_totals_.Clear();
@@ -80,6 +166,7 @@ void ProcessMemoryDump::Clear() {
allocator_dumps_storage_.clear();
allocator_dumps_.clear();
allocator_dumps_edges_.clear();
+ heap_dumps_.clear();
}
void ProcessMemoryDump::TakeAllDumpsFrom(ProcessMemoryDump* other) {
@@ -101,6 +188,9 @@ void ProcessMemoryDump::TakeAllDumpsFrom(ProcessMemoryDump* other) {
other->allocator_dumps_edges_.begin(),
other->allocator_dumps_edges_.end());
other->allocator_dumps_edges_.clear();
+
+ heap_dumps_.insert(other->heap_dumps_.begin(), other->heap_dumps_.end());
+ other->heap_dumps_.clear();
}
void ProcessMemoryDump::AsValueInto(TracedValue* value) const {
@@ -123,6 +213,13 @@ void ProcessMemoryDump::AsValueInto(TracedValue* value) const {
value->EndDictionary();
}
+ if (heap_dumps_.size() > 0) {
+ value->BeginDictionary("heaps");
+ for (const auto& name_and_dump : heap_dumps_)
+ value->SetValueWithCopiedName(name_and_dump.first, *name_and_dump.second);
+ value->EndDictionary(); // "heaps"
+ }
+
value->BeginArray("allocators_graph");
for (const MemoryAllocatorDumpEdge& edge : allocator_dumps_edges_) {
value->BeginDictionary();
diff --git a/base/trace_event/process_memory_dump.h b/base/trace_event/process_memory_dump.h
index 88ce28abe2..5a66402881 100644
--- a/base/trace_event/process_memory_dump.h
+++ b/base/trace_event/process_memory_dump.h
@@ -5,11 +5,14 @@
#ifndef BASE_TRACE_EVENT_PROCESS_MEMORY_DUMP_H_
#define BASE_TRACE_EVENT_PROCESS_MEMORY_DUMP_H_
+#include <stddef.h>
+
#include <vector>
#include "base/base_export.h"
#include "base/containers/hash_tables.h"
#include "base/containers/small_map.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_vector.h"
#include "base/trace_event/memory_allocator_dump.h"
@@ -17,6 +20,15 @@
#include "base/trace_event/memory_dump_session_state.h"
#include "base/trace_event/process_memory_maps.h"
#include "base/trace_event/process_memory_totals.h"
+#include "build/build_config.h"
+
+// Define COUNT_RESIDENT_BYTES_SUPPORTED if platform supports counting of the
+// resident memory.
+// TODO(crbug.com/542671): COUNT_RESIDENT_BYTES_SUPPORTED is disabled on iOS
+// as it cause memory corruption on iOS 9.0+ devices.
+#if defined(OS_POSIX) && !defined(OS_NACL) && !defined(OS_IOS)
+#define COUNT_RESIDENT_BYTES_SUPPORTED
+#endif
namespace base {
namespace trace_event {
@@ -24,13 +36,10 @@ namespace trace_event {
class ConvertableToTraceFormat;
class MemoryDumpManager;
class MemoryDumpSessionState;
+class TracedValue;
-// ProcessMemoryDump is as a strongly typed container which enforces the data
-// model for each memory dump and holds the dumps produced by the
-// MemoryDumpProvider(s) for a specific process.
-// At trace generation time (i.e. when AsValue() is called), ProcessMemoryDump
-// will compose a key-value dictionary of the various dumps obtained at trace
-// dump point time.
+// ProcessMemoryDump is as a strongly typed container which holds the dumps
+// produced by the MemoryDumpProvider(s) for a specific process.
class BASE_EXPORT ProcessMemoryDump {
public:
struct MemoryAllocatorDumpEdge {
@@ -45,31 +54,19 @@ class BASE_EXPORT ProcessMemoryDump {
using AllocatorDumpsMap =
SmallMap<hash_map<std::string, MemoryAllocatorDump*>>;
- ProcessMemoryDump(const scoped_refptr<MemoryDumpSessionState>& session_state);
- ~ProcessMemoryDump();
-
- // Called at trace generation time to populate the TracedValue.
- void AsValueInto(TracedValue* value) const;
-
- // Removes all the MemoryAllocatorDump(s) contained in this instance. This
- // ProcessMemoryDump can be safely reused as if it was new once this returns.
- void Clear();
-
- // Merges all MemoryAllocatorDump(s) contained in |other| inside this
- // ProcessMemoryDump, transferring their ownership to this instance.
- // |other| will be an empty ProcessMemoryDump after this method returns.
- // This is to allow dump providers to pre-populate ProcessMemoryDump instances
- // and later move their contents into the ProcessMemoryDump passed as argument
- // of the MemoryDumpProvider::OnMemoryDump(ProcessMemoryDump*) callback.
- void TakeAllDumpsFrom(ProcessMemoryDump* other);
+ using HeapDumpsMap =
+ SmallMap<hash_map<std::string, scoped_refptr<TracedValue>>>;
- ProcessMemoryTotals* process_totals() { return &process_totals_; }
- bool has_process_totals() const { return has_process_totals_; }
- void set_has_process_totals() { has_process_totals_ = true; }
+#if defined(COUNT_RESIDENT_BYTES_SUPPORTED)
+ // Returns the total bytes resident for a virtual address range, with given
+ // |start_address| and |mapped_size|. |mapped_size| is specified in bytes. The
+ // value returned is valid only if the given range is currently mmapped by the
+ // process. The |start_address| must be page-aligned.
+ static size_t CountResidentBytes(void* start_address, size_t mapped_size);
+#endif
- ProcessMemoryMaps* process_mmaps() { return &process_mmaps_; }
- bool has_process_mmaps() const { return has_process_mmaps_; }
- void set_has_process_mmaps() { has_process_mmaps_ = true; }
+ ProcessMemoryDump(const scoped_refptr<MemoryDumpSessionState>& session_state);
+ ~ProcessMemoryDump();
// Creates a new MemoryAllocatorDump with the given name and returns the
// empty object back to the caller.
@@ -80,7 +77,8 @@ class BASE_EXPORT ProcessMemoryDump {
// Leading or trailing slashes are not allowed.
// guid: an optional identifier, unique among all processes within the
// scope of a global dump. This is only relevant when using
- // AddOwnershipEdge(). If omitted, it will be automatically generated.
+ // AddOwnershipEdge() to express memory sharing. If omitted,
+ // it will be automatically generated.
// ProcessMemoryDump handles the memory ownership of its MemoryAllocatorDumps.
MemoryAllocatorDump* CreateAllocatorDump(const std::string& absolute_name);
MemoryAllocatorDump* CreateAllocatorDump(const std::string& absolute_name,
@@ -90,6 +88,9 @@ class BASE_EXPORT ProcessMemoryDump {
// nullptr if not found.
MemoryAllocatorDump* GetAllocatorDump(const std::string& absolute_name) const;
+ MemoryAllocatorDump* GetOrCreateAllocatorDump(
+ const std::string& absolute_name);
+
// Creates a shared MemoryAllocatorDump, to express cross-process sharing.
// Shared allocator dumps are allowed to have duplicate guids within the
// global scope, in order to reference the same dump from multiple processes.
@@ -104,6 +105,12 @@ class BASE_EXPORT ProcessMemoryDump {
// Returns the map of the MemoryAllocatorDumps added to this dump.
const AllocatorDumpsMap& allocator_dumps() const { return allocator_dumps_; }
+ // Adds a heap dump for the allocator with |absolute_name|. The |TracedValue|
+ // must have the correct format. |trace_event::HeapDumper| will generate such
+ // a value from a |trace_event::AllocationRegister|.
+ void AddHeapDump(const std::string& absolute_name,
+ scoped_refptr<TracedValue> heap_dump);
+
// Adds an ownership relationship between two MemoryAllocatorDump(s) with the
// semantics: |source| owns |target|, and has the effect of attributing
// the memory usage of |target| to |source|. |importance| is optional and
@@ -131,6 +138,29 @@ class BASE_EXPORT ProcessMemoryDump {
return session_state_;
}
+ // Removes all the MemoryAllocatorDump(s) contained in this instance. This
+ // ProcessMemoryDump can be safely reused as if it was new once this returns.
+ void Clear();
+
+ // Merges all MemoryAllocatorDump(s) contained in |other| inside this
+ // ProcessMemoryDump, transferring their ownership to this instance.
+ // |other| will be an empty ProcessMemoryDump after this method returns.
+ // This is to allow dump providers to pre-populate ProcessMemoryDump instances
+ // and later move their contents into the ProcessMemoryDump passed as argument
+ // of the MemoryDumpProvider::OnMemoryDump(ProcessMemoryDump*) callback.
+ void TakeAllDumpsFrom(ProcessMemoryDump* other);
+
+ // Called at trace generation time to populate the TracedValue.
+ void AsValueInto(TracedValue* value) const;
+
+ ProcessMemoryTotals* process_totals() { return &process_totals_; }
+ bool has_process_totals() const { return has_process_totals_; }
+ void set_has_process_totals() { has_process_totals_ = true; }
+
+ ProcessMemoryMaps* process_mmaps() { return &process_mmaps_; }
+ bool has_process_mmaps() const { return has_process_mmaps_; }
+ void set_has_process_mmaps() { has_process_mmaps_ = true; }
+
private:
void AddAllocatorDumpInternal(MemoryAllocatorDump* mad);
@@ -141,6 +171,7 @@ class BASE_EXPORT ProcessMemoryDump {
bool has_process_mmaps_;
AllocatorDumpsMap allocator_dumps_;
+ HeapDumpsMap heap_dumps_;
// ProcessMemoryDump handles the memory ownership of all its belongings.
ScopedVector<MemoryAllocatorDump> allocator_dumps_storage_;
diff --git a/base/trace_event/process_memory_dump_unittest.cc b/base/trace_event/process_memory_dump_unittest.cc
index 1e1fbc69cf..88984abd34 100644
--- a/base/trace_event/process_memory_dump_unittest.cc
+++ b/base/trace_event/process_memory_dump_unittest.cc
@@ -4,7 +4,10 @@
#include "base/trace_event/process_memory_dump.h"
-#include "base/memory/scoped_ptr.h"
+#include <stddef.h>
+
+#include "base/memory/aligned_memory.h"
+#include "base/process/process_metrics.h"
#include "base/trace_event/memory_allocator_dump_guid.h"
#include "base/trace_event/trace_event_argument.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -154,5 +157,28 @@ TEST(ProcessMemoryDumpTest, Suballocations) {
pmd.reset();
}
+#if defined(COUNT_RESIDENT_BYTES_SUPPORTED)
+TEST(ProcessMemoryDumpTest, CountResidentBytes) {
+ const size_t page_size = base::GetPageSize();
+
+ // Allocate few page of dirty memory and check if it is resident.
+ const size_t size1 = 5 * page_size;
+ scoped_ptr<char, base::AlignedFreeDeleter> memory1(
+ static_cast<char*>(base::AlignedAlloc(size1, page_size)));
+ memset(memory1.get(), 0, size1);
+ size_t res1 = ProcessMemoryDump::CountResidentBytes(memory1.get(), size1);
+ ASSERT_EQ(res1, size1);
+
+ // Allocate a large memory segment (>32Mib).
+ const size_t kVeryLargeMemorySize = 34 * 1024 * 1024;
+ scoped_ptr<char, base::AlignedFreeDeleter> memory2(
+ static_cast<char*>(base::AlignedAlloc(kVeryLargeMemorySize, page_size)));
+ memset(memory2.get(), 0, kVeryLargeMemorySize);
+ size_t res2 = ProcessMemoryDump::CountResidentBytes(memory2.get(),
+ kVeryLargeMemorySize);
+ ASSERT_EQ(res2, kVeryLargeMemorySize);
+}
+#endif // defined(COUNT_RESIDENT_BYTES_SUPPORTED)
+
} // namespace trace_event
} // namespace base
diff --git a/base/trace_event/process_memory_maps.cc b/base/trace_event/process_memory_maps.cc
index bb400de174..31083a8927 100644
--- a/base/trace_event/process_memory_maps.cc
+++ b/base/trace_event/process_memory_maps.cc
@@ -12,9 +12,9 @@ namespace base {
namespace trace_event {
// static
-const uint32 ProcessMemoryMaps::VMRegion::kProtectionFlagsRead = 4;
-const uint32 ProcessMemoryMaps::VMRegion::kProtectionFlagsWrite = 2;
-const uint32 ProcessMemoryMaps::VMRegion::kProtectionFlagsExec = 1;
+const uint32_t ProcessMemoryMaps::VMRegion::kProtectionFlagsRead = 4;
+const uint32_t ProcessMemoryMaps::VMRegion::kProtectionFlagsWrite = 2;
+const uint32_t ProcessMemoryMaps::VMRegion::kProtectionFlagsExec = 1;
ProcessMemoryMaps::VMRegion::VMRegion()
: start_address(0),
diff --git a/base/trace_event/process_memory_maps.h b/base/trace_event/process_memory_maps.h
index b06a85037a..3dfcc0c988 100644
--- a/base/trace_event/process_memory_maps.h
+++ b/base/trace_event/process_memory_maps.h
@@ -5,11 +5,13 @@
#ifndef BASE_TRACE_EVENT_PROCESS_MEMORY_MAPS_H_
#define BASE_TRACE_EVENT_PROCESS_MEMORY_MAPS_H_
+#include <stdint.h>
+
#include <string>
#include <vector>
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
namespace base {
namespace trace_event {
@@ -20,28 +22,28 @@ class TracedValue;
class BASE_EXPORT ProcessMemoryMaps {
public:
struct BASE_EXPORT VMRegion {
- static const uint32 kProtectionFlagsRead;
- static const uint32 kProtectionFlagsWrite;
- static const uint32 kProtectionFlagsExec;
+ static const uint32_t kProtectionFlagsRead;
+ static const uint32_t kProtectionFlagsWrite;
+ static const uint32_t kProtectionFlagsExec;
VMRegion();
- uint64 start_address;
- uint64 size_in_bytes;
- uint32 protection_flags;
+ uint64_t start_address;
+ uint64_t size_in_bytes;
+ uint32_t protection_flags;
std::string mapped_file;
// private_dirty_resident + private_clean_resident + shared_dirty_resident +
// shared_clean_resident = resident set size.
- uint64 byte_stats_private_dirty_resident;
- uint64 byte_stats_private_clean_resident;
- uint64 byte_stats_shared_dirty_resident;
- uint64 byte_stats_shared_clean_resident;
+ uint64_t byte_stats_private_dirty_resident;
+ uint64_t byte_stats_private_clean_resident;
+ uint64_t byte_stats_shared_dirty_resident;
+ uint64_t byte_stats_shared_clean_resident;
- uint64 byte_stats_swapped;
+ uint64_t byte_stats_swapped;
// For multiprocess accounting.
- uint64 byte_stats_proportional_resident;
+ uint64_t byte_stats_proportional_resident;
};
ProcessMemoryMaps();
diff --git a/base/trace_event/process_memory_maps_dump_provider.cc b/base/trace_event/process_memory_maps_dump_provider.cc
index e0ae20d2a5..4c3959fe9b 100644
--- a/base/trace_event/process_memory_maps_dump_provider.cc
+++ b/base/trace_event/process_memory_maps_dump_provider.cc
@@ -4,35 +4,38 @@
#include "base/trace_event/process_memory_maps_dump_provider.h"
-#include <cctype>
-#include <fstream>
+#include <stdint.h>
+#include "base/files/scoped_file.h"
+#include "base/format_macros.h"
#include "base/logging.h"
-#include "base/process/process_metrics.h"
+#include "base/strings/string_util.h"
#include "base/trace_event/process_memory_dump.h"
#include "base/trace_event/process_memory_maps.h"
namespace base {
namespace trace_event {
-#if defined(OS_LINUX) || defined(OS_ANDROID)
// static
-std::istream* ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = nullptr;
+FILE* ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = nullptr;
namespace {
-const uint32 kMaxLineSize = 4096;
+const uint32_t kMaxLineSize = 4096;
-bool ParseSmapsHeader(std::istream* smaps,
+bool ParseSmapsHeader(const char* header_line,
ProcessMemoryMaps::VMRegion* region) {
// e.g., "00400000-00421000 r-xp 00000000 fc:01 1234 /foo.so\n"
bool res = true; // Whether this region should be appended or skipped.
- uint64 end_addr;
- std::string protection_flags;
- std::string ignored;
- *smaps >> std::hex >> region->start_address;
- smaps->ignore(1);
- *smaps >> std::hex >> end_addr;
+ uint64_t end_addr = 0;
+ char protection_flags[5] = {0};
+ char mapped_file[kMaxLineSize];
+
+ if (sscanf(header_line, "%" SCNx64 "-%" SCNx64 " %4c %*s %*s %*s%4095[^\n]\n",
+ &region->start_address, &end_addr, protection_flags,
+ mapped_file) != 4)
+ return false;
+
if (end_addr > region->start_address) {
region->size_in_bytes = end_addr - region->start_address;
} else {
@@ -42,8 +45,6 @@ bool ParseSmapsHeader(std::istream* smaps,
}
region->protection_flags = 0;
- *smaps >> protection_flags;
- CHECK_EQ(4UL, protection_flags.size());
if (protection_flags[0] == 'r') {
region->protection_flags |=
ProcessMemoryMaps::VMRegion::kProtectionFlagsRead;
@@ -56,84 +57,70 @@ bool ParseSmapsHeader(std::istream* smaps,
region->protection_flags |=
ProcessMemoryMaps::VMRegion::kProtectionFlagsExec;
}
- *smaps >> ignored; // Ignore mapped file offset.
- *smaps >> ignored; // Ignore device maj-min (fc:01 in the example above).
- *smaps >> ignored; // Ignore inode number (1234 in the example above).
- while (smaps->peek() == ' ')
- smaps->ignore(1);
- char mapped_file[kMaxLineSize];
- smaps->getline(mapped_file, sizeof(mapped_file));
region->mapped_file = mapped_file;
+ TrimWhitespaceASCII(region->mapped_file, TRIM_ALL, &region->mapped_file);
return res;
}
-uint64 ReadCounterBytes(std::istream* smaps) {
- uint64 counter_value = 0;
- *smaps >> std::dec >> counter_value;
+uint64_t ReadCounterBytes(char* counter_line) {
+ uint64_t counter_value = 0;
+ int res = sscanf(counter_line, "%*s %" SCNu64 " kB", &counter_value);
+ DCHECK_EQ(1, res);
return counter_value * 1024;
}
-uint32 ParseSmapsCounter(std::istream* smaps,
- ProcessMemoryMaps::VMRegion* region) {
+uint32_t ParseSmapsCounter(char* counter_line,
+ ProcessMemoryMaps::VMRegion* region) {
// A smaps counter lines looks as follows: "RSS: 0 Kb\n"
- uint32 res = 1;
- std::string counter_name;
- *smaps >> counter_name;
-
- // TODO(primiano): "Swap" should also be accounted as resident. Check
- // whether Rss isn't already counting swapped and fix below if that is
- // the case.
- if (counter_name == "Pss:") {
- region->byte_stats_proportional_resident = ReadCounterBytes(smaps);
- } else if (counter_name == "Private_Dirty:") {
- region->byte_stats_private_dirty_resident = ReadCounterBytes(smaps);
- } else if (counter_name == "Private_Clean:") {
- region->byte_stats_private_clean_resident = ReadCounterBytes(smaps);
- } else if (counter_name == "Shared_Dirty:") {
- region->byte_stats_shared_dirty_resident = ReadCounterBytes(smaps);
- } else if (counter_name == "Shared_Clean:") {
- region->byte_stats_shared_clean_resident = ReadCounterBytes(smaps);
- } else if (counter_name == "Swap:") {
- region->byte_stats_swapped = ReadCounterBytes(smaps);
+ uint32_t res = 1;
+ char counter_name[20];
+ int did_read = sscanf(counter_line, "%19[^\n ]", counter_name);
+ DCHECK_EQ(1, did_read);
+
+ if (strcmp(counter_name, "Pss:") == 0) {
+ region->byte_stats_proportional_resident = ReadCounterBytes(counter_line);
+ } else if (strcmp(counter_name, "Private_Dirty:") == 0) {
+ region->byte_stats_private_dirty_resident = ReadCounterBytes(counter_line);
+ } else if (strcmp(counter_name, "Private_Clean:") == 0) {
+ region->byte_stats_private_clean_resident = ReadCounterBytes(counter_line);
+ } else if (strcmp(counter_name, "Shared_Dirty:") == 0) {
+ region->byte_stats_shared_dirty_resident = ReadCounterBytes(counter_line);
+ } else if (strcmp(counter_name, "Shared_Clean:") == 0) {
+ region->byte_stats_shared_clean_resident = ReadCounterBytes(counter_line);
+ } else if (strcmp(counter_name, "Swap:") == 0) {
+ region->byte_stats_swapped = ReadCounterBytes(counter_line);
} else {
res = 0;
}
-#ifndef NDEBUG
- // Paranoid check against changes of the Kernel /proc interface.
- if (res) {
- std::string unit;
- *smaps >> unit;
- DCHECK_EQ("kB", unit);
- }
-#endif
-
- smaps->ignore(kMaxLineSize, '\n');
-
return res;
}
-uint32 ReadLinuxProcSmapsFile(std::istream* smaps, ProcessMemoryMaps* pmm) {
- if (!smaps->good())
+uint32_t ReadLinuxProcSmapsFile(FILE* smaps_file, ProcessMemoryMaps* pmm) {
+ if (!smaps_file)
return 0;
- const uint32 kNumExpectedCountersPerRegion = 6;
- uint32 counters_parsed_for_current_region = 0;
- uint32 num_valid_regions = 0;
+ fseek(smaps_file, 0, SEEK_SET);
+
+ char line[kMaxLineSize];
+ const uint32_t kNumExpectedCountersPerRegion = 6;
+ uint32_t counters_parsed_for_current_region = 0;
+ uint32_t num_valid_regions = 0;
ProcessMemoryMaps::VMRegion region;
bool should_add_current_region = false;
for (;;) {
- int next = smaps->peek();
- if (next == std::ifstream::traits_type::eof() || next == '\n')
+ line[0] = '\0';
+ if (fgets(line, kMaxLineSize, smaps_file) == nullptr)
break;
- if (isxdigit(next) && !isupper(next)) {
+ DCHECK_GT(strlen(line), 0u);
+ if (isxdigit(line[0]) && !isupper(line[0])) {
region = ProcessMemoryMaps::VMRegion();
counters_parsed_for_current_region = 0;
- should_add_current_region = ParseSmapsHeader(smaps, &region);
+ should_add_current_region = ParseSmapsHeader(line, &region);
} else {
- counters_parsed_for_current_region += ParseSmapsCounter(smaps, &region);
+ counters_parsed_for_current_region += ParseSmapsCounter(line, &region);
DCHECK_LE(counters_parsed_for_current_region,
kNumExpectedCountersPerRegion);
if (counters_parsed_for_current_region == kNumExpectedCountersPerRegion) {
@@ -149,7 +136,6 @@ uint32 ReadLinuxProcSmapsFile(std::istream* smaps, ProcessMemoryMaps* pmm) {
}
} // namespace
-#endif // defined(OS_LINUX) || defined(OS_ANDROID)
// static
ProcessMemoryMapsDumpProvider* ProcessMemoryMapsDumpProvider::GetInstance() {
@@ -163,27 +149,26 @@ ProcessMemoryMapsDumpProvider::ProcessMemoryMapsDumpProvider() {
ProcessMemoryMapsDumpProvider::~ProcessMemoryMapsDumpProvider() {
}
-// Called at trace dump point time. Creates a snapshot the memory maps for the
-// current process.
-bool ProcessMemoryMapsDumpProvider::OnMemoryDump(ProcessMemoryDump* pmd) {
- uint32 res = 0;
+// Called at trace dump point time. Creates a snapshot of the memory maps for
+// the current process.
+bool ProcessMemoryMapsDumpProvider::OnMemoryDump(const MemoryDumpArgs& args,
+ ProcessMemoryDump* pmd) {
+ // Snapshot of memory maps is not taken for light dump requests.
+ if (args.level_of_detail == MemoryDumpLevelOfDetail::LIGHT)
+ return true;
-#if defined(OS_LINUX) || defined(OS_ANDROID)
+ uint32_t res = 0;
if (UNLIKELY(proc_smaps_for_testing)) {
res = ReadLinuxProcSmapsFile(proc_smaps_for_testing, pmd->process_mmaps());
} else {
- std::ifstream proc_self_smaps("/proc/self/smaps");
- res = ReadLinuxProcSmapsFile(&proc_self_smaps, pmd->process_mmaps());
+ ScopedFILE smaps_file(fopen("/proc/self/smaps", "r"));
+ res = ReadLinuxProcSmapsFile(smaps_file.get(), pmd->process_mmaps());
}
-#else
- LOG(ERROR) << "ProcessMemoryMaps dump provider is supported only on Linux";
-#endif
if (res > 0) {
pmd->set_has_process_mmaps();
return true;
}
-
return false;
}
diff --git a/base/trace_event/process_memory_maps_dump_provider.h b/base/trace_event/process_memory_maps_dump_provider.h
index c73c4d2be6..84badfe9a0 100644
--- a/base/trace_event/process_memory_maps_dump_provider.h
+++ b/base/trace_event/process_memory_maps_dump_provider.h
@@ -5,11 +5,11 @@
#ifndef BASE_TRACE_EVENT_PROCESS_MEMORY_MAPS_DUMP_PROVIDER_H_
#define BASE_TRACE_EVENT_PROCESS_MEMORY_MAPS_DUMP_PROVIDER_H_
-#include <istream>
-
#include "base/gtest_prod_util.h"
+#include "base/macros.h"
#include "base/memory/singleton.h"
#include "base/trace_event/memory_dump_provider.h"
+#include "build/build_config.h"
namespace base {
namespace trace_event {
@@ -20,14 +20,15 @@ class BASE_EXPORT ProcessMemoryMapsDumpProvider : public MemoryDumpProvider {
static ProcessMemoryMapsDumpProvider* GetInstance();
// MemoryDumpProvider implementation.
- bool OnMemoryDump(ProcessMemoryDump* pmd) override;
+ bool OnMemoryDump(const MemoryDumpArgs& args,
+ ProcessMemoryDump* pmd) override;
private:
friend struct DefaultSingletonTraits<ProcessMemoryMapsDumpProvider>;
FRIEND_TEST_ALL_PREFIXES(ProcessMemoryMapsDumpProviderTest, ParseProcSmaps);
-#if defined(OS_LINUX) || defined(OS_ANDROID)
- static std::istream* proc_smaps_for_testing;
+#if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_NACL)
+ static FILE* proc_smaps_for_testing;
#endif
ProcessMemoryMapsDumpProvider();
diff --git a/base/trace_event/process_memory_maps_dump_provider_unittest.cc b/base/trace_event/process_memory_maps_dump_provider_unittest.cc
index 5416e11996..624f96fcb0 100644
--- a/base/trace_event/process_memory_maps_dump_provider_unittest.cc
+++ b/base/trace_event/process_memory_maps_dump_provider_unittest.cc
@@ -4,9 +4,9 @@
#include "base/trace_event/process_memory_maps_dump_provider.h"
-#include <fstream>
-#include <sstream>
+#include <stdint.h>
+#include "base/files/file_util.h"
#include "base/trace_event/process_memory_dump.h"
#include "base/trace_event/process_memory_maps.h"
#include "base/trace_event/trace_event_argument.h"
@@ -15,7 +15,6 @@
namespace base {
namespace trace_event {
-#if defined(OS_LINUX) || defined(OS_ANDROID)
namespace {
const char kTestSmaps1[] =
"00400000-004be000 r-xp 00000000 fc:01 1234 /file/1\n"
@@ -104,35 +103,42 @@ const char kTestSmaps2[] =
"MMUPageSize: 4 kB\n"
"Locked: 0 kB\n"
"VmFlags: rd wr mr mw me ac sd\n";
+
+void CreateAndSetSmapsFileForTesting(const char* smaps_string,
+ ScopedFILE& file) {
+ FilePath temp_path;
+ FILE* temp_file = CreateAndOpenTemporaryFile(&temp_path);
+ file.reset(temp_file);
+ ASSERT_TRUE(temp_file);
+
+ ASSERT_TRUE(base::WriteFileDescriptor(fileno(temp_file), smaps_string,
+ strlen(smaps_string)));
+}
+
} // namespace
TEST(ProcessMemoryMapsDumpProviderTest, ParseProcSmaps) {
- const uint32 kProtR = ProcessMemoryMaps::VMRegion::kProtectionFlagsRead;
- const uint32 kProtW = ProcessMemoryMaps::VMRegion::kProtectionFlagsWrite;
- const uint32 kProtX = ProcessMemoryMaps::VMRegion::kProtectionFlagsExec;
+ const uint32_t kProtR = ProcessMemoryMaps::VMRegion::kProtectionFlagsRead;
+ const uint32_t kProtW = ProcessMemoryMaps::VMRegion::kProtectionFlagsWrite;
+ const uint32_t kProtX = ProcessMemoryMaps::VMRegion::kProtectionFlagsExec;
+ const MemoryDumpArgs dump_args = {MemoryDumpLevelOfDetail::DETAILED};
auto pmmdp = ProcessMemoryMapsDumpProvider::GetInstance();
- // Emulate a non-existent /proc/self/smaps.
- ProcessMemoryDump pmd_invalid(nullptr /* session_state */);
- std::ifstream non_existent_file("/tmp/does-not-exist");
- ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = &non_existent_file;
- CHECK_EQ(false, non_existent_file.good());
- pmmdp->OnMemoryDump(&pmd_invalid);
- ASSERT_FALSE(pmd_invalid.has_process_mmaps());
-
// Emulate an empty /proc/self/smaps.
- std::ifstream empty_file("/dev/null");
- ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = &empty_file;
- CHECK_EQ(true, empty_file.good());
- pmmdp->OnMemoryDump(&pmd_invalid);
+ ProcessMemoryDump pmd_invalid(nullptr /* session_state */);
+ ScopedFILE empty_file(OpenFile(FilePath("/dev/null"), "r"));
+ ASSERT_TRUE(empty_file.get());
+ ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = empty_file.get();
+ pmmdp->OnMemoryDump(dump_args, &pmd_invalid);
ASSERT_FALSE(pmd_invalid.has_process_mmaps());
// Parse the 1st smaps file.
ProcessMemoryDump pmd_1(nullptr /* session_state */);
- std::istringstream test_smaps_1(kTestSmaps1);
- ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = &test_smaps_1;
- pmmdp->OnMemoryDump(&pmd_1);
+ ScopedFILE temp_file1;
+ CreateAndSetSmapsFileForTesting(kTestSmaps1, temp_file1);
+ ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = temp_file1.get();
+ pmmdp->OnMemoryDump(dump_args, &pmd_1);
ASSERT_TRUE(pmd_1.has_process_mmaps());
const auto& regions_1 = pmd_1.process_mmaps()->vm_regions();
ASSERT_EQ(2UL, regions_1.size());
@@ -161,9 +167,10 @@ TEST(ProcessMemoryMapsDumpProviderTest, ParseProcSmaps) {
// Parse the 2nd smaps file.
ProcessMemoryDump pmd_2(nullptr /* session_state */);
- std::istringstream test_smaps_2(kTestSmaps2);
- ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = &test_smaps_2;
- pmmdp->OnMemoryDump(&pmd_2);
+ ScopedFILE temp_file2;
+ CreateAndSetSmapsFileForTesting(kTestSmaps2, temp_file2);
+ ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = temp_file2.get();
+ pmmdp->OnMemoryDump(dump_args, &pmd_2);
ASSERT_TRUE(pmd_2.has_process_mmaps());
const auto& regions_2 = pmd_2.process_mmaps()->vm_regions();
ASSERT_EQ(1UL, regions_2.size());
@@ -178,7 +185,6 @@ TEST(ProcessMemoryMapsDumpProviderTest, ParseProcSmaps) {
EXPECT_EQ(4 * 1024UL, regions_2[0].byte_stats_private_dirty_resident);
EXPECT_EQ(0 * 1024UL, regions_2[0].byte_stats_swapped);
}
-#endif // defined(OS_LINUX) || defined(OS_ANDROID)
} // namespace trace_event
} // namespace base
diff --git a/base/trace_event/process_memory_totals.cc b/base/trace_event/process_memory_totals.cc
index 1270924fbf..de27ab3d9d 100644
--- a/base/trace_event/process_memory_totals.cc
+++ b/base/trace_event/process_memory_totals.cc
@@ -17,6 +17,8 @@ ProcessMemoryTotals::ProcessMemoryTotals()
is_peak_rss_resetable_(false) {
}
+ProcessMemoryTotals::~ProcessMemoryTotals() {}
+
void ProcessMemoryTotals::AsValueInto(TracedValue* value) const {
value->SetString("resident_set_bytes",
StringPrintf("%" PRIx64, resident_set_bytes_));
@@ -25,11 +27,21 @@ void ProcessMemoryTotals::AsValueInto(TracedValue* value) const {
StringPrintf("%" PRIx64, peak_resident_set_bytes_));
value->SetBoolean("is_peak_rss_resetable", is_peak_rss_resetable_);
}
+
+ for (const auto it : extra_fields_) {
+ value->SetString(it.first, StringPrintf("%" PRIx64, it.second));
+ }
}
void ProcessMemoryTotals::Clear() {
resident_set_bytes_ = 0;
}
+void ProcessMemoryTotals::SetExtraFieldInBytes(const char* name,
+ uint64_t value) {
+ DCHECK_EQ(0u, extra_fields_.count(name));
+ extra_fields_[name] = value;
+}
+
} // namespace trace_event
} // namespace base
diff --git a/base/trace_event/process_memory_totals.h b/base/trace_event/process_memory_totals.h
index 1bf8bdcd7b..329967a6ee 100644
--- a/base/trace_event/process_memory_totals.h
+++ b/base/trace_event/process_memory_totals.h
@@ -5,8 +5,12 @@
#ifndef BASE_TRACE_EVENT_PROCESS_MEMORY_TOTALS_H_
#define BASE_TRACE_EVENT_PROCESS_MEMORY_TOTALS_H_
+#include <stdint.h>
+
+#include <map>
+
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
namespace base {
namespace trace_event {
@@ -17,6 +21,7 @@ class TracedValue;
class BASE_EXPORT ProcessMemoryTotals {
public:
ProcessMemoryTotals();
+ ~ProcessMemoryTotals();
// Called at trace generation time to populate the TracedValue.
void AsValueInto(TracedValue* value) const;
@@ -24,11 +29,11 @@ class BASE_EXPORT ProcessMemoryTotals {
// Clears up all the data collected.
void Clear();
- uint64 resident_set_bytes() const { return resident_set_bytes_; }
- void set_resident_set_bytes(uint64 value) { resident_set_bytes_ = value; }
+ uint64_t resident_set_bytes() const { return resident_set_bytes_; }
+ void set_resident_set_bytes(uint64_t value) { resident_set_bytes_ = value; }
- uint64 peak_resident_set_bytes() const { return peak_resident_set_bytes_; }
- void set_peak_resident_set_bytes(uint64 value) {
+ uint64_t peak_resident_set_bytes() const { return peak_resident_set_bytes_; }
+ void set_peak_resident_set_bytes(uint64_t value) {
peak_resident_set_bytes_ = value;
}
@@ -39,11 +44,16 @@ class BASE_EXPORT ProcessMemoryTotals {
bool is_peak_rss_resetable() const { return is_peak_rss_resetable_; }
void set_is_peak_rss_resetable(bool value) { is_peak_rss_resetable_ = value; }
+ void SetExtraFieldInBytes(const char* name, uint64_t value);
+
private:
- uint64 resident_set_bytes_;
- uint64 peak_resident_set_bytes_;
+ uint64_t resident_set_bytes_;
+ uint64_t peak_resident_set_bytes_;
bool is_peak_rss_resetable_;
+ // Extra metrics for OS-specific statistics.
+ std::map<const char*, uint64_t> extra_fields_;
+
DISALLOW_COPY_AND_ASSIGN(ProcessMemoryTotals);
};
diff --git a/base/trace_event/process_memory_totals_dump_provider.cc b/base/trace_event/process_memory_totals_dump_provider.cc
index 37f9bed68c..917dcf0940 100644
--- a/base/trace_event/process_memory_totals_dump_provider.cc
+++ b/base/trace_event/process_memory_totals_dump_provider.cc
@@ -4,9 +4,12 @@
#include "base/trace_event/process_memory_totals_dump_provider.h"
+#include <stddef.h>
+
#include "base/process/process_metrics.h"
#include "base/trace_event/process_memory_dump.h"
#include "base/trace_event/process_memory_totals.h"
+#include "build/build_config.h"
#if defined(OS_LINUX) || defined(OS_ANDROID)
#include <fcntl.h>
@@ -23,18 +26,7 @@ namespace base {
namespace trace_event {
// static
-uint64 ProcessMemoryTotalsDumpProvider::rss_bytes_for_testing = 0;
-
-namespace {
-
-ProcessMetrics* CreateProcessMetricsForCurrentProcess() {
-#if !defined(OS_MACOSX) || defined(OS_IOS)
- return ProcessMetrics::CreateProcessMetrics(GetCurrentProcessHandle());
-#else
- return ProcessMetrics::CreateProcessMetrics(GetCurrentProcessHandle(), NULL);
-#endif
-}
-} // namespace
+uint64_t ProcessMemoryTotalsDumpProvider::rss_bytes_for_testing = 0;
// static
ProcessMemoryTotalsDumpProvider*
@@ -45,20 +37,21 @@ ProcessMemoryTotalsDumpProvider::GetInstance() {
}
ProcessMemoryTotalsDumpProvider::ProcessMemoryTotalsDumpProvider()
- : process_metrics_(CreateProcessMetricsForCurrentProcess()) {
-}
+ : process_metrics_(ProcessMetrics::CreateCurrentProcessMetrics()) {}
ProcessMemoryTotalsDumpProvider::~ProcessMemoryTotalsDumpProvider() {
}
// Called at trace dump point time. Creates a snapshot the memory counters for
// the current process.
-bool ProcessMemoryTotalsDumpProvider::OnMemoryDump(ProcessMemoryDump* pmd) {
- const uint64 rss_bytes = rss_bytes_for_testing
- ? rss_bytes_for_testing
- : process_metrics_->GetWorkingSetSize();
+bool ProcessMemoryTotalsDumpProvider::OnMemoryDump(
+ const MemoryDumpArgs& /* args */,
+ ProcessMemoryDump* pmd) {
+ const uint64_t rss_bytes = rss_bytes_for_testing
+ ? rss_bytes_for_testing
+ : process_metrics_->GetWorkingSetSize();
- uint64 peak_rss_bytes = 0;
+ uint64_t peak_rss_bytes = 0;
#if !defined(OS_IOS)
peak_rss_bytes = process_metrics_->GetPeakWorkingSetSize();
@@ -76,6 +69,13 @@ bool ProcessMemoryTotalsDumpProvider::OnMemoryDump(ProcessMemoryDump* pmd) {
}
close(clear_refs_fd);
}
+#elif defined(OS_MACOSX)
+ size_t private_bytes;
+ bool res = process_metrics_->GetMemoryBytes(&private_bytes,
+ nullptr /* shared_bytes */);
+ if (res) {
+ pmd->process_totals()->SetExtraFieldInBytes("private_bytes", private_bytes);
+ }
#endif // defined(OS_LINUX) || defined(OS_ANDROID)
#endif // !defined(OS_IOS)
diff --git a/base/trace_event/process_memory_totals_dump_provider.h b/base/trace_event/process_memory_totals_dump_provider.h
index 6c86eb6b4a..d9573d31e1 100644
--- a/base/trace_event/process_memory_totals_dump_provider.h
+++ b/base/trace_event/process_memory_totals_dump_provider.h
@@ -5,7 +5,10 @@
#ifndef BASE_TRACE_EVENT_PROCESS_MEMORY_TOTALS_DUMP_PROVIDER_H_
#define BASE_TRACE_EVENT_PROCESS_MEMORY_TOTALS_DUMP_PROVIDER_H_
+#include <stdint.h>
+
#include "base/gtest_prod_util.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/singleton.h"
#include "base/trace_event/memory_dump_provider.h"
@@ -22,13 +25,14 @@ class BASE_EXPORT ProcessMemoryTotalsDumpProvider : public MemoryDumpProvider {
static ProcessMemoryTotalsDumpProvider* GetInstance();
// MemoryDumpProvider implementation.
- bool OnMemoryDump(ProcessMemoryDump* pmd) override;
+ bool OnMemoryDump(const MemoryDumpArgs& args,
+ ProcessMemoryDump* pmd) override;
private:
friend struct DefaultSingletonTraits<ProcessMemoryTotalsDumpProvider>;
FRIEND_TEST_ALL_PREFIXES(ProcessMemoryTotalsDumpProviderTest, DumpRSS);
- static uint64 rss_bytes_for_testing;
+ static uint64_t rss_bytes_for_testing;
ProcessMemoryTotalsDumpProvider();
~ProcessMemoryTotalsDumpProvider() override;
diff --git a/base/trace_event/process_memory_totals_dump_provider_unittest.cc b/base/trace_event/process_memory_totals_dump_provider_unittest.cc
index f9bb6c071c..d3f517e283 100644
--- a/base/trace_event/process_memory_totals_dump_provider_unittest.cc
+++ b/base/trace_event/process_memory_totals_dump_provider_unittest.cc
@@ -4,6 +4,9 @@
#include "base/trace_event/process_memory_totals_dump_provider.h"
+#include <stddef.h>
+#include <stdint.h>
+
#include "base/trace_event/process_memory_dump.h"
#include "base/trace_event/process_memory_totals.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -12,26 +15,28 @@ namespace base {
namespace trace_event {
TEST(ProcessMemoryTotalsDumpProviderTest, DumpRSS) {
+ const MemoryDumpArgs high_detail_args = {MemoryDumpLevelOfDetail::DETAILED};
auto pmtdp = ProcessMemoryTotalsDumpProvider::GetInstance();
scoped_ptr<ProcessMemoryDump> pmd_before(new ProcessMemoryDump(nullptr));
scoped_ptr<ProcessMemoryDump> pmd_after(new ProcessMemoryDump(nullptr));
ProcessMemoryTotalsDumpProvider::rss_bytes_for_testing = 1024;
- pmtdp->OnMemoryDump(pmd_before.get());
+ pmtdp->OnMemoryDump(high_detail_args, pmd_before.get());
// Pretend that the RSS of the process increased of +1M.
const size_t kAllocSize = 1048576;
ProcessMemoryTotalsDumpProvider::rss_bytes_for_testing += kAllocSize;
- pmtdp->OnMemoryDump(pmd_after.get());
+ pmtdp->OnMemoryDump(high_detail_args, pmd_after.get());
ProcessMemoryTotalsDumpProvider::rss_bytes_for_testing = 0;
ASSERT_TRUE(pmd_before->has_process_totals());
ASSERT_TRUE(pmd_after->has_process_totals());
- const uint64 rss_before = pmd_before->process_totals()->resident_set_bytes();
- const uint64 rss_after = pmd_after->process_totals()->resident_set_bytes();
+ const uint64_t rss_before =
+ pmd_before->process_totals()->resident_set_bytes();
+ const uint64_t rss_after = pmd_after->process_totals()->resident_set_bytes();
EXPECT_NE(0U, rss_before);
EXPECT_NE(0U, rss_after);
diff --git a/base/trace_event/trace_buffer.cc b/base/trace_event/trace_buffer.cc
new file mode 100644
index 0000000000..3b2069a222
--- /dev/null
+++ b/base/trace_event/trace_buffer.cc
@@ -0,0 +1,400 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/trace_buffer.h"
+
+#include <utility>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/trace_event/trace_event_impl.h"
+
+namespace base {
+namespace trace_event {
+
+namespace {
+
+class TraceBufferRingBuffer : public TraceBuffer {
+ public:
+ TraceBufferRingBuffer(size_t max_chunks)
+ : max_chunks_(max_chunks),
+ recyclable_chunks_queue_(new size_t[queue_capacity()]),
+ queue_head_(0),
+ queue_tail_(max_chunks),
+ current_iteration_index_(0),
+ current_chunk_seq_(1) {
+ chunks_.reserve(max_chunks);
+ for (size_t i = 0; i < max_chunks; ++i)
+ recyclable_chunks_queue_[i] = i;
+ }
+
+ scoped_ptr<TraceBufferChunk> GetChunk(size_t* index) override {
+ // Because the number of threads is much less than the number of chunks,
+ // the queue should never be empty.
+ DCHECK(!QueueIsEmpty());
+
+ *index = recyclable_chunks_queue_[queue_head_];
+ queue_head_ = NextQueueIndex(queue_head_);
+ current_iteration_index_ = queue_head_;
+
+ if (*index >= chunks_.size())
+ chunks_.resize(*index + 1);
+
+ TraceBufferChunk* chunk = chunks_[*index].release();
+ chunks_[*index] = NULL; // Put NULL in the slot of a in-flight chunk.
+ if (chunk)
+ chunk->Reset(current_chunk_seq_++);
+ else
+ chunk = new TraceBufferChunk(current_chunk_seq_++);
+
+ return scoped_ptr<TraceBufferChunk>(chunk);
+ }
+
+ void ReturnChunk(size_t index, scoped_ptr<TraceBufferChunk> chunk) override {
+ // When this method is called, the queue should not be full because it
+ // can contain all chunks including the one to be returned.
+ DCHECK(!QueueIsFull());
+ DCHECK(chunk);
+ DCHECK_LT(index, chunks_.size());
+ DCHECK(!chunks_[index]);
+ chunks_[index] = std::move(chunk);
+ recyclable_chunks_queue_[queue_tail_] = index;
+ queue_tail_ = NextQueueIndex(queue_tail_);
+ }
+
+ bool IsFull() const override { return false; }
+
+ size_t Size() const override {
+ // This is approximate because not all of the chunks are full.
+ return chunks_.size() * TraceBufferChunk::kTraceBufferChunkSize;
+ }
+
+ size_t Capacity() const override {
+ return max_chunks_ * TraceBufferChunk::kTraceBufferChunkSize;
+ }
+
+ TraceEvent* GetEventByHandle(TraceEventHandle handle) override {
+ if (handle.chunk_index >= chunks_.size())
+ return NULL;
+ TraceBufferChunk* chunk = chunks_[handle.chunk_index].get();
+ if (!chunk || chunk->seq() != handle.chunk_seq)
+ return NULL;
+ return chunk->GetEventAt(handle.event_index);
+ }
+
+ const TraceBufferChunk* NextChunk() override {
+ if (chunks_.empty())
+ return NULL;
+
+ while (current_iteration_index_ != queue_tail_) {
+ size_t chunk_index = recyclable_chunks_queue_[current_iteration_index_];
+ current_iteration_index_ = NextQueueIndex(current_iteration_index_);
+ if (chunk_index >= chunks_.size()) // Skip uninitialized chunks.
+ continue;
+ DCHECK(chunks_[chunk_index]);
+ return chunks_[chunk_index].get();
+ }
+ return NULL;
+ }
+
+ scoped_ptr<TraceBuffer> CloneForIteration() const override {
+ scoped_ptr<ClonedTraceBuffer> cloned_buffer(new ClonedTraceBuffer());
+ for (size_t queue_index = queue_head_; queue_index != queue_tail_;
+ queue_index = NextQueueIndex(queue_index)) {
+ size_t chunk_index = recyclable_chunks_queue_[queue_index];
+ if (chunk_index >= chunks_.size()) // Skip uninitialized chunks.
+ continue;
+ TraceBufferChunk* chunk = chunks_[chunk_index].get();
+ cloned_buffer->chunks_.push_back(chunk ? chunk->Clone() : NULL);
+ }
+ return std::move(cloned_buffer);
+ }
+
+ void EstimateTraceMemoryOverhead(
+ TraceEventMemoryOverhead* overhead) override {
+ overhead->Add("TraceBufferRingBuffer", sizeof(*this));
+ for (size_t queue_index = queue_head_; queue_index != queue_tail_;
+ queue_index = NextQueueIndex(queue_index)) {
+ size_t chunk_index = recyclable_chunks_queue_[queue_index];
+ if (chunk_index >= chunks_.size()) // Skip uninitialized chunks.
+ continue;
+ chunks_[chunk_index]->EstimateTraceMemoryOverhead(overhead);
+ }
+ }
+
+ private:
+ class ClonedTraceBuffer : public TraceBuffer {
+ public:
+ ClonedTraceBuffer() : current_iteration_index_(0) {}
+
+ // The only implemented method.
+ const TraceBufferChunk* NextChunk() override {
+ return current_iteration_index_ < chunks_.size()
+ ? chunks_[current_iteration_index_++].get()
+ : NULL;
+ }
+
+ scoped_ptr<TraceBufferChunk> GetChunk(size_t* /* index */) override {
+ NOTIMPLEMENTED();
+ return scoped_ptr<TraceBufferChunk>();
+ }
+ void ReturnChunk(size_t /*index*/, scoped_ptr<TraceBufferChunk>) override {
+ NOTIMPLEMENTED();
+ }
+ bool IsFull() const override { return false; }
+ size_t Size() const override { return 0; }
+ size_t Capacity() const override { return 0; }
+ TraceEvent* GetEventByHandle(TraceEventHandle /* handle */) override {
+ return NULL;
+ }
+ scoped_ptr<TraceBuffer> CloneForIteration() const override {
+ NOTIMPLEMENTED();
+ return scoped_ptr<TraceBuffer>();
+ }
+ void EstimateTraceMemoryOverhead(
+ TraceEventMemoryOverhead* /* overhead */) override {
+ NOTIMPLEMENTED();
+ }
+
+ size_t current_iteration_index_;
+ std::vector<scoped_ptr<TraceBufferChunk>> chunks_;
+ };
+
+ bool QueueIsEmpty() const { return queue_head_ == queue_tail_; }
+
+ size_t QueueSize() const {
+ return queue_tail_ > queue_head_
+ ? queue_tail_ - queue_head_
+ : queue_tail_ + queue_capacity() - queue_head_;
+ }
+
+ bool QueueIsFull() const { return QueueSize() == queue_capacity() - 1; }
+
+ size_t queue_capacity() const {
+ // One extra space to help distinguish full state and empty state.
+ return max_chunks_ + 1;
+ }
+
+ size_t NextQueueIndex(size_t index) const {
+ index++;
+ if (index >= queue_capacity())
+ index = 0;
+ return index;
+ }
+
+ size_t max_chunks_;
+ std::vector<scoped_ptr<TraceBufferChunk>> chunks_;
+
+ scoped_ptr<size_t[]> recyclable_chunks_queue_;
+ size_t queue_head_;
+ size_t queue_tail_;
+
+ size_t current_iteration_index_;
+ uint32_t current_chunk_seq_;
+
+ DISALLOW_COPY_AND_ASSIGN(TraceBufferRingBuffer);
+};
+
+class TraceBufferVector : public TraceBuffer {
+ public:
+ TraceBufferVector(size_t max_chunks)
+ : in_flight_chunk_count_(0),
+ current_iteration_index_(0),
+ max_chunks_(max_chunks) {
+ chunks_.reserve(max_chunks_);
+ }
+
+ scoped_ptr<TraceBufferChunk> GetChunk(size_t* index) override {
+ // This function may be called when adding normal events or indirectly from
+ // AddMetadataEventsWhileLocked(). We can not DECHECK(!IsFull()) because we
+ // have to add the metadata events and flush thread-local buffers even if
+ // the buffer is full.
+ *index = chunks_.size();
+ chunks_.push_back(NULL); // Put NULL in the slot of a in-flight chunk.
+ ++in_flight_chunk_count_;
+ // + 1 because zero chunk_seq is not allowed.
+ return scoped_ptr<TraceBufferChunk>(
+ new TraceBufferChunk(static_cast<uint32_t>(*index) + 1));
+ }
+
+ void ReturnChunk(size_t index, scoped_ptr<TraceBufferChunk> chunk) override {
+ DCHECK_GT(in_flight_chunk_count_, 0u);
+ DCHECK_LT(index, chunks_.size());
+ DCHECK(!chunks_[index]);
+ --in_flight_chunk_count_;
+ chunks_[index] = chunk.release();
+ }
+
+ bool IsFull() const override { return chunks_.size() >= max_chunks_; }
+
+ size_t Size() const override {
+ // This is approximate because not all of the chunks are full.
+ return chunks_.size() * TraceBufferChunk::kTraceBufferChunkSize;
+ }
+
+ size_t Capacity() const override {
+ return max_chunks_ * TraceBufferChunk::kTraceBufferChunkSize;
+ }
+
+ TraceEvent* GetEventByHandle(TraceEventHandle handle) override {
+ if (handle.chunk_index >= chunks_.size())
+ return NULL;
+ TraceBufferChunk* chunk = chunks_[handle.chunk_index];
+ if (!chunk || chunk->seq() != handle.chunk_seq)
+ return NULL;
+ return chunk->GetEventAt(handle.event_index);
+ }
+
+ const TraceBufferChunk* NextChunk() override {
+ while (current_iteration_index_ < chunks_.size()) {
+ // Skip in-flight chunks.
+ const TraceBufferChunk* chunk = chunks_[current_iteration_index_++];
+ if (chunk)
+ return chunk;
+ }
+ return NULL;
+ }
+
+ scoped_ptr<TraceBuffer> CloneForIteration() const override {
+ NOTIMPLEMENTED();
+ return scoped_ptr<TraceBuffer>();
+ }
+
+ void EstimateTraceMemoryOverhead(
+ TraceEventMemoryOverhead* overhead) override {
+ const size_t chunks_ptr_vector_allocated_size =
+ sizeof(*this) + max_chunks_ * sizeof(decltype(chunks_)::value_type);
+ const size_t chunks_ptr_vector_resident_size =
+ sizeof(*this) + chunks_.size() * sizeof(decltype(chunks_)::value_type);
+ overhead->Add("TraceBufferVector", chunks_ptr_vector_allocated_size,
+ chunks_ptr_vector_resident_size);
+ for (size_t i = 0; i < chunks_.size(); ++i) {
+ TraceBufferChunk* chunk = chunks_[i];
+ // Skip the in-flight (nullptr) chunks. They will be accounted by the
+ // per-thread-local dumpers, see ThreadLocalEventBuffer::OnMemoryDump.
+ if (chunk)
+ chunk->EstimateTraceMemoryOverhead(overhead);
+ }
+ }
+
+ private:
+ size_t in_flight_chunk_count_;
+ size_t current_iteration_index_;
+ size_t max_chunks_;
+ ScopedVector<TraceBufferChunk> chunks_;
+
+ DISALLOW_COPY_AND_ASSIGN(TraceBufferVector);
+};
+
+} // namespace
+
+TraceBufferChunk::TraceBufferChunk(uint32_t seq) : next_free_(0), seq_(seq) {}
+
+TraceBufferChunk::~TraceBufferChunk() {}
+
+void TraceBufferChunk::Reset(uint32_t new_seq) {
+ for (size_t i = 0; i < next_free_; ++i)
+ chunk_[i].Reset();
+ next_free_ = 0;
+ seq_ = new_seq;
+ cached_overhead_estimate_.reset();
+}
+
+TraceEvent* TraceBufferChunk::AddTraceEvent(size_t* event_index) {
+ DCHECK(!IsFull());
+ *event_index = next_free_++;
+ return &chunk_[*event_index];
+}
+
+scoped_ptr<TraceBufferChunk> TraceBufferChunk::Clone() const {
+ scoped_ptr<TraceBufferChunk> cloned_chunk(new TraceBufferChunk(seq_));
+ cloned_chunk->next_free_ = next_free_;
+ for (size_t i = 0; i < next_free_; ++i)
+ cloned_chunk->chunk_[i].CopyFrom(chunk_[i]);
+ return cloned_chunk;
+}
+
+void TraceBufferChunk::EstimateTraceMemoryOverhead(
+ TraceEventMemoryOverhead* overhead) {
+ if (!cached_overhead_estimate_) {
+ cached_overhead_estimate_.reset(new TraceEventMemoryOverhead);
+
+ // When estimating the size of TraceBufferChunk, exclude the array of trace
+ // events, as they are computed individually below.
+ cached_overhead_estimate_->Add("TraceBufferChunk",
+ sizeof(*this) - sizeof(chunk_));
+ }
+
+ const size_t num_cached_estimated_events =
+ cached_overhead_estimate_->GetCount("TraceEvent");
+ DCHECK_LE(num_cached_estimated_events, size());
+
+ if (IsFull() && num_cached_estimated_events == size()) {
+ overhead->Update(*cached_overhead_estimate_);
+ return;
+ }
+
+ for (size_t i = num_cached_estimated_events; i < size(); ++i)
+ chunk_[i].EstimateTraceMemoryOverhead(cached_overhead_estimate_.get());
+
+ if (IsFull()) {
+ cached_overhead_estimate_->AddSelf();
+ } else {
+ // The unused TraceEvents in |chunks_| are not cached. They will keep
+ // changing as new TraceEvents are added to this chunk, so they are
+ // computed on the fly.
+ const size_t num_unused_trace_events = capacity() - size();
+ overhead->Add("TraceEvent (unused)",
+ num_unused_trace_events * sizeof(TraceEvent));
+ }
+
+ overhead->Update(*cached_overhead_estimate_);
+}
+
+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("]");
+}
+
+TraceBuffer* TraceBuffer::CreateTraceBufferRingBuffer(size_t max_chunks) {
+ return new TraceBufferRingBuffer(max_chunks);
+}
+
+TraceBuffer* TraceBuffer::CreateTraceBufferVectorOfSize(size_t max_chunks) {
+ return new TraceBufferVector(max_chunks);
+}
+
+} // namespace trace_event
+} // namespace base
diff --git a/base/trace_event/trace_buffer.h b/base/trace_event/trace_buffer.h
new file mode 100644
index 0000000000..a7b80595b5
--- /dev/null
+++ b/base/trace_event/trace_buffer.h
@@ -0,0 +1,133 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_TRACE_BUFFER_H_
+#define BASE_TRACE_EVENT_TRACE_BUFFER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/base_export.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_impl.h"
+
+namespace base {
+
+namespace trace_event {
+
+// TraceBufferChunk is the basic unit of TraceBuffer.
+class BASE_EXPORT TraceBufferChunk {
+ public:
+ explicit TraceBufferChunk(uint32_t seq);
+ ~TraceBufferChunk();
+
+ void Reset(uint32_t new_seq);
+ TraceEvent* AddTraceEvent(size_t* event_index);
+ bool IsFull() const { return next_free_ == kTraceBufferChunkSize; }
+
+ uint32_t seq() const { return seq_; }
+ size_t capacity() const { return kTraceBufferChunkSize; }
+ size_t size() const { return next_free_; }
+
+ TraceEvent* GetEventAt(size_t index) {
+ DCHECK(index < size());
+ return &chunk_[index];
+ }
+ const TraceEvent* GetEventAt(size_t index) const {
+ DCHECK(index < size());
+ return &chunk_[index];
+ }
+
+ scoped_ptr<TraceBufferChunk> Clone() const;
+
+ void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead);
+
+ // These values must be kept consistent with the numbers of bits of
+ // chunk_index and event_index fields in TraceEventHandle
+ // (in trace_event_impl.h).
+ static const size_t kMaxChunkIndex = (1u << 26) - 1;
+ static const size_t kTraceBufferChunkSize = 64;
+
+ private:
+ size_t next_free_;
+ scoped_ptr<TraceEventMemoryOverhead> cached_overhead_estimate_;
+ TraceEvent chunk_[kTraceBufferChunkSize];
+ uint32_t seq_;
+};
+
+// TraceBuffer holds the events as they are collected.
+class BASE_EXPORT TraceBuffer {
+ public:
+ virtual ~TraceBuffer() {}
+
+ virtual scoped_ptr<TraceBufferChunk> GetChunk(size_t* index) = 0;
+ virtual void ReturnChunk(size_t index,
+ scoped_ptr<TraceBufferChunk> chunk) = 0;
+
+ virtual bool IsFull() const = 0;
+ virtual size_t Size() const = 0;
+ virtual size_t Capacity() const = 0;
+ virtual TraceEvent* GetEventByHandle(TraceEventHandle handle) = 0;
+
+ // For iteration. Each TraceBuffer can only be iterated once.
+ virtual const TraceBufferChunk* NextChunk() = 0;
+
+ virtual scoped_ptr<TraceBuffer> CloneForIteration() const = 0;
+
+ // Computes an estimate of the size of the buffer, including all the retained
+ // objects.
+ virtual void EstimateTraceMemoryOverhead(
+ TraceEventMemoryOverhead* overhead) = 0;
+
+ static TraceBuffer* CreateTraceBufferRingBuffer(size_t max_chunks);
+ static TraceBuffer* CreateTraceBufferVectorOfSize(size_t max_chunks);
+};
+
+// TraceResultBuffer collects and converts trace fragments returned by TraceLog
+// to JSON output.
+class BASE_EXPORT TraceResultBuffer {
+ public:
+ typedef base::Callback<void(const std::string&)> 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_;
+};
+
+} // namespace trace_event
+} // namespace base
+
+#endif // BASE_TRACE_EVENT_TRACE_BUFFER_H_
diff --git a/base/trace_event/trace_config.cc b/base/trace_event/trace_config.cc
index ef9b8925ff..8e11078ebc 100644
--- a/base/trace_event/trace_config.cc
+++ b/base/trace_event/trace_config.cc
@@ -4,11 +4,18 @@
#include "base/trace_event/trace_config.h"
+#include <stddef.h>
+
+#include <utility>
+
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
+#include "base/strings/pattern.h"
#include "base/strings/string_split.h"
#include "base/strings/string_tokenizer.h"
#include "base/strings/stringprintf.h"
+#include "base/trace_event/memory_dump_manager.h"
+#include "base/trace_event/memory_dump_request_args.h"
#include "base/trace_event/trace_event.h"
namespace base {
@@ -36,6 +43,37 @@ const char kSyntheticDelaysParam[] = "synthetic_delays";
const char kSyntheticDelayCategoryFilterPrefix[] = "DELAY(";
+// String parameters that is used to parse memory dump config in trace config
+// string.
+const char kMemoryDumpConfigParam[] = "memory_dump_config";
+const char kTriggersParam[] = "triggers";
+const char kPeriodicIntervalParam[] = "periodic_interval_ms";
+const char kModeParam[] = "mode";
+
+// Default configuration of memory dumps.
+const TraceConfig::MemoryDumpTriggerConfig kDefaultHeavyMemoryDumpTrigger = {
+ 2000, // periodic_interval_ms
+ MemoryDumpLevelOfDetail::DETAILED};
+const TraceConfig::MemoryDumpTriggerConfig kDefaultLightMemoryDumpTrigger = {
+ 250, // periodic_interval_ms
+ MemoryDumpLevelOfDetail::LIGHT};
+
+class ConvertableTraceConfigToTraceFormat
+ : public base::trace_event::ConvertableToTraceFormat {
+ public:
+ explicit ConvertableTraceConfigToTraceFormat(const TraceConfig& trace_config)
+ : trace_config_(trace_config) {}
+ void AppendAsTraceFormat(std::string* out) const override {
+ out->append(trace_config_.ToString());
+ }
+
+ protected:
+ ~ConvertableTraceConfigToTraceFormat() override {}
+
+ private:
+ const TraceConfig trace_config_;
+};
+
} // namespace
TraceConfig::TraceConfig() {
@@ -81,11 +119,11 @@ TraceConfig::TraceConfig(const TraceConfig& tc)
enable_sampling_(tc.enable_sampling_),
enable_systrace_(tc.enable_systrace_),
enable_argument_filter_(tc.enable_argument_filter_),
+ memory_dump_config_(tc.memory_dump_config_),
included_categories_(tc.included_categories_),
disabled_categories_(tc.disabled_categories_),
excluded_categories_(tc.excluded_categories_),
- synthetic_delays_(tc.synthetic_delays_) {
-}
+ synthetic_delays_(tc.synthetic_delays_) {}
TraceConfig::~TraceConfig() {
}
@@ -98,6 +136,7 @@ TraceConfig& TraceConfig::operator=(const TraceConfig& rhs) {
enable_sampling_ = rhs.enable_sampling_;
enable_systrace_ = rhs.enable_systrace_;
enable_argument_filter_ = rhs.enable_argument_filter_;
+ memory_dump_config_ = rhs.memory_dump_config_;
included_categories_ = rhs.included_categories_;
disabled_categories_ = rhs.disabled_categories_;
excluded_categories_ = rhs.excluded_categories_;
@@ -119,6 +158,11 @@ std::string TraceConfig::ToString() const {
return json;
}
+scoped_refptr<ConvertableToTraceFormat>
+TraceConfig::AsConvertableToTraceFormat() const {
+ return new ConvertableTraceConfigToTraceFormat(*this);
+}
+
std::string TraceConfig::ToCategoryFilterString() const {
std::string filter_string;
WriteCategoryFilterString(included_categories_, &filter_string, true);
@@ -147,8 +191,8 @@ bool TraceConfig::IsCategoryGroupEnabled(
if (IsCategoryEnabled(category_group_token.c_str())) {
return true;
}
- if (!MatchPattern(category_group_token.c_str(),
- TRACE_DISABLED_BY_DEFAULT("*")))
+ if (!base::MatchPattern(category_group_token.c_str(),
+ TRACE_DISABLED_BY_DEFAULT("*")))
had_enabled_by_default = true;
}
// Do a second pass to check for explicitly disabled categories
@@ -160,7 +204,7 @@ bool TraceConfig::IsCategoryGroupEnabled(
for (StringList::const_iterator ci = excluded_categories_.begin();
ci != excluded_categories_.end();
++ci) {
- if (MatchPattern(category_group_token.c_str(), ci->c_str())) {
+ if (base::MatchPattern(category_group_token.c_str(), ci->c_str())) {
// Current token of category_group_name is present in excluded_list.
// Flag the exclusion and proceed further to check if any of the
// remaining categories of category_group_name is not present in the
@@ -169,9 +213,13 @@ bool TraceConfig::IsCategoryGroupEnabled(
break;
}
// One of the category of category_group_name is not present in
- // excluded_ list. So, it has to be included_ list. Enable the
- // category_group_name for recording.
- category_group_disabled = false;
+ // excluded_ list. So, if it's not a disabled-by-default category,
+ // it has to be included_ list. Enable the category_group_name
+ // for recording.
+ if (!base::MatchPattern(category_group_token.c_str(),
+ TRACE_DISABLED_BY_DEFAULT("*"))) {
+ category_group_disabled = false;
+ }
}
// One of the categories present in category_group_name is not present in
// excluded_ list. Implies this category_group_name group can be enabled
@@ -206,6 +254,10 @@ void TraceConfig::Merge(const TraceConfig& config) {
included_categories_.clear();
}
+ memory_dump_config_.insert(memory_dump_config_.end(),
+ config.memory_dump_config_.begin(),
+ config.memory_dump_config_.end());
+
disabled_categories_.insert(disabled_categories_.end(),
config.disabled_categories_.begin(),
config.disabled_categories_.end());
@@ -226,6 +278,7 @@ void TraceConfig::Clear() {
disabled_categories_.clear();
excluded_categories_.clear();
synthetic_delays_.clear();
+ memory_dump_config_.clear();
}
void TraceConfig::InitializeDefault() {
@@ -278,23 +331,33 @@ void TraceConfig::InitializeFromConfigString(const std::string& config_string) {
else
enable_argument_filter_ = enable_argument_filter;
-
- base::ListValue* category_list = NULL;
+ base::ListValue* category_list = nullptr;
if (dict->GetList(kIncludedCategoriesParam, &category_list))
SetCategoriesFromIncludedList(*category_list);
if (dict->GetList(kExcludedCategoriesParam, &category_list))
SetCategoriesFromExcludedList(*category_list);
if (dict->GetList(kSyntheticDelaysParam, &category_list))
SetSyntheticDelaysFromList(*category_list);
+
+ if (IsCategoryEnabled(MemoryDumpManager::kTraceCategory)) {
+ // If dump triggers not set, the client is using the legacy with just
+ // category enabled. So, use the default periodic dump config.
+ base::DictionaryValue* memory_dump_config = nullptr;
+ if (dict->GetDictionary(kMemoryDumpConfigParam, &memory_dump_config))
+ SetMemoryDumpConfig(*memory_dump_config);
+ else
+ SetDefaultMemoryDumpConfig();
+ }
}
void TraceConfig::InitializeFromStrings(
const std::string& category_filter_string,
const std::string& trace_options_string) {
if (!category_filter_string.empty()) {
- std::vector<std::string> split;
+ std::vector<std::string> split = base::SplitString(
+ category_filter_string, ",", base::TRIM_WHITESPACE,
+ base::SPLIT_WANT_ALL);
std::vector<std::string>::iterator iter;
- base::SplitString(category_filter_string, ',', &split);
for (iter = split.begin(); iter != split.end(); ++iter) {
std::string category = *iter;
// Ignore empty categories.
@@ -330,9 +393,9 @@ void TraceConfig::InitializeFromStrings(
enable_systrace_ = false;
enable_argument_filter_ = false;
if(!trace_options_string.empty()) {
- std::vector<std::string> split;
+ std::vector<std::string> split = base::SplitString(
+ trace_options_string, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
std::vector<std::string>::iterator iter;
- base::SplitString(trace_options_string, ',', &split);
for (iter = split.begin(); iter != split.end(); ++iter) {
if (*iter == kRecordUntilFull) {
record_mode_ = RECORD_UNTIL_FULL;
@@ -351,6 +414,10 @@ void TraceConfig::InitializeFromStrings(
}
}
}
+
+ if (IsCategoryEnabled(MemoryDumpManager::kTraceCategory)) {
+ SetDefaultMemoryDumpConfig();
+ }
}
void TraceConfig::SetCategoriesFromIncludedList(
@@ -407,7 +474,44 @@ void TraceConfig::AddCategoryToDict(base::DictionaryValue& dict,
list->AppendString(*ci);
}
- dict.Set(param, list.Pass());
+ dict.Set(param, std::move(list));
+}
+
+void TraceConfig::SetMemoryDumpConfig(
+ const base::DictionaryValue& memory_dump_config) {
+ memory_dump_config_.clear();
+
+ const base::ListValue* trigger_list = nullptr;
+ if (!memory_dump_config.GetList(kTriggersParam, &trigger_list) ||
+ trigger_list->GetSize() == 0) {
+ return;
+ }
+
+ for (size_t i = 0; i < trigger_list->GetSize(); ++i) {
+ const base::DictionaryValue* trigger = nullptr;
+ if (!trigger_list->GetDictionary(i, &trigger))
+ continue;
+
+ MemoryDumpTriggerConfig dump_config;
+ int interval = 0;
+
+ if (!trigger->GetInteger(kPeriodicIntervalParam, &interval)) {
+ continue;
+ }
+ DCHECK_GT(interval, 0);
+ dump_config.periodic_interval_ms = static_cast<uint32_t>(interval);
+ std::string level_of_detail_str;
+ trigger->GetString(kModeParam, &level_of_detail_str);
+ dump_config.level_of_detail =
+ StringToMemoryDumpLevelOfDetail(level_of_detail_str);
+ memory_dump_config_.push_back(dump_config);
+ }
+}
+
+void TraceConfig::SetDefaultMemoryDumpConfig() {
+ memory_dump_config_.clear();
+ memory_dump_config_.push_back(kDefaultHeavyMemoryDumpTrigger);
+ memory_dump_config_.push_back(kDefaultLightMemoryDumpTrigger);
}
void TraceConfig::ToDict(base::DictionaryValue& dict) const {
@@ -450,6 +554,26 @@ void TraceConfig::ToDict(base::DictionaryValue& dict) const {
AddCategoryToDict(dict, kIncludedCategoriesParam, categories);
AddCategoryToDict(dict, kExcludedCategoriesParam, excluded_categories_);
AddCategoryToDict(dict, kSyntheticDelaysParam, synthetic_delays_);
+
+ if (IsCategoryEnabled(MemoryDumpManager::kTraceCategory)) {
+ scoped_ptr<base::DictionaryValue> memory_dump_config(
+ new base::DictionaryValue());
+ scoped_ptr<base::ListValue> triggers_list(new base::ListValue());
+ for (const MemoryDumpTriggerConfig& config : memory_dump_config_) {
+ scoped_ptr<base::DictionaryValue> trigger_dict(
+ new base::DictionaryValue());
+ trigger_dict->SetInteger(kPeriodicIntervalParam,
+ static_cast<int>(config.periodic_interval_ms));
+ trigger_dict->SetString(
+ kModeParam, MemoryDumpLevelOfDetailToString(config.level_of_detail));
+ triggers_list->Append(std::move(trigger_dict));
+ }
+
+ // Empty triggers will still be specified explicitly since it means that
+ // the periodic dumps are not enabled.
+ memory_dump_config->Set(kTriggersParam, std::move(triggers_list));
+ dict.Set(kMemoryDumpConfigParam, std::move(memory_dump_config));
+ }
}
std::string TraceConfig::ToTraceOptionsString() const {
@@ -515,17 +639,17 @@ bool TraceConfig::IsCategoryEnabled(const char* category_name) const {
for (ci = disabled_categories_.begin();
ci != disabled_categories_.end();
++ci) {
- if (MatchPattern(category_name, ci->c_str()))
+ if (base::MatchPattern(category_name, ci->c_str()))
return true;
}
- if (MatchPattern(category_name, TRACE_DISABLED_BY_DEFAULT("*")))
+ if (base::MatchPattern(category_name, TRACE_DISABLED_BY_DEFAULT("*")))
return false;
for (ci = included_categories_.begin();
ci != included_categories_.end();
++ci) {
- if (MatchPattern(category_name, ci->c_str()))
+ if (base::MatchPattern(category_name, ci->c_str()))
return true;
}
diff --git a/base/trace_event/trace_config.h b/base/trace_event/trace_config.h
index a9f8306562..c7d3f4b379 100644
--- a/base/trace_event/trace_config.h
+++ b/base/trace_event/trace_config.h
@@ -1,20 +1,25 @@
-// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_TRACE_EVENT_TRACE_CONFIG_H_
#define BASE_TRACE_EVENT_TRACE_CONFIG_H_
+#include <stdint.h>
+
#include <string>
#include <vector>
#include "base/base_export.h"
#include "base/gtest_prod_util.h"
+#include "base/trace_event/memory_dump_request_args.h"
#include "base/values.h"
namespace base {
namespace trace_event {
+class ConvertableToTraceFormat;
+
// Options determines how the trace buffer stores data.
enum TraceRecordMode {
// Record until the trace buffer is full.
@@ -35,6 +40,15 @@ class BASE_EXPORT TraceConfig {
public:
typedef std::vector<std::string> StringList;
+ // Specifies the memory dump config for tracing. Used only when
+ // "memory-infra" category is enabled.
+ struct MemoryDumpTriggerConfig {
+ uint32_t periodic_interval_ms;
+ MemoryDumpLevelOfDetail level_of_detail;
+ };
+
+ typedef std::vector<MemoryDumpTriggerConfig> MemoryDumpConfig;
+
TraceConfig();
// Create TraceConfig object from category filter and trace options strings.
@@ -99,10 +113,21 @@ class BASE_EXPORT TraceConfig {
// "enable_argument_filter": true,
// "included_categories": ["included",
// "inc_pattern*",
- // "disabled-by-default-category1"],
+ // "disabled-by-default-memory-infra"],
// "excluded_categories": ["excluded", "exc_pattern*"],
// "synthetic_delays": ["test.Delay1;16", "test.Delay2;32"]
+ // "memory_dump_config": {
+ // "triggers": [
+ // {
+ // "mode": "detailed",
+ // "periodic_interval_ms": 2000
+ // }
+ // ]
+ // }
// }
+ //
+ // Note: memory_dump_config can be specified only if
+ // disabled-by-default-memory-infra category is enabled.
explicit TraceConfig(const std::string& config_string);
TraceConfig(const TraceConfig& tc);
@@ -128,6 +153,9 @@ class BASE_EXPORT TraceConfig {
// formatted.
std::string ToString() const;
+ // Returns a scoped_refptr and wrap TraceConfig in ConvertableToTraceFormat
+ scoped_refptr<ConvertableToTraceFormat> AsConvertableToTraceFormat() const;
+
// Write the string representation of the CategoryFilter part.
std::string ToCategoryFilterString() const;
@@ -140,6 +168,10 @@ class BASE_EXPORT TraceConfig {
void Clear();
+ const MemoryDumpConfig& memory_dump_config() const {
+ return memory_dump_config_;
+ }
+
private:
FRIEND_TEST_ALL_PREFIXES(TraceConfigTest, TraceConfigFromValidLegacyFormat);
FRIEND_TEST_ALL_PREFIXES(TraceConfigTest,
@@ -149,6 +181,9 @@ class BASE_EXPORT TraceConfig {
FRIEND_TEST_ALL_PREFIXES(TraceConfigTest, TraceConfigFromInvalidString);
FRIEND_TEST_ALL_PREFIXES(TraceConfigTest,
IsEmptyOrContainsLeadingOrTrailingWhitespace);
+ FRIEND_TEST_ALL_PREFIXES(TraceConfigTest, TraceConfigFromMemoryConfigString);
+ FRIEND_TEST_ALL_PREFIXES(TraceConfigTest, LegacyStringToMemoryDumpConfig);
+ FRIEND_TEST_ALL_PREFIXES(TraceConfigTest, EmptyMemoryDumpConfigTest);
// The default trace config, used when none is provided.
// Allows all non-disabled-by-default categories through, except if they end
@@ -169,6 +204,9 @@ class BASE_EXPORT TraceConfig {
const char* param,
const StringList& categories) const;
+ void SetMemoryDumpConfig(const base::DictionaryValue& memory_dump_config);
+ void SetDefaultMemoryDumpConfig();
+
// Convert TraceConfig to the dict representation of the TraceConfig.
void ToDict(base::DictionaryValue& dict) const;
@@ -193,6 +231,8 @@ class BASE_EXPORT TraceConfig {
bool enable_systrace_ : 1;
bool enable_argument_filter_ : 1;
+ MemoryDumpConfig memory_dump_config_;
+
StringList included_categories_;
StringList disabled_categories_;
StringList excluded_categories_;
diff --git a/base/trace_event/trace_config_memory_test_util.h b/base/trace_event/trace_config_memory_test_util.h
new file mode 100644
index 0000000000..8d8206fd7a
--- /dev/null
+++ b/base/trace_event/trace_config_memory_test_util.h
@@ -0,0 +1,76 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_TRACE_CONFIG_MEMORY_TEST_UTIL_H_
+#define BASE_TRACE_EVENT_TRACE_CONFIG_MEMORY_TEST_UTIL_H_
+
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/memory_dump_manager.h"
+
+namespace base {
+namespace trace_event {
+
+class TraceConfigMemoryTestUtil {
+ public:
+ static std::string GetTraceConfig_PeriodicTriggers(int light_period,
+ int heavy_period) {
+ return StringPrintf(
+ "{"
+ "\"enable_argument_filter\":false,"
+ "\"enable_sampling\":false,"
+ "\"enable_systrace\":false,"
+ "\"included_categories\":["
+ "\"%s\""
+ "],"
+ "\"memory_dump_config\":{"
+ "\"triggers\":["
+ "{"
+ "\"mode\":\"light\","
+ "\"periodic_interval_ms\":%d"
+ "},"
+ "{"
+ "\"mode\":\"detailed\","
+ "\"periodic_interval_ms\":%d"
+ "}"
+ "]"
+ "},"
+ "\"record_mode\":\"record-until-full\""
+ "}", MemoryDumpManager::kTraceCategory, light_period, heavy_period);
+ }
+
+ static std::string GetTraceConfig_EmptyTriggers() {
+ return StringPrintf(
+ "{"
+ "\"enable_argument_filter\":false,"
+ "\"enable_sampling\":false,"
+ "\"enable_systrace\":false,"
+ "\"included_categories\":["
+ "\"%s\""
+ "],"
+ "\"memory_dump_config\":{"
+ "\"triggers\":["
+ "]"
+ "},"
+ "\"record_mode\":\"record-until-full\""
+ "}", MemoryDumpManager::kTraceCategory);
+ }
+
+ static std::string GetTraceConfig_NoTriggers() {
+ return StringPrintf(
+ "{"
+ "\"enable_argument_filter\":false,"
+ "\"enable_sampling\":false,"
+ "\"enable_systrace\":false,"
+ "\"included_categories\":["
+ "\"%s\""
+ "],"
+ "\"record_mode\":\"record-until-full\""
+ "}", MemoryDumpManager::kTraceCategory);
+ }
+};
+
+} // namespace trace_event
+} // namespace base
+
+#endif // BASE_TRACE_EVENT_TRACE_CONFIG_MEMORY_TEST_UTIL_H_
diff --git a/base/trace_event/trace_config_unittest.cc b/base/trace_event/trace_config_unittest.cc
index a2a3703ea3..bd37880329 100644
--- a/base/trace_event/trace_config_unittest.cc
+++ b/base/trace_event/trace_config_unittest.cc
@@ -1,8 +1,13 @@
-// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stddef.h>
+
+#include "base/macros.h"
+#include "base/trace_event/memory_dump_manager.h"
#include "base/trace_event/trace_config.h"
+#include "base/trace_event/trace_config_memory_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
@@ -18,7 +23,6 @@ const char kDefaultTraceConfigString[] =
"\"excluded_categories\":[\"*Debug\",\"*Test\"],"
"\"record_mode\":\"record-until-full\""
"}";
-
} // namespace
TEST(TraceConfigTest, TraceConfigFromValidLegacyFormat) {
@@ -447,6 +451,12 @@ TEST(TraceConfigTest, IsCategoryGroupEnabled) {
EXPECT_TRUE(tc.IsCategoryGroupEnabled("disabled-by-default-cc"));
EXPECT_TRUE(tc.IsCategoryGroupEnabled("included"));
EXPECT_FALSE(tc.IsCategoryGroupEnabled("other_included"));
+
+ // Excluding categories won't enable disabled-by-default ones with the
+ // excluded category is also present in the group.
+ tc = TraceConfig("-excluded", "");
+ EXPECT_STREQ("-excluded", tc.ToCategoryFilterString().c_str());
+ EXPECT_FALSE(tc.IsCategoryGroupEnabled("excluded,disabled-by-default-cc"));
}
TEST(TraceConfigTest, IsEmptyOrContainsLeadingOrTrailingWhitespace) {
@@ -488,5 +498,37 @@ TEST(TraceConfigTest, SetTraceOptionValues) {
EXPECT_TRUE(tc.IsSystraceEnabled());
}
+TEST(TraceConfigTest, TraceConfigFromMemoryConfigString) {
+ std::string tc_str =
+ TraceConfigMemoryTestUtil::GetTraceConfig_PeriodicTriggers(200, 2000);
+ TraceConfig tc(tc_str);
+ EXPECT_EQ(tc_str, tc.ToString());
+ EXPECT_TRUE(tc.IsCategoryGroupEnabled(MemoryDumpManager::kTraceCategory));
+ EXPECT_EQ(2u, tc.memory_dump_config_.size());
+
+ EXPECT_EQ(200u, tc.memory_dump_config_[0].periodic_interval_ms);
+ EXPECT_EQ(MemoryDumpLevelOfDetail::LIGHT,
+ tc.memory_dump_config_[0].level_of_detail);
+
+ EXPECT_EQ(2000u, tc.memory_dump_config_[1].periodic_interval_ms);
+ EXPECT_EQ(MemoryDumpLevelOfDetail::DETAILED,
+ tc.memory_dump_config_[1].level_of_detail);
+}
+
+TEST(TraceConfigTest, EmptyMemoryDumpConfigTest) {
+ // Empty trigger list should also be specified when converting back to string.
+ TraceConfig tc(TraceConfigMemoryTestUtil::GetTraceConfig_EmptyTriggers());
+ EXPECT_EQ(TraceConfigMemoryTestUtil::GetTraceConfig_EmptyTriggers(),
+ tc.ToString());
+ EXPECT_EQ(0u, tc.memory_dump_config_.size());
+}
+
+TEST(TraceConfigTest, LegacyStringToMemoryDumpConfig) {
+ TraceConfig tc(MemoryDumpManager::kTraceCategory, "");
+ EXPECT_TRUE(tc.IsCategoryGroupEnabled(MemoryDumpManager::kTraceCategory));
+ EXPECT_NE(std::string::npos, tc.ToString().find("memory_dump_config"));
+ EXPECT_EQ(2u, tc.memory_dump_config_.size());
+}
+
} // namespace trace_event
} // namespace base
diff --git a/base/trace_event/trace_event.gypi b/base/trace_event/trace_event.gypi
index 82a87cce62..6948d7cfe0 100644
--- a/base/trace_event/trace_event.gypi
+++ b/base/trace_event/trace_event.gypi
@@ -4,6 +4,21 @@
{
'variables': {
'trace_event_sources' : [
+ 'trace_event/common/trace_event_common.h',
+ 'trace_event/heap_profiler_allocation_context.cc',
+ 'trace_event/heap_profiler_allocation_context.h',
+ 'trace_event/heap_profiler_allocation_context_tracker.cc',
+ 'trace_event/heap_profiler_allocation_context_tracker.h',
+ 'trace_event/heap_profiler_allocation_register.cc',
+ 'trace_event/heap_profiler_allocation_register_posix.cc',
+ 'trace_event/heap_profiler_allocation_register_win.cc',
+ 'trace_event/heap_profiler_allocation_register.h',
+ 'trace_event/heap_profiler_heap_dump_writer.cc',
+ 'trace_event/heap_profiler_heap_dump_writer.h',
+ 'trace_event/heap_profiler_stack_frame_deduplicator.cc',
+ 'trace_event/heap_profiler_stack_frame_deduplicator.h',
+ 'trace_event/heap_profiler_type_name_deduplicator.cc',
+ 'trace_event/heap_profiler_type_name_deduplicator.h',
'trace_event/java_heap_dump_provider_android.cc',
'trace_event/java_heap_dump_provider_android.h',
'trace_event/memory_allocator_dump.cc',
@@ -13,6 +28,7 @@
'trace_event/memory_dump_manager.cc',
'trace_event/memory_dump_manager.h',
'trace_event/memory_dump_provider.h',
+ 'trace_event/memory_dump_request_args.cc',
'trace_event/memory_dump_request_args.h',
'trace_event/memory_dump_session_state.cc',
'trace_event/memory_dump_session_state.h',
@@ -20,12 +36,13 @@
'trace_event/process_memory_dump.h',
'trace_event/process_memory_maps.cc',
'trace_event/process_memory_maps.h',
- 'trace_event/process_memory_maps_dump_provider.cc',
'trace_event/process_memory_maps_dump_provider.h',
'trace_event/process_memory_totals.cc',
'trace_event/process_memory_totals.h',
'trace_event/process_memory_totals_dump_provider.cc',
'trace_event/process_memory_totals_dump_provider.h',
+ 'trace_event/trace_buffer.cc',
+ 'trace_event/trace_buffer.h',
'trace_event/trace_config.cc',
'trace_event/trace_config.h',
'trace_event/trace_event.h',
@@ -36,43 +53,61 @@
'trace_event/trace_event_etw_export_win.h',
'trace_event/trace_event_impl.cc',
'trace_event/trace_event_impl.h',
- 'trace_event/trace_event_impl_constants.cc',
- 'trace_event/trace_event_memory.cc',
- 'trace_event/trace_event_memory.h',
'trace_event/trace_event_memory_overhead.cc',
'trace_event/trace_event_memory_overhead.h',
'trace_event/trace_event_synthetic_delay.cc',
'trace_event/trace_event_synthetic_delay.h',
'trace_event/trace_event_system_stats_monitor.cc',
'trace_event/trace_event_system_stats_monitor.h',
- 'trace_event/trace_event_win.cc',
- 'trace_event/trace_event_win.h',
+ 'trace_event/trace_log.cc',
+ 'trace_event/trace_log.h',
+ 'trace_event/trace_log_constants.cc',
+ 'trace_event/trace_sampling_thread.cc',
+ 'trace_event/trace_sampling_thread.h',
+ 'trace_event/tracing_agent.cc',
+ 'trace_event/tracing_agent.h',
'trace_event/winheap_dump_provider_win.cc',
'trace_event/winheap_dump_provider_win.h',
],
- 'conditions': [
- ['OS == "linux" or OS == "android"', {
- 'trace_event_sources': [
- 'trace_event/malloc_dump_provider.cc',
- 'trace_event/malloc_dump_provider.h',
- ],
- }],
- ],
'trace_event_test_sources' : [
+ 'trace_event/heap_profiler_allocation_context_tracker_unittest.cc',
+ 'trace_event/heap_profiler_allocation_register_unittest.cc',
+ 'trace_event/heap_profiler_heap_dump_writer_unittest.cc',
+ 'trace_event/heap_profiler_stack_frame_deduplicator_unittest.cc',
+ 'trace_event/heap_profiler_type_name_deduplicator_unittest.cc',
'trace_event/java_heap_dump_provider_android_unittest.cc',
'trace_event/memory_allocator_dump_unittest.cc',
'trace_event/memory_dump_manager_unittest.cc',
'trace_event/process_memory_dump_unittest.cc',
- 'trace_event/process_memory_maps_dump_provider_unittest.cc',
'trace_event/process_memory_totals_dump_provider_unittest.cc',
+ 'trace_event/trace_config_memory_test_util.h',
'trace_event/trace_config_unittest.cc',
'trace_event/trace_event_argument_unittest.cc',
- 'trace_event/trace_event_memory_unittest.cc',
'trace_event/trace_event_synthetic_delay_unittest.cc',
'trace_event/trace_event_system_stats_monitor_unittest.cc',
'trace_event/trace_event_unittest.cc',
- 'trace_event/trace_event_win_unittest.cc',
'trace_event/winheap_dump_provider_win_unittest.cc',
],
+ 'conditions': [
+ ['OS == "linux" or OS=="android" or OS=="mac"', {
+ 'trace_event_sources': [
+ 'trace_event/malloc_dump_provider.cc',
+ 'trace_event/malloc_dump_provider.h',
+ ],
+ }],
+ ['OS == "linux" or OS == "android"', {
+ 'trace_event_sources': [
+ 'trace_event/process_memory_maps_dump_provider.cc',
+ ],
+ 'trace_event_test_sources' : [
+ 'trace_event/process_memory_maps_dump_provider_unittest.cc',
+ ],
+ }],
+ ['OS == "android"', {
+ 'trace_event_test_sources' : [
+ 'trace_event/trace_event_android_unittest.cc',
+ ],
+ }],
+ ],
},
}
diff --git a/base/trace_event/trace_event.h b/base/trace_event/trace_event.h
index 95e88679f5..75bb81bff0 100644
--- a/base/trace_event/trace_event.h
+++ b/base/trace_event/trace_event.h
@@ -2,200 +2,24 @@
// 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"));
-//
-//
-// Convertable 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::trace_event::ConvertableToTraceFormat {
-// public:
-// MyData() {}
-// void AppendAsTraceFormat(std::string* out) const override {
-// out->append("{\"foo\":1}");
-// }
-// private:
-// ~MyData() override {}
-// DISALLOW_COPY_AND_ASSIGN(MyData);
-// };
-//
-// TRACE_EVENT1("foo", "bar", "data",
-// scoped_refptr<ConvertableToTraceFormat>(new MyData()));
-//
-// 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_TRACE_EVENT_TRACE_EVENT_H_
#define BASE_TRACE_EVENT_TRACE_EVENT_H_
+// This header file defines implementation details of how the trace macros in
+// trace_event_common.h collect and store trace events. Anything not
+// implementation-specific should go in trace_macros_common.h instead of here.
+
+#include <stddef.h>
+#include <stdint.h>
+
#include <string>
#include "base/atomicops.h"
+#include "base/macros.h"
#include "base/time/time.h"
-#include "base/trace_event/trace_event_impl.h"
-#include "base/trace_event/trace_event_memory.h"
+#include "base/trace_event/common/trace_event_common.h"
#include "base/trace_event/trace_event_system_stats_monitor.h"
+#include "base/trace_event/trace_log.h"
#include "build/build_config.h"
// By default, const char* argument values are assumed to have long-lived scope
@@ -203,12 +27,8 @@
#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.
+// By default, uint64_t 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)
@@ -217,105 +37,6 @@
#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)
-
-// Records events like TRACE_EVENT2 but uses |memory_tag| for memory tracing.
-// Use this where |name| is too generic to accurately aggregate allocations.
-#define TRACE_EVENT_WITH_MEMORY_TAG2( \
- category, name, memory_tag, arg1_name, arg1_val, arg2_name, arg2_val) \
- INTERNAL_TRACE_MEMORY(category, memory_tag) \
- INTERNAL_TRACE_EVENT_ADD_SCOPED( \
- category, 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
@@ -342,555 +63,8 @@
trace_event_internal::TraceEventSamplingStateScope<bucket_number> \
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)
-#define TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP1( \
- category_group, name, id, thread_id, timestamp, arg1_name, arg1_val) \
- 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, arg1_name, arg1_val)
-#define TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP2( \
- category_group, name, id, thread_id, timestamp, arg1_name, arg1_val, \
- arg2_name, arg2_val) \
- 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, arg1_name, arg1_val, arg2_name, \
- arg2_val)
-
-// 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)
-#define TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP1( \
- category_group, name, id, thread_id, timestamp, arg1_name, arg1_val) \
- 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, arg1_name, arg1_val)
-#define TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP2( \
- category_group, name, id, thread_id, timestamp, arg1_name, arg1_val, \
- arg2_name, arg2_val) \
- 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, arg1_name, arg1_val, arg2_name, \
- arg2_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.
-#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<int>(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<int>(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<int>(value1_val), \
- value2_name, static_cast<int>(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<int>(value1_val), \
- value2_name, static_cast<int>(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<int>(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<int>(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<int>(value1_val), \
- value2_name, static_cast<int>(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<int>(value1_val), \
- value2_name, static_cast<int>(value2_val))
-
-// TRACE_EVENT_SAMPLE_* events are injected by the sampling profiler.
-#define TRACE_EVENT_SAMPLE_WITH_TID_AND_TIMESTAMP0(category_group, name, \
- thread_id, timestamp) \
- INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
- TRACE_EVENT_PHASE_SAMPLE, category_group, name, 0, thread_id, timestamp, \
- TRACE_EVENT_FLAG_NONE)
-
-#define TRACE_EVENT_SAMPLE_WITH_TID_AND_TIMESTAMP1( \
- category_group, name, thread_id, timestamp, arg1_name, arg1_val) \
- INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
- TRACE_EVENT_PHASE_SAMPLE, category_group, name, 0, thread_id, timestamp, \
- TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
-
-#define TRACE_EVENT_SAMPLE_WITH_TID_AND_TIMESTAMP2(category_group, name, \
- thread_id, timestamp, \
- arg1_name, arg1_val, \
- arg2_name, arg2_val) \
- INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
- TRACE_EVENT_PHASE_SAMPLE, category_group, name, 0, thread_id, timestamp, \
- TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, arg2_name, arg2_val)
-
-// ASYNC_STEP_* APIs should be only used by legacy code. New code should
-// consider using NESTABLE_ASYNC_* APIs to describe substeps within an async
-// event.
-// 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_INTO or ASYNC_STEP_PAST macros. The ASYNC_STEP_INTO macro will
-// annotate the block following the call. The ASYNC_STEP_PAST macro will
-// annotate the block prior to the call. Note that any particular event must use
-// only STEP_INTO or STEP_PAST macros; they can not mix and match. When the
-// operation completes, call ASYNC_END.
-//
-// An ASYNC trace typically occurs 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 step 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)
-
-// Similar to TRACE_EVENT_ASYNC_BEGINx but with a custom |at| timestamp
-// provided.
-#define TRACE_EVENT_ASYNC_BEGIN_WITH_TIMESTAMP0(category_group, \
- name, id, timestamp) \
- INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
- TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, \
- static_cast<int>(base::PlatformThread::CurrentId()), \
- timestamp, TRACE_EVENT_FLAG_NONE)
-#define TRACE_EVENT_COPY_ASYNC_BEGIN_WITH_TIMESTAMP0(category_group, \
- name, id, timestamp) \
- INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
- TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, \
- static_cast<int>(base::PlatformThread::CurrentId()), \
- timestamp, TRACE_EVENT_FLAG_COPY)
-
-// Records a single ASYNC_STEP_INTO 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. The ASYNC_BEGIN event must not have any
-// ASYNC_STEP_PAST events.
-#define TRACE_EVENT_ASYNC_STEP_INTO0(category_group, name, id, step) \
- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP_INTO, \
- category_group, name, id, TRACE_EVENT_FLAG_NONE, "step", step)
-#define TRACE_EVENT_ASYNC_STEP_INTO1(category_group, name, id, step, \
- arg1_name, arg1_val) \
- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP_INTO, \
- category_group, name, id, TRACE_EVENT_FLAG_NONE, "step", step, \
- arg1_name, arg1_val)
-
-// Similar to TRACE_EVENT_ASYNC_STEP_INTOx but with a custom |at| timestamp
-// provided.
-#define TRACE_EVENT_ASYNC_STEP_INTO_WITH_TIMESTAMP0(category_group, name, \
- id, step, timestamp) \
- INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
- TRACE_EVENT_PHASE_ASYNC_STEP_INTO, category_group, name, id, \
- static_cast<int>(base::PlatformThread::CurrentId()), \
- timestamp, TRACE_EVENT_FLAG_NONE, "step", step)
-
-// Records a single ASYNC_STEP_PAST 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. The ASYNC_BEGIN event must not have any
-// ASYNC_STEP_INTO events.
-#define TRACE_EVENT_ASYNC_STEP_PAST0(category_group, name, id, step) \
- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP_PAST, \
- category_group, name, id, TRACE_EVENT_FLAG_NONE, "step", step)
-#define TRACE_EVENT_ASYNC_STEP_PAST1(category_group, name, id, step, \
- arg1_name, arg1_val) \
- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP_PAST, \
- category_group, name, id, TRACE_EVENT_FLAG_NONE, "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)
-
-// Similar to TRACE_EVENT_ASYNC_ENDx but with a custom |at| timestamp provided.
-#define TRACE_EVENT_ASYNC_END_WITH_TIMESTAMP0(category_group, \
- name, id, timestamp) \
- INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
- TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, \
- static_cast<int>(base::PlatformThread::CurrentId()), \
- timestamp, TRACE_EVENT_FLAG_NONE)
-
-// NESTABLE_ASYNC_* APIs are used to describe an async operation, which can
-// be nested within a NESTABLE_ASYNC event and/or have inner NESTABLE_ASYNC
-// events.
-// - category and name strings must have application lifetime (statics or
-// literals). They may not include " chars.
-// - A pair of NESTABLE_ASYNC_BEGIN event and NESTABLE_ASYNC_END event is
-// considered as a match if their category_group, name and id 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.
-// - |id| is used to match a child NESTABLE_ASYNC event with its parent
-// NESTABLE_ASYNC event. Therefore, events in the same nested event tree must
-// be logged using the same id and category_group.
-//
-// Unmatched NESTABLE_ASYNC_END event will be parsed as an event that starts
-// at the first NESTABLE_ASYNC event of that id, and unmatched
-// NESTABLE_ASYNC_BEGIN event will be parsed as an event that ends at the last
-// NESTABLE_ASYNC event of that id. Corresponding warning messages for
-// unmatched events will be shown in the analysis view.
-
-// Records a single NESTABLE_ASYNC_BEGIN event called "name" immediately, with
-// 0, 1 or 2 associated arguments. If the category is not enabled, then this
-// does nothing.
-#define TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(category_group, name, id) \
- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, \
- category_group, name, id, TRACE_EVENT_FLAG_NONE)
-#define TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(category_group, name, id, arg1_name, \
- arg1_val) \
- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, \
- category_group, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
-#define TRACE_EVENT_NESTABLE_ASYNC_BEGIN2(category_group, name, id, arg1_name, \
- arg1_val, arg2_name, arg2_val) \
- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, \
- category_group, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \
- arg2_name, arg2_val)
-// Records a single NESTABLE_ASYNC_END event called "name" immediately, with 0
-// or 2 associated arguments. If the category is not enabled, then this does
-// nothing.
-#define TRACE_EVENT_NESTABLE_ASYNC_END0(category_group, name, id) \
- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, \
- category_group, name, id, TRACE_EVENT_FLAG_NONE)
-#define TRACE_EVENT_NESTABLE_ASYNC_END2(category_group, name, id, arg1_name, \
- arg1_val, arg2_name, arg2_val) \
- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, \
- category_group, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \
- arg2_name, arg2_val)
-
-#define TRACE_EVENT_COPY_NESTABLE_ASYNC_BEGIN_WITH_TTS2(category_group, name, \
- id, arg1_name, arg1_val, arg2_name, arg2_val) \
- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, \
- category_group, name, id, \
- TRACE_EVENT_FLAG_ASYNC_TTS | TRACE_EVENT_FLAG_COPY, \
- arg1_name, arg1_val, arg2_name, arg2_val)
-#define TRACE_EVENT_COPY_NESTABLE_ASYNC_END_WITH_TTS2(category_group, name, \
- id, arg1_name, arg1_val, arg2_name, arg2_val) \
- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, \
- category_group, name, id, \
- TRACE_EVENT_FLAG_ASYNC_TTS | TRACE_EVENT_FLAG_COPY, \
- arg1_name, arg1_val, arg2_name, arg2_val)
-
-// Similar to TRACE_EVENT_NESTABLE_ASYNC_{BEGIN,END}x but with a custom
-// |timestamp| provided.
-#define TRACE_EVENT_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP0(category_group, name, \
- id, timestamp) \
- INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
- TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, category_group, name, id, \
- static_cast<int>(base::PlatformThread::CurrentId()), timestamp, \
- TRACE_EVENT_FLAG_NONE)
-
-#define TRACE_EVENT_NESTABLE_ASYNC_END_WITH_TIMESTAMP0(category_group, name, \
- id, timestamp) \
- INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
- TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, category_group, name, id, \
- static_cast<int>(base::PlatformThread::CurrentId()), timestamp, \
- TRACE_EVENT_FLAG_NONE)
-
-// Records a single NESTABLE_ASYNC_INSTANT event called "name" immediately,
-// with 2 associated arguments. If the category is not enabled, then this
-// does nothing.
-#define TRACE_EVENT_NESTABLE_ASYNC_INSTANT2(category_group, name, id, \
- arg1_name, arg1_val, arg2_name, arg2_val) \
- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT, \
- category_group, name, id, TRACE_EVENT_FLAG_NONE, 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_END_BIND_TO_ENCLOSING0(category_group, name, id) \
- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \
- category_group, name, id, TRACE_EVENT_FLAG_BIND_TO_ENCLOSING)
-#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)
+#define TRACE_EVENT_API_CURRENT_THREAD_ID \
+ static_cast<int>(base::PlatformThread::CurrentId())
#define INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE() \
UNLIKELY(*INTERNAL_TRACE_EVENT_UID(category_group_enabled) & \
@@ -898,33 +72,6 @@
base::trace_event::TraceLog::ENABLED_FOR_EVENT_CALLBACK | \
base::trace_event::TraceLog::ENABLED_FOR_ETW_EXPORT))
-// 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_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \
- *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.
@@ -957,24 +104,65 @@
// const char** arg_names,
// const unsigned char* arg_types,
// const unsigned long long* arg_values,
-// unsigned char flags)
+// const scoped_refptr<ConvertableToTraceFormat>*
+// convertable_values,
+// unsigned int flags)
#define TRACE_EVENT_API_ADD_TRACE_EVENT \
base::trace_event::TraceLog::GetInstance()->AddTraceEvent
// Add a trace event to the platform tracing system.
// base::trace_event::TraceEventHandle
+// TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_BIND_ID(
+// char phase,
+// const unsigned char* category_group_enabled,
+// const char* name,
+// unsigned long long id,
+// unsigned long long bind_id,
+// int num_args,
+// const char** arg_names,
+// const unsigned char* arg_types,
+// const unsigned long long* arg_values,
+// const scoped_refptr<ConvertableToTraceFormat>*
+// convertable_values,
+// unsigned int flags)
+#define TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_BIND_ID \
+ base::trace_event::TraceLog::GetInstance()->AddTraceEventWithBindId
+
+// Add a trace event to the platform tracing system overriding the pid.
+// The resulting event will have tid = pid == (process_id passed here).
+// base::trace_event::TraceEventHandle
+// TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_PROCESS_ID(
+// char phase,
+// const unsigned char* category_group_enabled,
+// const char* name,
+// unsigned long long id,
+// int process_id,
+// int num_args,
+// const char** arg_names,
+// const unsigned char* arg_types,
+// const unsigned long long* arg_values,
+// const scoped_refptr<ConvertableToTraceFormat>*
+// convertable_values,
+// unsigned int flags)
+#define TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_PROCESS_ID \
+ base::trace_event::TraceLog::GetInstance()->AddTraceEventWithProcessId
+
+// Add a trace event to the platform tracing system.
+// base::trace_event::TraceEventHandle
// 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 TraceTicks& timestamp,
+// const TimeTicks& timestamp,
// int num_args,
// const char** arg_names,
// const unsigned char* arg_types,
// const unsigned long long* arg_values,
-// unsigned char flags)
+// const scoped_refptr<ConvertableToTraceFormat>*
+// convertable_values,
+// unsigned int flags)
#define TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP \
base::trace_event::TraceLog::GetInstance() \
->AddTraceEventWithThreadIdAndTimestamp
@@ -987,6 +175,15 @@
#define TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION \
base::trace_event::TraceLog::GetInstance()->UpdateTraceEventDuration
+// Adds a metadata event to the trace log. The |AppendValueAsTraceFormat| method
+// on the convertable value will be called at flush time.
+// TRACE_EVENT_API_ADD_METADATA_EVENT(
+// const char* event_name,
+// const char* arg_name,
+// scoped_refptr<ConvertableToTraceFormat> arg_value)
+#define TRACE_EVENT_API_ADD_METADATA_EVENT \
+ trace_event_internal::AddMetadataEvent
+
// 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))
@@ -1047,7 +244,8 @@ TRACE_EVENT_API_CLASS_EXPORT extern \
if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \
trace_event_internal::AddTraceEvent( \
phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, \
- trace_event_internal::kNoEventId, flags, ##__VA_ARGS__); \
+ trace_event_internal::kNoId, flags, \
+ trace_event_internal::kNoId, ##__VA_ARGS__); \
} \
} while (0)
@@ -1062,12 +260,30 @@ TRACE_EVENT_API_CLASS_EXPORT extern \
trace_event_internal::AddTraceEvent( \
TRACE_EVENT_PHASE_COMPLETE, \
INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, \
- trace_event_internal::kNoEventId, TRACE_EVENT_FLAG_NONE, \
- ##__VA_ARGS__); \
+ trace_event_internal::kNoId, TRACE_EVENT_FLAG_NONE, \
+ trace_event_internal::kNoId, ##__VA_ARGS__); \
INTERNAL_TRACE_EVENT_UID(tracer).Initialize( \
INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, h); \
}
+#define INTERNAL_TRACE_EVENT_ADD_SCOPED_WITH_FLOW( \
+ category_group, name, bind_id, flow_flags, ...) \
+ INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \
+ trace_event_internal::ScopedTracer INTERNAL_TRACE_EVENT_UID(tracer); \
+ if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \
+ unsigned int trace_event_flags = flow_flags; \
+ trace_event_internal::TraceID trace_event_bind_id(bind_id, \
+ &trace_event_flags); \
+ base::trace_event::TraceEventHandle h = \
+ trace_event_internal::AddTraceEvent( \
+ TRACE_EVENT_PHASE_COMPLETE, \
+ INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, \
+ trace_event_internal::kNoId, trace_event_flags, \
+ trace_event_bind_id.data(), ##__VA_ARGS__); \
+ INTERNAL_TRACE_EVENT_UID(tracer).Initialize( \
+ INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, h); \
+ }
+
// 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, \
@@ -1075,103 +291,57 @@ TRACE_EVENT_API_CLASS_EXPORT extern \
do { \
INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \
if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \
- unsigned char trace_event_flags = flags | TRACE_EVENT_FLAG_HAS_ID; \
+ unsigned int 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(category_group_enabled), \
name, trace_event_trace_id.data(), trace_event_flags, \
- ##__VA_ARGS__); \
+ trace_event_internal::kNoId, ##__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_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \
- 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(category_group_enabled), \
- name, trace_event_trace_id.data(), \
- thread_id, base::TraceTicks::FromInternalValue(timestamp), \
- trace_event_flags | TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP, \
- ##__VA_ARGS__); \
- } \
- } while (0)
+#define INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP(phase, category_group, name, \
+ timestamp, flags, ...) \
+ do { \
+ INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \
+ if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \
+ trace_event_internal::AddTraceEventWithThreadIdAndTimestamp( \
+ phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, \
+ trace_event_internal::kNoId, TRACE_EVENT_API_CURRENT_THREAD_ID, \
+ base::TimeTicks::FromInternalValue(timestamp), \
+ flags | TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP, \
+ trace_event_internal::kNoId, ##__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_COMPLETE ('X')
-#define TRACE_EVENT_PHASE_INSTANT ('I')
-#define TRACE_EVENT_PHASE_ASYNC_BEGIN ('S')
-#define TRACE_EVENT_PHASE_ASYNC_STEP_INTO ('T')
-#define TRACE_EVENT_PHASE_ASYNC_STEP_PAST ('p')
-#define TRACE_EVENT_PHASE_ASYNC_END ('F')
-#define TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN ('b')
-#define TRACE_EVENT_PHASE_NESTABLE_ASYNC_END ('e')
-#define TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT ('n')
-#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')
-#define TRACE_EVENT_PHASE_MEMORY_DUMP ('v')
-
-// Flags for changing the behavior of TRACE_EVENT_API_ADD_TRACE_EVENT.
-#define TRACE_EVENT_FLAG_NONE (static_cast<unsigned char>(0))
-#define TRACE_EVENT_FLAG_COPY (static_cast<unsigned char>(1 << 0))
-#define TRACE_EVENT_FLAG_HAS_ID (static_cast<unsigned char>(1 << 1))
-#define TRACE_EVENT_FLAG_MANGLE_ID (static_cast<unsigned char>(1 << 2))
-#define TRACE_EVENT_FLAG_SCOPE_OFFSET (static_cast<unsigned char>(1 << 3))
-#define TRACE_EVENT_FLAG_SCOPE_EXTRA (static_cast<unsigned char>(1 << 4))
-#define TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP (static_cast<unsigned char>(1 << 5))
-#define TRACE_EVENT_FLAG_ASYNC_TTS (static_cast<unsigned char>(1 << 6))
-#define TRACE_EVENT_FLAG_BIND_TO_ENCLOSING (static_cast<unsigned char>(1 << 7))
-
-#define TRACE_EVENT_FLAG_SCOPE_MASK (static_cast<unsigned char>( \
- TRACE_EVENT_FLAG_SCOPE_OFFSET | TRACE_EVENT_FLAG_SCOPE_EXTRA))
-
-// Type values for identifying types in the TraceValue union.
-#define TRACE_VALUE_TYPE_BOOL (static_cast<unsigned char>(1))
-#define TRACE_VALUE_TYPE_UINT (static_cast<unsigned char>(2))
-#define TRACE_VALUE_TYPE_INT (static_cast<unsigned char>(3))
-#define TRACE_VALUE_TYPE_DOUBLE (static_cast<unsigned char>(4))
-#define TRACE_VALUE_TYPE_POINTER (static_cast<unsigned char>(5))
-#define TRACE_VALUE_TYPE_STRING (static_cast<unsigned char>(6))
-#define TRACE_VALUE_TYPE_COPY_STRING (static_cast<unsigned char>(7))
-#define TRACE_VALUE_TYPE_CONVERTABLE (static_cast<unsigned char>(8))
-
-// Enum reflecting the scope of an INSTANT event. Must fit within
-// TRACE_EVENT_FLAG_SCOPE_MASK.
-#define TRACE_EVENT_SCOPE_GLOBAL (static_cast<unsigned char>(0 << 3))
-#define TRACE_EVENT_SCOPE_PROCESS (static_cast<unsigned char>(1 << 3))
-#define TRACE_EVENT_SCOPE_THREAD (static_cast<unsigned char>(2 << 3))
-
-#define TRACE_EVENT_SCOPE_NAME_GLOBAL ('g')
-#define TRACE_EVENT_SCOPE_NAME_PROCESS ('p')
-#define TRACE_EVENT_SCOPE_NAME_THREAD ('t')
+// 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_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \
+ unsigned int 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(category_group_enabled), name, \
+ trace_event_trace_id.data(), thread_id, \
+ base::TimeTicks::FromInternalValue(timestamp), \
+ trace_event_flags | TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP, \
+ trace_event_internal::kNoId, ##__VA_ARGS__); \
+ } \
+ } while (0)
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;
+const unsigned long long kNoId = 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
@@ -1224,35 +394,35 @@ class TraceID {
private:
unsigned long long data_;
};
- TraceID(const void* id, unsigned char* flags)
+ TraceID(const void* id, unsigned int* flags)
: data_(static_cast<unsigned long long>(
reinterpret_cast<uintptr_t>(id))) {
*flags |= TRACE_EVENT_FLAG_MANGLE_ID;
}
- TraceID(ForceMangle id, unsigned char* flags) : data_(id.data()) {
+ TraceID(ForceMangle id, unsigned int* flags) : data_(id.data()) {
*flags |= TRACE_EVENT_FLAG_MANGLE_ID;
}
- TraceID(DontMangle id, unsigned char* /* flags */) : data_(id.data()) {
+ TraceID(DontMangle id, unsigned int* /* flags */) : data_(id.data()) {
}
- TraceID(unsigned long long id, unsigned char* flags)
+ TraceID(unsigned long long id, unsigned int* flags)
: data_(id) { (void)flags; }
- TraceID(unsigned long id, unsigned char* flags)
+ TraceID(unsigned long id, unsigned int* flags)
: data_(id) { (void)flags; }
- TraceID(unsigned int id, unsigned char* flags)
+ TraceID(unsigned int id, unsigned int* flags)
: data_(id) { (void)flags; }
- TraceID(unsigned short id, unsigned char* flags)
+ TraceID(unsigned short id, unsigned int* flags)
: data_(id) { (void)flags; }
- TraceID(unsigned char id, unsigned char* flags)
+ TraceID(unsigned char id, unsigned int* flags)
: data_(id) { (void)flags; }
- TraceID(long long id, unsigned char* flags)
+ TraceID(long long id, unsigned int* flags)
: data_(static_cast<unsigned long long>(id)) { (void)flags; }
- TraceID(long id, unsigned char* flags)
+ TraceID(long id, unsigned int* flags)
: data_(static_cast<unsigned long long>(id)) { (void)flags; }
- TraceID(int id, unsigned char* flags)
+ TraceID(int id, unsigned int* flags)
: data_(static_cast<unsigned long long>(id)) { (void)flags; }
- TraceID(short id, unsigned char* flags)
+ TraceID(short id, unsigned int* flags)
: data_(static_cast<unsigned long long>(id)) { (void)flags; }
- TraceID(signed char id, unsigned char* flags)
+ TraceID(signed char id, unsigned int* flags)
: data_(static_cast<unsigned long long>(id)) { (void)flags; }
unsigned long long data() const { return data_; }
@@ -1363,13 +533,6 @@ static inline void SetTraceValue(const base::ThreadTicks arg,
*value = arg.ToInternalValue();
}
-static inline void SetTraceValue(const base::TraceTicks arg,
- unsigned char* type,
- unsigned long long* value) {
- *type = TRACE_VALUE_TYPE_INT;
- *value = arg.ToInternalValue();
-}
-
// 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
@@ -1383,15 +546,16 @@ AddTraceEventWithThreadIdAndTimestamp(
const char* name,
unsigned long long id,
int thread_id,
- const base::TraceTicks& timestamp,
- unsigned char flags,
+ const base::TimeTicks& timestamp,
+ unsigned int flags,
+ unsigned long long bind_id,
const char* arg1_name,
const scoped_refptr<base::trace_event::ConvertableToTraceFormat>&
arg1_val) {
const int num_args = 1;
unsigned char arg_types[1] = { TRACE_VALUE_TYPE_CONVERTABLE };
return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
- phase, category_group_enabled, name, id, thread_id, timestamp,
+ phase, category_group_enabled, name, id, bind_id, thread_id, timestamp,
num_args, &arg1_name, arg_types, NULL, &arg1_val, flags);
}
@@ -1403,8 +567,9 @@ AddTraceEventWithThreadIdAndTimestamp(
const char* name,
unsigned long long id,
int thread_id,
- const base::TraceTicks& timestamp,
- unsigned char flags,
+ const base::TimeTicks& timestamp,
+ unsigned int flags,
+ unsigned long long bind_id,
const char* arg1_name,
const ARG1_TYPE& arg1_val,
const char* arg2_name,
@@ -1423,7 +588,7 @@ AddTraceEventWithThreadIdAndTimestamp(
convertable_values[1] = arg2_val;
return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
- phase, category_group_enabled, name, id, thread_id, timestamp,
+ phase, category_group_enabled, name, id, bind_id, thread_id, timestamp,
num_args, arg_names, arg_types, arg_values, convertable_values, flags);
}
@@ -1435,8 +600,9 @@ AddTraceEventWithThreadIdAndTimestamp(
const char* name,
unsigned long long id,
int thread_id,
- const base::TraceTicks& timestamp,
- unsigned char flags,
+ const base::TimeTicks& timestamp,
+ unsigned int flags,
+ unsigned long long bind_id,
const char* arg1_name,
const scoped_refptr<base::trace_event::ConvertableToTraceFormat>& arg1_val,
const char* arg2_name,
@@ -1455,7 +621,7 @@ AddTraceEventWithThreadIdAndTimestamp(
convertable_values[0] = arg1_val;
return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
- phase, category_group_enabled, name, id, thread_id, timestamp,
+ phase, category_group_enabled, name, id, bind_id, thread_id, timestamp,
num_args, arg_names, arg_types, arg_values, convertable_values, flags);
}
@@ -1466,8 +632,9 @@ AddTraceEventWithThreadIdAndTimestamp(
const char* name,
unsigned long long id,
int thread_id,
- const base::TraceTicks& timestamp,
- unsigned char flags,
+ const base::TimeTicks& timestamp,
+ unsigned int flags,
+ unsigned long long bind_id,
const char* arg1_name,
const scoped_refptr<base::trace_event::ConvertableToTraceFormat>& arg1_val,
const char* arg2_name,
@@ -1481,7 +648,7 @@ AddTraceEventWithThreadIdAndTimestamp(
convertable_values[2] = {arg1_val, arg2_val};
return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
- phase, category_group_enabled, name, id, thread_id, timestamp,
+ phase, category_group_enabled, name, id, bind_id, thread_id, timestamp,
num_args, arg_names, arg_types, NULL, convertable_values, flags);
}
@@ -1492,10 +659,11 @@ AddTraceEventWithThreadIdAndTimestamp(
const char* name,
unsigned long long id,
int thread_id,
- const base::TraceTicks& timestamp,
- unsigned char flags) {
+ const base::TimeTicks& timestamp,
+ unsigned int flags,
+ unsigned long long bind_id) {
return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
- phase, category_group_enabled, name, id, thread_id, timestamp,
+ phase, category_group_enabled, name, id, bind_id, thread_id, timestamp,
kZeroNumArgs, NULL, NULL, NULL, NULL, flags);
}
@@ -1504,11 +672,12 @@ static inline base::trace_event::TraceEventHandle AddTraceEvent(
const unsigned char* category_group_enabled,
const char* name,
unsigned long long id,
- unsigned char flags) {
+ unsigned int flags,
+ unsigned long long bind_id) {
const int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
- const base::TraceTicks now = base::TraceTicks::Now();
- return AddTraceEventWithThreadIdAndTimestamp(phase, category_group_enabled,
- name, id, thread_id, now, flags);
+ const base::TimeTicks now = base::TimeTicks::Now();
+ return AddTraceEventWithThreadIdAndTimestamp(
+ phase, category_group_enabled, name, id, thread_id, now, flags, bind_id);
}
template<class ARG1_TYPE>
@@ -1519,8 +688,9 @@ AddTraceEventWithThreadIdAndTimestamp(
const char* name,
unsigned long long id,
int thread_id,
- const base::TraceTicks& timestamp,
- unsigned char flags,
+ const base::TimeTicks& timestamp,
+ unsigned int flags,
+ unsigned long long bind_id,
const char* arg1_name,
const ARG1_TYPE& arg1_val) {
const int num_args = 1;
@@ -1528,7 +698,7 @@ AddTraceEventWithThreadIdAndTimestamp(
unsigned long long arg_values[1];
SetTraceValue(arg1_val, &arg_types[0], &arg_values[0]);
return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
- phase, category_group_enabled, name, id, thread_id, timestamp,
+ phase, category_group_enabled, name, id, bind_id, thread_id, timestamp,
num_args, &arg1_name, arg_types, arg_values, NULL, flags);
}
@@ -1538,14 +708,15 @@ static inline base::trace_event::TraceEventHandle AddTraceEvent(
const unsigned char* category_group_enabled,
const char* name,
unsigned long long id,
- unsigned char flags,
+ unsigned int flags,
+ unsigned long long bind_id,
const char* arg1_name,
const ARG1_TYPE& arg1_val) {
int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
- base::TraceTicks now = base::TraceTicks::Now();
+ base::TimeTicks now = base::TimeTicks::Now();
return AddTraceEventWithThreadIdAndTimestamp(phase, category_group_enabled,
name, id, thread_id, now, flags,
- arg1_name, arg1_val);
+ bind_id, arg1_name, arg1_val);
}
template<class ARG1_TYPE, class ARG2_TYPE>
@@ -1556,8 +727,9 @@ AddTraceEventWithThreadIdAndTimestamp(
const char* name,
unsigned long long id,
int thread_id,
- const base::TraceTicks& timestamp,
- unsigned char flags,
+ const base::TimeTicks& timestamp,
+ unsigned int flags,
+ unsigned long long bind_id,
const char* arg1_name,
const ARG1_TYPE& arg1_val,
const char* arg2_name,
@@ -1569,7 +741,7 @@ AddTraceEventWithThreadIdAndTimestamp(
SetTraceValue(arg1_val, &arg_types[0], &arg_values[0]);
SetTraceValue(arg2_val, &arg_types[1], &arg_values[1]);
return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
- phase, category_group_enabled, name, id, thread_id, timestamp,
+ phase, category_group_enabled, name, id, bind_id, thread_id, timestamp,
num_args, arg_names, arg_types, arg_values, NULL, flags);
}
@@ -1579,17 +751,48 @@ static inline base::trace_event::TraceEventHandle AddTraceEvent(
const unsigned char* category_group_enabled,
const char* name,
unsigned long long id,
- unsigned char flags,
+ unsigned int flags,
+ unsigned long long bind_id,
const char* arg1_name,
const ARG1_TYPE& arg1_val,
const char* arg2_name,
const ARG2_TYPE& arg2_val) {
int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
- base::TraceTicks now = base::TraceTicks::Now();
- return AddTraceEventWithThreadIdAndTimestamp(phase, category_group_enabled,
- name, id, thread_id, now, flags,
- arg1_name, arg1_val,
- arg2_name, arg2_val);
+ base::TimeTicks now = base::TimeTicks::Now();
+ return AddTraceEventWithThreadIdAndTimestamp(
+ phase, category_group_enabled, name, id, thread_id, now, flags, bind_id,
+ arg1_name, arg1_val, arg2_name, arg2_val);
+}
+
+static inline void AddMetadataEvent(
+ const char* event_name,
+ const char* arg_name,
+ scoped_refptr<base::trace_event::ConvertableToTraceFormat> arg_value) {
+ const char* arg_names[1] = {arg_name};
+ scoped_refptr<base::trace_event::ConvertableToTraceFormat>
+ convertable_values[1] = {arg_value};
+ unsigned char arg_types[1] = {TRACE_VALUE_TYPE_CONVERTABLE};
+ base::trace_event::TraceLog::GetInstance()->AddMetadataEvent(
+ event_name,
+ 1, // num_args
+ arg_names, arg_types,
+ nullptr, // arg_values
+ convertable_values, TRACE_EVENT_FLAG_NONE);
+}
+
+template <class ARG1_TYPE>
+static void AddMetadataEvent(const char* event_name,
+ const char* arg_name,
+ const ARG1_TYPE& arg_val) {
+ const int num_args = 1;
+ const char* arg_names[1] = {arg_name};
+ unsigned char arg_types[1];
+ unsigned long long arg_values[1];
+ SetTraceValue(arg_val, &arg_types[0], &arg_values[0]);
+
+ base::trace_event::TraceLog::GetInstance()->AddMetadataEvent(
+ event_name, num_args, arg_names, arg_types, arg_values, nullptr,
+ TRACE_EVENT_FLAG_NONE);
}
// Used by TRACE_EVENTx macros. Do not use directly.
diff --git a/base/trace_event/trace_event_argument.cc b/base/trace_event/trace_event_argument.cc
index 14a4499c1f..6d787c80da 100644
--- a/base/trace_event/trace_event_argument.cc
+++ b/base/trace_event/trace_event_argument.cc
@@ -4,6 +4,11 @@
#include "base/trace_event/trace_event_argument.h"
+#include <stdint.h>
+
+#include <utility>
+
+#include "base/bits.h"
#include "base/json/json_writer.h"
#include "base/trace_event/trace_event_memory_overhead.h"
#include "base/values.h"
@@ -38,10 +43,10 @@ const bool kStackTypeArray = true;
inline void WriteKeyNameAsRawPtr(Pickle& pickle, const char* ptr) {
pickle.WriteBytes(&kTypeCStr, 1);
- pickle.WriteUInt64(static_cast<uint64>(reinterpret_cast<uintptr_t>(ptr)));
+ pickle.WriteUInt64(static_cast<uint64_t>(reinterpret_cast<uintptr_t>(ptr)));
}
-inline void WriteKeyNameAsStdString(Pickle& pickle, const std::string& str) {
+inline void WriteKeyNameWithCopy(Pickle& pickle, base::StringPiece str) {
pickle.WriteBytes(&kTypeString, 1);
pickle.WriteString(str);
}
@@ -51,7 +56,7 @@ std::string ReadKeyName(PickleIterator& pickle_iterator) {
bool res = pickle_iterator.ReadBytes(&type, 1);
std::string key_name;
if (res && *type == kTypeCStr) {
- uint64 ptr_value = 0;
+ uint64_t ptr_value = 0;
res = pickle_iterator.ReadUInt64(&ptr_value);
key_name = reinterpret_cast<const char*>(static_cast<uintptr_t>(ptr_value));
} else if (res && *type == kTypeString) {
@@ -84,11 +89,11 @@ void TracedValue::SetInteger(const char* name, int value) {
WriteKeyNameAsRawPtr(pickle_, name);
}
-void TracedValue::SetIntegerWithCopiedName(const std::string& name, int value) {
+void TracedValue::SetIntegerWithCopiedName(base::StringPiece name, int value) {
DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
pickle_.WriteBytes(&kTypeInt, 1);
pickle_.WriteInt(value);
- WriteKeyNameAsStdString(pickle_, name);
+ WriteKeyNameWithCopy(pickle_, name);
}
void TracedValue::SetDouble(const char* name, double value) {
@@ -98,12 +103,12 @@ void TracedValue::SetDouble(const char* name, double value) {
WriteKeyNameAsRawPtr(pickle_, name);
}
-void TracedValue::SetDoubleWithCopiedName(const std::string& name,
+void TracedValue::SetDoubleWithCopiedName(base::StringPiece name,
double value) {
DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
pickle_.WriteBytes(&kTypeDouble, 1);
pickle_.WriteDouble(value);
- WriteKeyNameAsStdString(pickle_, name);
+ WriteKeyNameWithCopy(pickle_, name);
}
void TracedValue::SetBoolean(const char* name, bool value) {
@@ -113,27 +118,27 @@ void TracedValue::SetBoolean(const char* name, bool value) {
WriteKeyNameAsRawPtr(pickle_, name);
}
-void TracedValue::SetBooleanWithCopiedName(const std::string& name,
+void TracedValue::SetBooleanWithCopiedName(base::StringPiece name,
bool value) {
DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
pickle_.WriteBytes(&kTypeBool, 1);
pickle_.WriteBool(value);
- WriteKeyNameAsStdString(pickle_, name);
+ WriteKeyNameWithCopy(pickle_, name);
}
-void TracedValue::SetString(const char* name, const std::string& value) {
+void TracedValue::SetString(const char* name, base::StringPiece value) {
DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
pickle_.WriteBytes(&kTypeString, 1);
pickle_.WriteString(value);
WriteKeyNameAsRawPtr(pickle_, name);
}
-void TracedValue::SetStringWithCopiedName(const std::string& name,
- const std::string& value) {
+void TracedValue::SetStringWithCopiedName(base::StringPiece name,
+ base::StringPiece value) {
DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
pickle_.WriteBytes(&kTypeString, 1);
pickle_.WriteString(value);
- WriteKeyNameAsStdString(pickle_, name);
+ WriteKeyNameWithCopy(pickle_, name);
}
void TracedValue::SetValue(const char* name, const TracedValue& value) {
@@ -144,7 +149,7 @@ void TracedValue::SetValue(const char* name, const TracedValue& value) {
EndDictionary();
}
-void TracedValue::SetValueWithCopiedName(const std::string& name,
+void TracedValue::SetValueWithCopiedName(base::StringPiece name,
const TracedValue& value) {
DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
BeginDictionaryWithCopiedName(name);
@@ -160,11 +165,11 @@ void TracedValue::BeginDictionary(const char* name) {
WriteKeyNameAsRawPtr(pickle_, name);
}
-void TracedValue::BeginDictionaryWithCopiedName(const std::string& name) {
+void TracedValue::BeginDictionaryWithCopiedName(base::StringPiece name) {
DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
DEBUG_PUSH_CONTAINER(kStackTypeDict);
pickle_.WriteBytes(&kTypeStartDict, 1);
- WriteKeyNameAsStdString(pickle_, name);
+ WriteKeyNameWithCopy(pickle_, name);
}
void TracedValue::BeginArray(const char* name) {
@@ -174,11 +179,11 @@ void TracedValue::BeginArray(const char* name) {
WriteKeyNameAsRawPtr(pickle_, name);
}
-void TracedValue::BeginArrayWithCopiedName(const std::string& name) {
+void TracedValue::BeginArrayWithCopiedName(base::StringPiece name) {
DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
DEBUG_PUSH_CONTAINER(kStackTypeArray);
pickle_.WriteBytes(&kTypeStartArray, 1);
- WriteKeyNameAsStdString(pickle_, name);
+ WriteKeyNameWithCopy(pickle_, name);
}
void TracedValue::EndDictionary() {
@@ -205,7 +210,7 @@ void TracedValue::AppendBoolean(bool value) {
pickle_.WriteBool(value);
}
-void TracedValue::AppendString(const std::string& value) {
+void TracedValue::AppendString(base::StringPiece value) {
DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
pickle_.WriteBytes(&kTypeString, 1);
pickle_.WriteString(value);
@@ -233,7 +238,7 @@ void TracedValue::SetValue(const char* name, scoped_ptr<base::Value> value) {
SetBaseValueWithCopiedName(name, *value);
}
-void TracedValue::SetBaseValueWithCopiedName(const std::string& name,
+void TracedValue::SetBaseValueWithCopiedName(base::StringPiece name,
const base::Value& value) {
DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
switch (value.GetType()) {
@@ -356,7 +361,8 @@ scoped_ptr<base::Value> TracedValue::ToBaseValue() const {
case kTypeStartDict: {
auto new_dict = new DictionaryValue();
if (cur_dict) {
- cur_dict->Set(ReadKeyName(it), make_scoped_ptr(new_dict));
+ cur_dict->SetWithoutPathExpansion(ReadKeyName(it),
+ make_scoped_ptr(new_dict));
stack.push_back(cur_dict);
cur_dict = new_dict;
} else {
@@ -380,7 +386,8 @@ scoped_ptr<base::Value> TracedValue::ToBaseValue() const {
case kTypeStartArray: {
auto new_list = new ListValue();
if (cur_dict) {
- cur_dict->Set(ReadKeyName(it), make_scoped_ptr(new_list));
+ cur_dict->SetWithoutPathExpansion(ReadKeyName(it),
+ make_scoped_ptr(new_list));
stack.push_back(cur_dict);
cur_dict = nullptr;
cur_list = new_list;
@@ -395,7 +402,7 @@ scoped_ptr<base::Value> TracedValue::ToBaseValue() const {
bool value;
CHECK(it.ReadBool(&value));
if (cur_dict) {
- cur_dict->SetBoolean(ReadKeyName(it), value);
+ cur_dict->SetBooleanWithoutPathExpansion(ReadKeyName(it), value);
} else {
cur_list->AppendBoolean(value);
}
@@ -405,7 +412,7 @@ scoped_ptr<base::Value> TracedValue::ToBaseValue() const {
int value;
CHECK(it.ReadInt(&value));
if (cur_dict) {
- cur_dict->SetInteger(ReadKeyName(it), value);
+ cur_dict->SetIntegerWithoutPathExpansion(ReadKeyName(it), value);
} else {
cur_list->AppendInteger(value);
}
@@ -415,7 +422,7 @@ scoped_ptr<base::Value> TracedValue::ToBaseValue() const {
double value;
CHECK(it.ReadDouble(&value));
if (cur_dict) {
- cur_dict->SetDouble(ReadKeyName(it), value);
+ cur_dict->SetDoubleWithoutPathExpansion(ReadKeyName(it), value);
} else {
cur_list->AppendDouble(value);
}
@@ -425,7 +432,7 @@ scoped_ptr<base::Value> TracedValue::ToBaseValue() const {
std::string value;
CHECK(it.ReadString(&value));
if (cur_dict) {
- cur_dict->SetString(ReadKeyName(it), value);
+ cur_dict->SetStringWithoutPathExpansion(ReadKeyName(it), value);
} else {
cur_list->AppendString(value);
}
@@ -436,7 +443,7 @@ scoped_ptr<base::Value> TracedValue::ToBaseValue() const {
}
}
DCHECK(stack.empty());
- return root.Pass();
+ return std::move(root);
}
void TracedValue::AppendAsTraceFormat(std::string* out) const {
@@ -453,9 +460,14 @@ void TracedValue::AppendAsTraceFormat(std::string* out) const {
void TracedValue::EstimateTraceMemoryOverhead(
TraceEventMemoryOverhead* overhead) {
+ const size_t kPickleHeapAlign = 4096; // Must be == Pickle::kPickleHeapAlign.
overhead->Add("TracedValue",
- pickle_.GetTotalAllocatedSize() /* allocated size */,
- pickle_.size() /* resident size */);
+
+ /* allocated size */
+ bits::Align(pickle_.GetTotalAllocatedSize(), kPickleHeapAlign),
+
+ /* resident size */
+ bits::Align(pickle_.size(), kPickleHeapAlign));
}
} // namespace trace_event
diff --git a/base/trace_event/trace_event_argument.h b/base/trace_event/trace_event_argument.h
index aab58bc5ba..a127b0d66d 100644
--- a/base/trace_event/trace_event_argument.h
+++ b/base/trace_event/trace_event_argument.h
@@ -5,12 +5,16 @@
#ifndef BASE_TRACE_EVENT_TRACE_EVENT_ARGUMENT_H_
#define BASE_TRACE_EVENT_TRACE_EVENT_ARGUMENT_H_
+#include <stddef.h>
+
#include <string>
#include <vector>
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/pickle.h"
-#include "base/trace_event/trace_event.h"
+#include "base/strings/string_piece.h"
+#include "base/trace_event/trace_event_impl.h"
namespace base {
@@ -30,26 +34,26 @@ class BASE_EXPORT TracedValue : public ConvertableToTraceFormat {
void SetInteger(const char* name, int value);
void SetDouble(const char* name, double value);
void SetBoolean(const char* name, bool value);
- void SetString(const char* name, const std::string& value);
+ void SetString(const char* name, base::StringPiece value);
void SetValue(const char* name, const TracedValue& value);
void BeginDictionary(const char* name);
void BeginArray(const char* name);
// These, instead, can be safely passed a temporary string.
- void SetIntegerWithCopiedName(const std::string& name, int value);
- void SetDoubleWithCopiedName(const std::string& name, double value);
- void SetBooleanWithCopiedName(const std::string& name, bool value);
- void SetStringWithCopiedName(const std::string& name,
- const std::string& value);
- void SetValueWithCopiedName(const std::string& name,
+ void SetIntegerWithCopiedName(base::StringPiece name, int value);
+ void SetDoubleWithCopiedName(base::StringPiece name, double value);
+ void SetBooleanWithCopiedName(base::StringPiece name, bool value);
+ void SetStringWithCopiedName(base::StringPiece name,
+ base::StringPiece value);
+ void SetValueWithCopiedName(base::StringPiece name,
const TracedValue& value);
- void BeginDictionaryWithCopiedName(const std::string& name);
- void BeginArrayWithCopiedName(const std::string& name);
+ void BeginDictionaryWithCopiedName(base::StringPiece name);
+ void BeginArrayWithCopiedName(base::StringPiece name);
void AppendInteger(int);
void AppendDouble(double);
void AppendBoolean(bool);
- void AppendString(const std::string&);
+ void AppendString(base::StringPiece);
void BeginArray();
void BeginDictionary();
@@ -63,7 +67,7 @@ class BASE_EXPORT TracedValue : public ConvertableToTraceFormat {
// TODO(primiano): migrate the (three) existing clients to the cheaper
// SetValue(TracedValue) API. crbug.com/495628.
void SetValue(const char* name, scoped_ptr<base::Value> value);
- void SetBaseValueWithCopiedName(const std::string& name,
+ void SetBaseValueWithCopiedName(base::StringPiece name,
const base::Value& value);
void AppendBaseValue(const base::Value& value);
diff --git a/base/trace_event/trace_event_argument_unittest.cc b/base/trace_event/trace_event_argument_unittest.cc
index cb1cf2ef1d..82436ba199 100644
--- a/base/trace_event/trace_event_argument_unittest.cc
+++ b/base/trace_event/trace_event_argument_unittest.cc
@@ -3,6 +3,11 @@
// found in the LICENSE file.
#include "base/trace_event/trace_event_argument.h"
+
+#include <stddef.h>
+
+#include <utility>
+
#include "base/values.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -22,6 +27,19 @@ TEST(TraceEventArgumentTest, FlatDictionary) {
json);
}
+TEST(TraceEventArgumentTest, NoDotPathExpansion) {
+ scoped_refptr<TracedValue> value = new TracedValue();
+ value->SetInteger("in.t", 2014);
+ value->SetDouble("doub.le", 0.0);
+ value->SetBoolean("bo.ol", true);
+ value->SetString("str.ing", "str.ing");
+ std::string json;
+ value->AppendAsTraceFormat(&json);
+ EXPECT_EQ(
+ "{\"bo.ol\":true,\"doub.le\":0.0,\"in.t\":2014,\"str.ing\":\"str.ing\"}",
+ json);
+}
+
TEST(TraceEventArgumentTest, Hierarchy) {
scoped_refptr<TracedValue> value = new TracedValue();
value->SetInteger("i0", 2014);
@@ -93,11 +111,11 @@ TEST(TraceEventArgumentTest, PassBaseValue) {
list_value->AppendBoolean(false);
list_value->AppendInteger(1);
list_value->AppendString("in_list");
- list_value->Append(dict_value.Pass());
+ list_value->Append(std::move(dict_value));
scoped_refptr<TracedValue> value = new TracedValue();
value->BeginDictionary("outer_dict");
- value->SetValue("inner_list", list_value.Pass());
+ value->SetValue("inner_list", std::move(list_value));
value->EndDictionary();
dict_value.reset();
diff --git a/base/trace_event/trace_event_impl.cc b/base/trace_event/trace_event_impl.cc
index 9d9165361a..24d6568f90 100644
--- a/base/trace_event/trace_event_impl.cc
+++ b/base/trace_event/trace_event_impl.cc
@@ -4,527 +4,24 @@
#include "base/trace_event/trace_event_impl.h"
-#include <algorithm>
-#include <cmath>
+#include <stddef.h>
-#include "base/base_switches.h"
-#include "base/bind.h"
-#include "base/command_line.h"
#include "base/format_macros.h"
#include "base/json/string_escape.h"
-#include "base/lazy_instance.h"
-#include "base/location.h"
-#include "base/memory/singleton.h"
-#include "base/process/process_metrics.h"
+#include "base/process/process_handle.h"
#include "base/stl_util.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/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/thread_task_runner_handle.h"
-#include "base/threading/platform_thread.h"
-#include "base/threading/thread_id_name_manager.h"
-#include "base/threading/worker_pool.h"
-#include "base/time/time.h"
-#include "base/trace_event/memory_dump_manager.h"
-#include "base/trace_event/memory_dump_provider.h"
-#include "base/trace_event/process_memory_dump.h"
#include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_synthetic_delay.h"
-
-#if defined(OS_WIN)
-#include "base/trace_event/trace_event_etw_export_win.h"
-#include "base/trace_event/trace_event_win.h"
-#endif
-
-class DeleteTraceLogForTesting {
- public:
- static void Delete() {
- Singleton<base::trace_event::TraceLog,
- LeakySingletonTraits<base::trace_event::TraceLog>>::OnExit(0);
- }
-};
-
-// The thread buckets for the sampling profiler.
-BASE_EXPORT TRACE_EVENT_API_ATOMIC_WORD g_trace_state[3];
+#include "base/trace_event/trace_log.h"
namespace base {
namespace trace_event {
namespace {
-// The overhead of TraceEvent above this threshold will be reported in the
-// trace.
-const int kOverheadReportThresholdInMicroseconds = 50;
-
-// Controls the number of trace events we will buffer in-memory
-// before throwing them away.
-const size_t kTraceBufferChunkSize = TraceBufferChunk::kTraceBufferChunkSize;
-const size_t kTraceEventVectorBigBufferChunks =
- 512000000 / kTraceBufferChunkSize;
-const size_t kTraceEventVectorBufferChunks = 256000 / kTraceBufferChunkSize;
-const size_t kTraceEventRingBufferChunks = kTraceEventVectorBufferChunks / 4;
-const size_t kTraceEventBufferSizeInBytes = 100 * 1024;
-// Can store results for 30 seconds with 1 ms sampling interval.
-const size_t kMonitorTraceEventBufferChunks = 30000 / kTraceBufferChunkSize;
-// ECHO_TO_CONSOLE needs a small buffer to hold the unfinished COMPLETE events.
-const size_t kEchoToConsoleTraceEventBufferChunks = 256;
-
-const int kThreadFlushTimeoutMs = 3000;
-
-#if !defined(OS_NACL)
-// These categories will cause deadlock when ECHO_TO_CONSOLE. crbug.com/325575.
-const char kEchoToConsoleCategoryFilter[] = "-ipc,-task";
-#endif
-
-#define MAX_CATEGORY_GROUPS 100
-
-// 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] = {
- "toplevel",
- "tracing already shutdown",
- "tracing categories exhausted; must increase MAX_CATEGORY_GROUPS",
- "__metadata",
- // For reporting trace_event overhead. For thread local event buffers only.
- "trace_event_overhead"};
-
-// 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 };
-// Indexes here have to match the g_category_groups array indexes above.
-const int g_category_already_shutdown = 1;
-const int g_category_categories_exhausted = 2;
-const int g_category_metadata = 3;
-const int g_category_trace_event_overhead = 4;
-const int g_num_builtin_categories = 5;
-// Skip default categories.
-base::subtle::AtomicWord g_category_index = g_num_builtin_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<ThreadLocalPointer<const char> >::Leaky
- g_current_thread_name = LAZY_INSTANCE_INITIALIZER;
-
-ThreadTicks ThreadNow() {
- return ThreadTicks::IsSupported() ? ThreadTicks::Now() : ThreadTicks();
-}
-
-class TraceBufferRingBuffer : public TraceBuffer {
- public:
- TraceBufferRingBuffer(size_t max_chunks)
- : max_chunks_(max_chunks),
- recyclable_chunks_queue_(new size_t[queue_capacity()]),
- queue_head_(0),
- queue_tail_(max_chunks),
- current_iteration_index_(0),
- current_chunk_seq_(1) {
- chunks_.reserve(max_chunks);
- for (size_t i = 0; i < max_chunks; ++i)
- recyclable_chunks_queue_[i] = i;
- }
-
- scoped_ptr<TraceBufferChunk> GetChunk(size_t* index) override {
- // Because the number of threads is much less than the number of chunks,
- // the queue should never be empty.
- DCHECK(!QueueIsEmpty());
-
- *index = recyclable_chunks_queue_[queue_head_];
- queue_head_ = NextQueueIndex(queue_head_);
- current_iteration_index_ = queue_head_;
-
- if (*index >= chunks_.size())
- chunks_.resize(*index + 1);
-
- TraceBufferChunk* chunk = chunks_[*index];
- chunks_[*index] = NULL; // Put NULL in the slot of a in-flight chunk.
- if (chunk)
- chunk->Reset(current_chunk_seq_++);
- else
- chunk = new TraceBufferChunk(current_chunk_seq_++);
-
- return scoped_ptr<TraceBufferChunk>(chunk);
- }
-
- void ReturnChunk(size_t index, scoped_ptr<TraceBufferChunk> chunk) override {
- // When this method is called, the queue should not be full because it
- // can contain all chunks including the one to be returned.
- DCHECK(!QueueIsFull());
- DCHECK(chunk);
- DCHECK_LT(index, chunks_.size());
- DCHECK(!chunks_[index]);
- chunks_[index] = chunk.release();
- recyclable_chunks_queue_[queue_tail_] = index;
- queue_tail_ = NextQueueIndex(queue_tail_);
- }
-
- bool IsFull() const override { return false; }
-
- size_t Size() const override {
- // This is approximate because not all of the chunks are full.
- return chunks_.size() * kTraceBufferChunkSize;
- }
-
- size_t Capacity() const override {
- return max_chunks_ * kTraceBufferChunkSize;
- }
-
- TraceEvent* GetEventByHandle(TraceEventHandle handle) override {
- if (handle.chunk_index >= chunks_.size())
- return NULL;
- TraceBufferChunk* chunk = chunks_[handle.chunk_index];
- if (!chunk || chunk->seq() != handle.chunk_seq)
- return NULL;
- return chunk->GetEventAt(handle.event_index);
- }
-
- const TraceBufferChunk* NextChunk() override {
- if (chunks_.empty())
- return NULL;
-
- while (current_iteration_index_ != queue_tail_) {
- size_t chunk_index = recyclable_chunks_queue_[current_iteration_index_];
- current_iteration_index_ = NextQueueIndex(current_iteration_index_);
- if (chunk_index >= chunks_.size()) // Skip uninitialized chunks.
- continue;
- DCHECK(chunks_[chunk_index]);
- return chunks_[chunk_index];
- }
- return NULL;
- }
-
- scoped_ptr<TraceBuffer> CloneForIteration() const override {
- scoped_ptr<ClonedTraceBuffer> cloned_buffer(new ClonedTraceBuffer());
- for (size_t queue_index = queue_head_; queue_index != queue_tail_;
- queue_index = NextQueueIndex(queue_index)) {
- size_t chunk_index = recyclable_chunks_queue_[queue_index];
- if (chunk_index >= chunks_.size()) // Skip uninitialized chunks.
- continue;
- TraceBufferChunk* chunk = chunks_[chunk_index];
- cloned_buffer->chunks_.push_back(chunk ? chunk->Clone().release() : NULL);
- }
- return cloned_buffer.Pass();
- }
-
- void EstimateTraceMemoryOverhead(
- TraceEventMemoryOverhead* overhead) override {
- overhead->Add("TraceBufferRingBuffer", sizeof(*this));
- for (size_t queue_index = queue_head_; queue_index != queue_tail_;
- queue_index = NextQueueIndex(queue_index)) {
- size_t chunk_index = recyclable_chunks_queue_[queue_index];
- if (chunk_index >= chunks_.size()) // Skip uninitialized chunks.
- continue;
- chunks_[chunk_index]->EstimateTraceMemoryOverhead(overhead);
- }
- }
-
- private:
- class ClonedTraceBuffer : public TraceBuffer {
- public:
- ClonedTraceBuffer() : current_iteration_index_(0) {}
-
- // The only implemented method.
- const TraceBufferChunk* NextChunk() override {
- return current_iteration_index_ < chunks_.size() ?
- chunks_[current_iteration_index_++] : NULL;
- }
-
- scoped_ptr<TraceBufferChunk> GetChunk(size_t* /* index */) override {
- NOTIMPLEMENTED();
- return scoped_ptr<TraceBufferChunk>();
- }
- void ReturnChunk(size_t /* index */,
- scoped_ptr<TraceBufferChunk>) override {
- NOTIMPLEMENTED();
- }
- bool IsFull() const override { return false; }
- size_t Size() const override { return 0; }
- size_t Capacity() const override { return 0; }
- TraceEvent* GetEventByHandle(TraceEventHandle /* handle */) override {
- return NULL;
- }
- scoped_ptr<TraceBuffer> CloneForIteration() const override {
- NOTIMPLEMENTED();
- return scoped_ptr<TraceBuffer>();
- }
- void EstimateTraceMemoryOverhead(
- TraceEventMemoryOverhead* /* overhead */) override {
- NOTIMPLEMENTED();
- }
-
- size_t current_iteration_index_;
- ScopedVector<TraceBufferChunk> chunks_;
- };
-
- bool QueueIsEmpty() const {
- return queue_head_ == queue_tail_;
- }
-
- size_t QueueSize() const {
- return queue_tail_ > queue_head_ ? queue_tail_ - queue_head_ :
- queue_tail_ + queue_capacity() - queue_head_;
- }
-
- bool QueueIsFull() const {
- return QueueSize() == queue_capacity() - 1;
- }
-
- size_t queue_capacity() const {
- // One extra space to help distinguish full state and empty state.
- return max_chunks_ + 1;
- }
-
- size_t NextQueueIndex(size_t index) const {
- index++;
- if (index >= queue_capacity())
- index = 0;
- return index;
- }
-
- size_t max_chunks_;
- ScopedVector<TraceBufferChunk> chunks_;
-
- scoped_ptr<size_t[]> recyclable_chunks_queue_;
- size_t queue_head_;
- size_t queue_tail_;
-
- size_t current_iteration_index_;
- uint32 current_chunk_seq_;
-
- DISALLOW_COPY_AND_ASSIGN(TraceBufferRingBuffer);
-};
-
-class TraceBufferVector : public TraceBuffer {
- public:
- TraceBufferVector(size_t max_chunks)
- : in_flight_chunk_count_(0),
- current_iteration_index_(0),
- max_chunks_(max_chunks) {
- chunks_.reserve(max_chunks_);
- }
-
- scoped_ptr<TraceBufferChunk> GetChunk(size_t* index) override {
- // This function may be called when adding normal events or indirectly from
- // AddMetadataEventsWhileLocked(). We can not DECHECK(!IsFull()) because we
- // have to add the metadata events and flush thread-local buffers even if
- // the buffer is full.
- *index = chunks_.size();
- chunks_.push_back(NULL); // Put NULL in the slot of a in-flight chunk.
- ++in_flight_chunk_count_;
- // + 1 because zero chunk_seq is not allowed.
- return scoped_ptr<TraceBufferChunk>(
- new TraceBufferChunk(static_cast<uint32>(*index) + 1));
- }
-
- void ReturnChunk(size_t index, scoped_ptr<TraceBufferChunk> chunk) override {
- DCHECK_GT(in_flight_chunk_count_, 0u);
- DCHECK_LT(index, chunks_.size());
- DCHECK(!chunks_[index]);
- --in_flight_chunk_count_;
- chunks_[index] = chunk.release();
- }
-
- bool IsFull() const override { return chunks_.size() >= max_chunks_; }
-
- size_t Size() const override {
- // This is approximate because not all of the chunks are full.
- return chunks_.size() * kTraceBufferChunkSize;
- }
-
- size_t Capacity() const override {
- return max_chunks_ * kTraceBufferChunkSize;
- }
-
- TraceEvent* GetEventByHandle(TraceEventHandle handle) override {
- if (handle.chunk_index >= chunks_.size())
- return NULL;
- TraceBufferChunk* chunk = chunks_[handle.chunk_index];
- if (!chunk || chunk->seq() != handle.chunk_seq)
- return NULL;
- return chunk->GetEventAt(handle.event_index);
- }
-
- const TraceBufferChunk* NextChunk() override {
- while (current_iteration_index_ < chunks_.size()) {
- // Skip in-flight chunks.
- const TraceBufferChunk* chunk = chunks_[current_iteration_index_++];
- if (chunk)
- return chunk;
- }
- return NULL;
- }
-
- scoped_ptr<TraceBuffer> CloneForIteration() const override {
- NOTIMPLEMENTED();
- return scoped_ptr<TraceBuffer>();
- }
-
- void EstimateTraceMemoryOverhead(
- TraceEventMemoryOverhead* overhead) override {
- // Skip the in-flight chunks owned by the threads. They will be accounted
- // by the per-thread-local dumper, see ThreadLocalEventBuffer::OnMemoryDump.
- overhead->Add("TraceBufferVector", sizeof(*this));
- for (size_t i = 0; i < chunks_.size(); ++i) {
- TraceBufferChunk* chunk = chunks_[i];
- if (chunk)
- chunk->EstimateTraceMemoryOverhead(overhead);
- }
- }
-
- private:
- size_t in_flight_chunk_count_;
- size_t current_iteration_index_;
- size_t max_chunks_;
- ScopedVector<TraceBufferChunk> chunks_;
-
- DISALLOW_COPY_AND_ASSIGN(TraceBufferVector);
-};
-
-template <typename T>
-void InitializeMetadataEvent(TraceEvent* trace_event,
- int thread_id,
- const char* metadata_name, const char* arg_name,
- const T& value) {
- if (!trace_event)
- return;
-
- int num_args = 1;
- unsigned char arg_type;
- unsigned long long arg_value;
- ::trace_event_internal::SetTraceValue(value, &arg_type, &arg_value);
- trace_event->Initialize(thread_id,
- TraceTicks(), ThreadTicks(),
- 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);
-}
-
-class AutoThreadLocalBoolean {
- public:
- explicit AutoThreadLocalBoolean(ThreadLocalBoolean* thread_local_boolean)
- : thread_local_boolean_(thread_local_boolean) {
- DCHECK(!thread_local_boolean_->Get());
- thread_local_boolean_->Set(true);
- }
- ~AutoThreadLocalBoolean() {
- thread_local_boolean_->Set(false);
- }
-
- private:
- ThreadLocalBoolean* thread_local_boolean_;
- DISALLOW_COPY_AND_ASSIGN(AutoThreadLocalBoolean);
-};
-
-} // namespace
-
-TraceBufferChunk::TraceBufferChunk(uint32 seq) : next_free_(0), seq_(seq) {
-}
-
-TraceBufferChunk::~TraceBufferChunk() {
-}
-
-void TraceBufferChunk::Reset(uint32 new_seq) {
- for (size_t i = 0; i < next_free_; ++i)
- chunk_[i].Reset();
- next_free_ = 0;
- seq_ = new_seq;
- cached_overhead_estimate_when_full_.reset();
-}
-
-TraceEvent* TraceBufferChunk::AddTraceEvent(size_t* event_index) {
- DCHECK(!IsFull());
- *event_index = next_free_++;
- return &chunk_[*event_index];
-}
-
-scoped_ptr<TraceBufferChunk> TraceBufferChunk::Clone() const {
- scoped_ptr<TraceBufferChunk> cloned_chunk(new TraceBufferChunk(seq_));
- cloned_chunk->next_free_ = next_free_;
- for (size_t i = 0; i < next_free_; ++i)
- cloned_chunk->chunk_[i].CopyFrom(chunk_[i]);
- return cloned_chunk.Pass();
-}
-
-void TraceBufferChunk::EstimateTraceMemoryOverhead(
- TraceEventMemoryOverhead* overhead) {
- if (cached_overhead_estimate_when_full_) {
- DCHECK(IsFull());
- overhead->Update(*cached_overhead_estimate_when_full_);
- return;
- }
-
- // Cache the memory overhead estimate only if the chunk is full.
- TraceEventMemoryOverhead* estimate = overhead;
- if (IsFull()) {
- cached_overhead_estimate_when_full_.reset(new TraceEventMemoryOverhead);
- estimate = cached_overhead_estimate_when_full_.get();
- }
-
- estimate->Add("TraceBufferChunk", sizeof(*this));
- for (size_t i = 0; i < next_free_; ++i)
- chunk_[i].EstimateTraceMemoryOverhead(estimate);
-
- if (IsFull()) {
- estimate->AddSelf();
- overhead->Update(*estimate);
- }
-}
-
-// A helper class that allows the lock to be acquired in the middle of the scope
-// and unlocks at the end of scope if locked.
-class TraceLog::OptionalAutoLock {
- public:
- explicit OptionalAutoLock(Lock* lock) : lock_(lock), locked_(false) {}
-
- ~OptionalAutoLock() {
- if (locked_)
- lock_->Release();
- }
-
- void EnsureAcquired() {
- if (!locked_) {
- lock_->Acquire();
- locked_ = true;
- }
- }
-
- private:
- Lock* lock_;
- bool locked_;
- DISALLOW_COPY_AND_ASSIGN(OptionalAutoLock);
-};
-
-// Use this function instead of TraceEventHandle constructor to keep the
-// overhead of ScopedTracer (trace_event.h) constructor minimum.
-void MakeHandle(uint32 chunk_seq, size_t chunk_index, size_t event_index,
- TraceEventHandle* handle) {
- DCHECK(chunk_seq);
- DCHECK(chunk_index < (1u << 16));
- DCHECK(event_index < (1u << 16));
- handle->chunk_seq = chunk_seq;
- handle->chunk_index = static_cast<uint16>(chunk_index);
- handle->event_index = static_cast<uint16>(event_index);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-// 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
@@ -548,8 +45,8 @@ TraceEvent::TraceEvent()
category_group_enabled_(NULL),
name_(NULL),
thread_id_(0),
- phase_(TRACE_EVENT_PHASE_BEGIN),
- flags_(0) {
+ flags_(0),
+ phase_(TRACE_EVENT_PHASE_BEGIN) {
for (int i = 0; i < kTraceMaxNumArgs; ++i)
arg_names_[i] = NULL;
memset(arg_values_, 0, sizeof(arg_values_));
@@ -565,7 +62,10 @@ void TraceEvent::CopyFrom(const TraceEvent& other) {
id_ = other.id_;
category_group_enabled_ = other.category_group_enabled_;
name_ = other.name_;
- thread_id_ = other.thread_id_;
+ if (other.flags_ & TRACE_EVENT_FLAG_HAS_PROCESS_ID)
+ process_id_ = other.process_id_;
+ else
+ thread_id_ = other.thread_id_;
phase_ = other.phase_;
flags_ = other.flags_;
parameter_copy_storage_ = other.parameter_copy_storage_;
@@ -580,18 +80,19 @@ void TraceEvent::CopyFrom(const TraceEvent& other) {
void TraceEvent::Initialize(
int thread_id,
- TraceTicks timestamp,
+ TimeTicks timestamp,
ThreadTicks thread_timestamp,
char phase,
const unsigned char* category_group_enabled,
const char* name,
unsigned long long id,
+ unsigned long long bind_id,
int num_args,
const char** arg_names,
const unsigned char* arg_types,
const unsigned long long* arg_values,
const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
- unsigned char flags) {
+ unsigned int flags) {
timestamp_ = timestamp;
thread_timestamp_ = thread_timestamp;
duration_ = TimeDelta::FromInternalValue(-1);
@@ -601,6 +102,7 @@ void TraceEvent::Initialize(
thread_id_ = thread_id;
phase_ = phase;
flags_ = flags;
+ bind_id_ = bind_id;
// Clamp num_args since it may have been set by a third_party library.
num_args = (num_args > kTraceMaxNumArgs) ? kTraceMaxNumArgs : num_args;
@@ -672,37 +174,33 @@ void TraceEvent::Reset() {
parameter_copy_storage_ = NULL;
for (int i = 0; i < kTraceMaxNumArgs; ++i)
convertable_values_[i] = NULL;
- cached_memory_overhead_estimate_.reset();
}
-void TraceEvent::UpdateDuration(const TraceTicks& now,
+void TraceEvent::UpdateDuration(const TimeTicks& now,
const ThreadTicks& thread_now) {
DCHECK_EQ(duration_.ToInternalValue(), -1);
duration_ = now - timestamp_;
- thread_duration_ = thread_now - thread_timestamp_;
+
+ // |thread_timestamp_| can be empty if the thread ticks clock wasn't
+ // initialized when it was recorded.
+ if (thread_timestamp_ != ThreadTicks())
+ thread_duration_ = thread_now - thread_timestamp_;
}
void TraceEvent::EstimateTraceMemoryOverhead(
TraceEventMemoryOverhead* overhead) {
- if (!cached_memory_overhead_estimate_) {
- cached_memory_overhead_estimate_.reset(new TraceEventMemoryOverhead);
- cached_memory_overhead_estimate_->Add("TraceEvent", sizeof(*this));
- // TODO(primiano): parameter_copy_storage_ is refcounted and, in theory,
- // could be shared by several events and we might overcount. In practice
- // this is unlikely but it's worth checking.
- if (parameter_copy_storage_) {
- cached_memory_overhead_estimate_->AddRefCountedString(
- *parameter_copy_storage_.get());
- }
- for (size_t i = 0; i < kTraceMaxNumArgs; ++i) {
- if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE) {
- convertable_values_[i]->EstimateTraceMemoryOverhead(
- cached_memory_overhead_estimate_.get());
- }
- }
- cached_memory_overhead_estimate_->AddSelf();
+ overhead->Add("TraceEvent", sizeof(*this));
+
+ // TODO(primiano): parameter_copy_storage_ is refcounted and, in theory,
+ // could be shared by several events and we might overcount. In practice
+ // this is unlikely but it's worth checking.
+ if (parameter_copy_storage_)
+ overhead->AddRefCountedString(*parameter_copy_storage_.get());
+
+ for (size_t i = 0; i < kTraceMaxNumArgs; ++i) {
+ if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE)
+ convertable_values_[i]->EstimateTraceMemoryOverhead(overhead);
}
- overhead->Update(*cached_memory_overhead_estimate_);
}
// static
@@ -714,10 +212,10 @@ void TraceEvent::AppendValueAsJSON(unsigned char type,
*out += value.as_bool ? "true" : "false";
break;
case TRACE_VALUE_TYPE_UINT:
- StringAppendF(out, "%" PRIu64, static_cast<uint64>(value.as_uint));
+ StringAppendF(out, "%" PRIu64, static_cast<uint64_t>(value.as_uint));
break;
case TRACE_VALUE_TYPE_INT:
- StringAppendF(out, "%" PRId64, static_cast<int64>(value.as_int));
+ StringAppendF(out, "%" PRId64, static_cast<int64_t>(value.as_int));
break;
case TRACE_VALUE_TYPE_DOUBLE: {
// FIXME: base/json/json_writer.cc is using the same code,
@@ -757,9 +255,9 @@ void TraceEvent::AppendValueAsJSON(unsigned char type,
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<uint64>(
- reinterpret_cast<intptr_t>(
- value.as_pointer)));
+ StringAppendF(
+ out, "\"0x%" PRIx64 "\"",
+ static_cast<uint64_t>(reinterpret_cast<intptr_t>(value.as_pointer)));
break;
case TRACE_VALUE_TYPE_STRING:
case TRACE_VALUE_TYPE_COPY_STRING:
@@ -774,8 +272,17 @@ void TraceEvent::AppendValueAsJSON(unsigned char type,
void TraceEvent::AppendAsJSON(
std::string* out,
const ArgumentFilterPredicate& argument_filter_predicate) const {
- int64 time_int64 = timestamp_.ToInternalValue();
- int process_id = TraceLog::GetInstance()->process_id();
+ int64_t time_int64 = timestamp_.ToInternalValue();
+ int process_id;
+ int thread_id;
+ if ((flags_ & TRACE_EVENT_FLAG_HAS_PROCESS_ID) &&
+ process_id_ != kNullProcessId) {
+ process_id = process_id_;
+ thread_id = -1;
+ } else {
+ process_id = TraceLog::GetInstance()->process_id();
+ thread_id = thread_id_;
+ }
const char* category_group_name =
TraceLog::GetCategoryGroupName(category_group_enabled_);
@@ -784,12 +291,18 @@ void TraceEvent::AppendAsJSON(
StringAppendF(out, "{\"pid\":%i,\"tid\":%i,\"ts\":%" PRId64
","
"\"ph\":\"%c\",\"cat\":\"%s\",\"name\":\"%s\",\"args\":",
- process_id, thread_id_, time_int64, phase_, category_group_name,
+ process_id, thread_id, time_int64, phase_, category_group_name,
name_);
// Output argument names and values, stop at first NULL argument name.
- bool strip_args = arg_names_[0] && !argument_filter_predicate.is_null() &&
- !argument_filter_predicate.Run(category_group_name, name_);
+ // TODO(oysteine): The dual predicates here is a bit ugly; if the filtering
+ // capabilities need to grow even more precise we should rethink this
+ // approach
+ ArgumentNameFilterPredicate argument_name_filter_predicate;
+ bool strip_args =
+ arg_names_[0] && !argument_filter_predicate.is_null() &&
+ !argument_filter_predicate.Run(category_group_name, name_,
+ &argument_name_filter_predicate);
if (strip_args) {
*out += "\"__stripped__\"";
@@ -803,21 +316,26 @@ void TraceEvent::AppendAsJSON(
*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);
+ if (argument_name_filter_predicate.is_null() ||
+ argument_name_filter_predicate.Run(arg_names_[i])) {
+ if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE)
+ convertable_values_[i]->AppendAsTraceFormat(out);
+ else
+ AppendValueAsJSON(arg_types_[i], arg_values_[i], out);
+ } else {
+ *out += "\"__stripped__\"";
+ }
}
*out += "}";
}
if (phase_ == TRACE_EVENT_PHASE_COMPLETE) {
- int64 duration = duration_.ToInternalValue();
+ int64_t duration = duration_.ToInternalValue();
if (duration != -1)
StringAppendF(out, ",\"dur\":%" PRId64, duration);
if (!thread_timestamp_.is_null()) {
- int64 thread_duration = thread_duration_.ToInternalValue();
+ int64_t thread_duration = thread_duration_.ToInternalValue();
if (thread_duration != -1)
StringAppendF(out, ",\"tdur\":%" PRId64, thread_duration);
}
@@ -825,7 +343,7 @@ void TraceEvent::AppendAsJSON(
// Output tts if thread_timestamp is valid.
if (!thread_timestamp_.is_null()) {
- int64 thread_time_int64 = thread_timestamp_.ToInternalValue();
+ int64_t thread_time_int64 = thread_timestamp_.ToInternalValue();
StringAppendF(out, ",\"tts\":%" PRId64, thread_time_int64);
}
@@ -837,11 +355,21 @@ void TraceEvent::AppendAsJSON(
// 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<uint64>(id_));
+ StringAppendF(out, ",\"id\":\"0x%" PRIx64 "\"", static_cast<uint64_t>(id_));
if (flags_ & TRACE_EVENT_FLAG_BIND_TO_ENCLOSING)
StringAppendF(out, ",\"bp\":\"e\"");
+ if ((flags_ & TRACE_EVENT_FLAG_FLOW_OUT) ||
+ (flags_ & TRACE_EVENT_FLAG_FLOW_IN)) {
+ StringAppendF(out, ",\"bind_id\":\"0x%" PRIx64 "\"",
+ static_cast<uint64_t>(bind_id_));
+ }
+ if (flags_ & TRACE_EVENT_FLAG_FLOW_IN)
+ StringAppendF(out, ",\"flow_in\":true");
+ if (flags_ & TRACE_EVENT_FLAG_FLOW_OUT)
+ StringAppendF(out, ",\"flow_out\":true");
+
// Instant events also output their scope.
if (phase_ == TRACE_EVENT_PHASE_INSTANT) {
char scope = '?';
@@ -887,1599 +415,5 @@ void TraceEvent::AppendPrettyPrinted(std::ostringstream* out) const {
}
}
-////////////////////////////////////////////////////////////////////////////////
-//
-// 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<void(TraceBucketData*)> 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();
- ~TraceSamplingThread() override;
-
- // Implementation of PlatformThread::Delegate:
- void ThreadMain() override;
-
- static void DefaultSamplingCallback(TraceBucketData* bucekt_data);
-
- void Stop();
- void WaitSamplingEventForTesting();
-
- 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<TraceBucketData> sample_buckets_;
- bool thread_running_;
- CancellationFlag cancellation_flag_;
- WaitableEvent waitable_event_for_testing_;
-};
-
-
-TraceSamplingThread::TraceSamplingThread()
- : thread_running_(false),
- waitable_event_for_testing_(false, false) {
-}
-
-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();
- waitable_event_for_testing_.Signal();
- }
-}
-
-// static
-void TraceSamplingThread::DefaultSamplingCallback(
- 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<const char* const>(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) {
- // Access to sample_buckets_ doesn't cause races with the sampling thread
- // that uses the sample_buckets_, because it is guaranteed that
- // RegisterSampleBucket is called before the sampling thread is created.
- 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::WaitSamplingEventForTesting() {
- waitable_event_for_testing_.Wait();
-}
-
-TraceBucketData::TraceBucketData(base::subtle::AtomicWord* bucket,
- const char* name,
- TraceSampleCallback callback)
- : bucket(bucket),
- bucket_name(name),
- callback(callback) {
-}
-
-TraceBucketData::~TraceBucketData() {
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-// TraceLog
-//
-////////////////////////////////////////////////////////////////////////////////
-
-class TraceLog::ThreadLocalEventBuffer
- : public MessageLoop::DestructionObserver,
- public MemoryDumpProvider {
- public:
- ThreadLocalEventBuffer(TraceLog* trace_log);
- ~ThreadLocalEventBuffer() override;
-
- TraceEvent* AddTraceEvent(TraceEventHandle* handle);
-
- void ReportOverhead(const TraceTicks& event_timestamp,
- const ThreadTicks& event_thread_timestamp);
-
- TraceEvent* GetEventByHandle(TraceEventHandle handle) {
- if (!chunk_ || handle.chunk_seq != chunk_->seq() ||
- handle.chunk_index != chunk_index_)
- return NULL;
-
- return chunk_->GetEventAt(handle.event_index);
- }
-
- int generation() const { return generation_; }
-
- private:
- // MessageLoop::DestructionObserver
- void WillDestroyCurrentMessageLoop() override;
-
- // MemoryDumpProvider implementation.
- bool OnMemoryDump(ProcessMemoryDump* pmd) override;
-
- void FlushWhileLocked();
-
- void CheckThisIsCurrentBuffer() const {
- DCHECK(trace_log_->thread_local_event_buffer_.Get() == this);
- }
-
- // Since TraceLog is a leaky singleton, trace_log_ will always be valid
- // as long as the thread exists.
- TraceLog* trace_log_;
- scoped_ptr<TraceBufferChunk> chunk_;
- size_t chunk_index_;
- int event_count_;
- TimeDelta overhead_;
- int generation_;
-
- DISALLOW_COPY_AND_ASSIGN(ThreadLocalEventBuffer);
-};
-
-TraceLog::ThreadLocalEventBuffer::ThreadLocalEventBuffer(TraceLog* trace_log)
- : trace_log_(trace_log),
- chunk_index_(0),
- event_count_(0),
- generation_(trace_log->generation()) {
- // ThreadLocalEventBuffer is created only if the thread has a message loop, so
- // the following message_loop won't be NULL.
- MessageLoop* message_loop = MessageLoop::current();
- message_loop->AddDestructionObserver(this);
-
- // This is to report the local memory usage when memory-infra is enabled.
- MemoryDumpManager::GetInstance()->RegisterDumpProvider(
- this, ThreadTaskRunnerHandle::Get());
-
- AutoLock lock(trace_log->lock_);
- trace_log->thread_message_loops_.insert(message_loop);
-}
-
-TraceLog::ThreadLocalEventBuffer::~ThreadLocalEventBuffer() {
- CheckThisIsCurrentBuffer();
- MessageLoop::current()->RemoveDestructionObserver(this);
- MemoryDumpManager::GetInstance()->UnregisterDumpProvider(this);
-
- // Zero event_count_ happens in either of the following cases:
- // - no event generated for the thread;
- // - the thread has no message loop;
- // - trace_event_overhead is disabled.
- if (event_count_) {
- InitializeMetadataEvent(AddTraceEvent(NULL),
- static_cast<int>(base::PlatformThread::CurrentId()),
- "overhead", "average_overhead",
- overhead_.InMillisecondsF() / event_count_);
- }
-
- {
- AutoLock lock(trace_log_->lock_);
- FlushWhileLocked();
- trace_log_->thread_message_loops_.erase(MessageLoop::current());
- }
- trace_log_->thread_local_event_buffer_.Set(NULL);
-}
-
-TraceEvent* TraceLog::ThreadLocalEventBuffer::AddTraceEvent(
- TraceEventHandle* handle) {
- CheckThisIsCurrentBuffer();
-
- if (chunk_ && chunk_->IsFull()) {
- AutoLock lock(trace_log_->lock_);
- FlushWhileLocked();
- chunk_.reset();
- }
- if (!chunk_) {
- AutoLock lock(trace_log_->lock_);
- chunk_ = trace_log_->logged_events_->GetChunk(&chunk_index_);
- trace_log_->CheckIfBufferIsFullWhileLocked();
- }
- if (!chunk_)
- return NULL;
-
- size_t event_index;
- TraceEvent* trace_event = chunk_->AddTraceEvent(&event_index);
- if (trace_event && handle)
- MakeHandle(chunk_->seq(), chunk_index_, event_index, handle);
-
- return trace_event;
-}
-
-void TraceLog::ThreadLocalEventBuffer::ReportOverhead(
- const TraceTicks& event_timestamp,
- const ThreadTicks& event_thread_timestamp) {
- if (!g_category_group_enabled[g_category_trace_event_overhead])
- return;
-
- CheckThisIsCurrentBuffer();
-
- event_count_++;
- ThreadTicks thread_now = ThreadNow();
- TraceTicks now = trace_log_->OffsetNow();
- TimeDelta overhead = now - event_timestamp;
- if (overhead.InMicroseconds() >= kOverheadReportThresholdInMicroseconds) {
- TraceEvent* trace_event = AddTraceEvent(NULL);
- if (trace_event) {
- trace_event->Initialize(
- static_cast<int>(PlatformThread::CurrentId()),
- event_timestamp, event_thread_timestamp,
- TRACE_EVENT_PHASE_COMPLETE,
- &g_category_group_enabled[g_category_trace_event_overhead],
- "overhead", 0, 0, NULL, NULL, NULL, NULL, 0);
- trace_event->UpdateDuration(now, thread_now);
- }
- }
- overhead_ += overhead;
-}
-
-void TraceLog::ThreadLocalEventBuffer::WillDestroyCurrentMessageLoop() {
- delete this;
-}
-
-bool TraceLog::ThreadLocalEventBuffer::OnMemoryDump(ProcessMemoryDump* pmd) {
- if (!chunk_)
- return true;
- std::string dump_base_name = StringPrintf(
- "tracing/thread_%d", static_cast<int>(PlatformThread::CurrentId()));
- TraceEventMemoryOverhead overhead;
- chunk_->EstimateTraceMemoryOverhead(&overhead);
- overhead.DumpInto(dump_base_name.c_str(), pmd);
- return true;
-}
-
-void TraceLog::ThreadLocalEventBuffer::FlushWhileLocked() {
- if (!chunk_)
- return;
-
- trace_log_->lock_.AssertAcquired();
- if (trace_log_->CheckGeneration(generation_)) {
- // Return the chunk to the buffer only if the generation matches.
- trace_log_->logged_events_->ReturnChunk(chunk_index_, chunk_.Pass());
- }
- // Otherwise this method may be called from the destructor, or TraceLog will
- // find the generation mismatch and delete this buffer soon.
-}
-
-TraceLogStatus::TraceLogStatus() : event_capacity(0), event_count(0) {
-}
-
-TraceLogStatus::~TraceLogStatus() {
-}
-
-// static
-TraceLog* TraceLog::GetInstance() {
- return Singleton<TraceLog, LeakySingletonTraits<TraceLog> >::get();
-}
-
-TraceLog::TraceLog()
- : mode_(DISABLED),
- num_traces_recorded_(0),
- event_callback_(0),
- dispatching_to_observer_list_(false),
- process_sort_index_(0),
- process_id_hash_(0),
- process_id_(0),
- watch_category_(0),
- trace_options_(kInternalRecordUntilFull),
- sampling_thread_handle_(0),
- trace_config_(TraceConfig()),
- event_callback_trace_config_(TraceConfig()),
- thread_shared_chunk_index_(0),
- generation_(0),
- use_worker_thread_(false) {
- // 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.
-#if defined(OS_NACL) // NaCl shouldn't expose the process id.
- SetProcessID(0);
-#else
- SetProcessID(static_cast<int>(GetCurrentProcId()));
-
- // NaCl also shouldn't access the command line.
- if (CommandLine::InitializedForCurrentProcess() &&
- CommandLine::ForCurrentProcess()->HasSwitch(switches::kTraceToConsole)) {
- std::string filter = CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
- switches::kTraceToConsole);
- if (filter.empty()) {
- filter = kEchoToConsoleCategoryFilter;
- } else {
- filter.append(",");
- filter.append(kEchoToConsoleCategoryFilter);
- }
-
- LOG(ERROR) << "Start " << switches::kTraceToConsole
- << " with CategoryFilter '" << filter << "'.";
- SetEnabled(TraceConfig(filter, ECHO_TO_CONSOLE), RECORDING_MODE);
- }
-#endif
-
- logged_events_.reset(CreateTraceBuffer());
-
- MemoryDumpManager::GetInstance()->RegisterDumpProvider(this);
-}
-
-TraceLog::~TraceLog() {
-}
-
-bool TraceLog::OnMemoryDump(ProcessMemoryDump* pmd) {
- TraceEventMemoryOverhead overhead;
- overhead.Add("TraceLog", sizeof(*this));
- if (logged_events_)
- logged_events_->EstimateTraceMemoryOverhead(&overhead);
- overhead.AddSelf();
- overhead.DumpInto("tracing/main_trace_log", pmd);
- return true;
-}
-
-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<uintptr_t>(g_category_group_enabled);
- uintptr_t category_ptr = reinterpret_cast<uintptr_t>(category_group_enabled);
- DCHECK(category_ptr >= category_begin &&
- category_ptr < reinterpret_cast<uintptr_t>(
- 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(size_t category_index) {
- unsigned char enabled_flag = 0;
- const char* category_group = g_category_groups[category_index];
- if (mode_ == RECORDING_MODE &&
- trace_config_.IsCategoryGroupEnabled(category_group))
- enabled_flag |= ENABLED_FOR_RECORDING;
- else if (mode_ == MONITORING_MODE &&
- trace_config_.IsCategoryGroupEnabled(category_group))
- enabled_flag |= ENABLED_FOR_MONITORING;
- if (event_callback_ &&
- event_callback_trace_config_.IsCategoryGroupEnabled(category_group))
- enabled_flag |= ENABLED_FOR_EVENT_CALLBACK;
-#if defined(OS_WIN)
- if (base::trace_event::TraceEventETWExport::isETWExportEnabled())
- enabled_flag |= ENABLED_FOR_ETW_EXPORT;
-#endif
-
- g_category_group_enabled[category_index] = enabled_flag;
-}
-
-void TraceLog::UpdateCategoryGroupEnabledFlags() {
- size_t category_index = base::subtle::NoBarrier_Load(&g_category_index);
- for (size_t i = 0; i < category_index; i++)
- UpdateCategoryGroupEnabledFlag(i);
-}
-
-void TraceLog::UpdateSyntheticDelaysFromTraceConfig() {
- ResetTraceEventSyntheticDelays();
- const TraceConfig::StringList& delays =
- trace_config_.GetSyntheticDelayValues();
- TraceConfig::StringList::const_iterator ci;
- for (ci = delays.begin(); ci != delays.end(); ++ci) {
- StringTokenizer tokens(*ci, ";");
- if (!tokens.GetNext())
- continue;
- TraceEventSyntheticDelay* delay =
- TraceEventSyntheticDelay::Lookup(tokens.token());
- while (tokens.GetNext()) {
- std::string token = tokens.token();
- char* duration_end;
- double target_duration = strtod(token.c_str(), &duration_end);
- if (duration_end != token.c_str()) {
- delay->SetTargetDuration(TimeDelta::FromMicroseconds(
- static_cast<int64>(target_duration * 1e6)));
- } else if (token == "static") {
- delay->SetMode(TraceEventSyntheticDelay::STATIC);
- } else if (token == "oneshot") {
- delay->SetMode(TraceEventSyntheticDelay::ONE_SHOT);
- } else if (token == "alternating") {
- delay->SetMode(TraceEventSyntheticDelay::ALTERNATING);
- }
- }
- }
-}
-
-const unsigned char* TraceLog::GetCategoryGroupEnabledInternal(
- const char* category_group) {
- DCHECK(!strchr(category_group, '"')) <<
- "Category groups may not contain double quote";
- // The g_category_groups is append only, avoid using a lock for the fast path.
- size_t current_category_index = base::subtle::Acquire_Load(&g_category_index);
-
- // Search for pre-existing category group.
- for (size_t i = 0; i < current_category_index; ++i) {
- if (strcmp(g_category_groups[i], category_group) == 0) {
- return &g_category_group_enabled[i];
- }
- }
-
- unsigned char* category_group_enabled = NULL;
- // This is the slow path: the lock is not held in the case above, so more
- // than one thread could have reached here trying to add the same category.
- // Only hold to lock when actually appending a new category, and
- // check the categories groups again.
- AutoLock lock(lock_);
- size_t category_index = base::subtle::Acquire_Load(&g_category_index);
- for (size_t i = 0; i < category_index; ++i) {
- if (strcmp(g_category_groups[i], category_group) == 0) {
- return &g_category_group_enabled[i];
- }
- }
-
- // Create a new category group.
- DCHECK(category_index < MAX_CATEGORY_GROUPS) <<
- "must increase MAX_CATEGORY_GROUPS";
- if (category_index < MAX_CATEGORY_GROUPS) {
- // 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);
- g_category_groups[category_index] = new_group;
- DCHECK(!g_category_group_enabled[category_index]);
- // Note that if both included and excluded patterns in the
- // TraceConfig are empty, we exclude nothing,
- // thereby enabling this category group.
- UpdateCategoryGroupEnabledFlag(category_index);
- category_group_enabled = &g_category_group_enabled[category_index];
- // Update the max index now.
- base::subtle::Release_Store(&g_category_index, category_index + 1);
- } else {
- category_group_enabled =
- &g_category_group_enabled[g_category_categories_exhausted];
- }
- return category_group_enabled;
-}
-
-void TraceLog::GetKnownCategoryGroups(
- std::vector<std::string>* category_groups) {
- AutoLock lock(lock_);
- category_groups->push_back(
- g_category_groups[g_category_trace_event_overhead]);
- size_t category_index = base::subtle::NoBarrier_Load(&g_category_index);
- for (size_t i = g_num_builtin_categories; i < category_index; i++)
- category_groups->push_back(g_category_groups[i]);
-}
-
-void TraceLog::SetEnabled(const TraceConfig& trace_config, Mode mode) {
- std::vector<EnabledStateObserver*> observer_list;
- {
- AutoLock lock(lock_);
-
- // Can't enable tracing when Flush() is in progress.
- DCHECK(!flush_task_runner_);
-
- InternalTraceOptions new_options =
- GetInternalOptionsFromTraceConfig(trace_config);
-
- InternalTraceOptions old_options = trace_options();
-
- if (IsEnabled()) {
- if (new_options != old_options) {
- DLOG(ERROR) << "Attempting to re-enable tracing with a different "
- << "set of options.";
- }
-
- if (mode != mode_) {
- DLOG(ERROR) << "Attempting to re-enable tracing with a different mode.";
- }
-
- trace_config_.Merge(trace_config);
- UpdateCategoryGroupEnabledFlags();
- return;
- }
-
- if (dispatching_to_observer_list_) {
- DLOG(ERROR) <<
- "Cannot manipulate TraceLog::Enabled state from an observer.";
- return;
- }
-
- mode_ = mode;
-
- if (new_options != old_options) {
- subtle::NoBarrier_Store(&trace_options_, new_options);
- UseNextTraceBuffer();
- }
-
- num_traces_recorded_++;
-
- trace_config_ = TraceConfig(trace_config);
- UpdateCategoryGroupEnabledFlags();
- UpdateSyntheticDelaysFromTraceConfig();
-
- if (new_options & kInternalEnableSampling) {
- sampling_thread_.reset(new TraceSamplingThread);
- sampling_thread_->RegisterSampleBucket(
- &g_trace_state[0],
- "bucket0",
- Bind(&TraceSamplingThread::DefaultSamplingCallback));
- sampling_thread_->RegisterSampleBucket(
- &g_trace_state[1],
- "bucket1",
- Bind(&TraceSamplingThread::DefaultSamplingCallback));
- sampling_thread_->RegisterSampleBucket(
- &g_trace_state[2],
- "bucket2",
- Bind(&TraceSamplingThread::DefaultSamplingCallback));
- 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;
- }
-}
-
-void TraceLog::SetArgumentFilterPredicate(
- const TraceEvent::ArgumentFilterPredicate& argument_filter_predicate) {
- AutoLock lock(lock_);
- DCHECK(!argument_filter_predicate.is_null());
- DCHECK(argument_filter_predicate_.is_null());
- argument_filter_predicate_ = argument_filter_predicate;
-}
-
-TraceLog::InternalTraceOptions TraceLog::GetInternalOptionsFromTraceConfig(
- const TraceConfig& config) {
- InternalTraceOptions ret =
- config.IsSamplingEnabled() ? kInternalEnableSampling : kInternalNone;
- if (config.IsArgumentFilterEnabled())
- ret |= kInternalEnableArgumentFilter;
- switch (config.GetTraceRecordMode()) {
- case RECORD_UNTIL_FULL:
- return ret | kInternalRecordUntilFull;
- case RECORD_CONTINUOUSLY:
- return ret | kInternalRecordContinuously;
- case ECHO_TO_CONSOLE:
- return ret | kInternalEchoToConsole;
- case RECORD_AS_MUCH_AS_POSSIBLE:
- return ret | kInternalRecordAsMuchAsPossible;
- }
- NOTREACHED();
- return kInternalNone;
-}
-
-TraceConfig TraceLog::GetCurrentTraceConfig() const {
- AutoLock lock(lock_);
- return trace_config_;
-}
-
-void TraceLog::SetDisabled() {
- AutoLock lock(lock_);
- SetDisabledWhileLocked();
-}
-
-void TraceLog::SetDisabledWhileLocked() {
- lock_.AssertAcquired();
-
- if (!IsEnabled())
- return;
-
- if (dispatching_to_observer_list_) {
- DLOG(ERROR)
- << "Cannot manipulate TraceLog::Enabled state from an observer.";
- return;
- }
-
- mode_ = DISABLED;
-
- 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();
- }
-
- trace_config_.Clear();
- subtle::NoBarrier_Store(&watch_category_, 0);
- watch_event_name_ = "";
- UpdateCategoryGroupEnabledFlags();
- AddMetadataEventsWhileLocked();
-
- dispatching_to_observer_list_ = true;
- std::vector<EnabledStateObserver*> observer_list =
- enabled_state_observer_list_;
-
- {
- // Dispatch to observers outside the lock in case the observer triggers a
- // trace event.
- AutoUnlock unlock(lock_);
- for (size_t i = 0; i < observer_list.size(); ++i)
- observer_list[i]->OnTraceLogDisabled();
- }
- dispatching_to_observer_list_ = false;
-}
-
-int TraceLog::GetNumTracesRecorded() {
- AutoLock lock(lock_);
- if (!IsEnabled())
- 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<EnabledStateObserver*>::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<EnabledStateObserver*>::const_iterator it =
- std::find(enabled_state_observer_list_.begin(),
- enabled_state_observer_list_.end(),
- listener);
- return it != enabled_state_observer_list_.end();
-}
-
-TraceLogStatus TraceLog::GetStatus() const {
- AutoLock lock(lock_);
- TraceLogStatus result;
- result.event_capacity = logged_events_->Capacity();
- result.event_count = logged_events_->Size();
- return result;
-}
-
-bool TraceLog::BufferIsFull() const {
- AutoLock lock(lock_);
- return logged_events_->IsFull();
-}
-
-TraceBuffer* TraceLog::CreateTraceBuffer() {
- InternalTraceOptions options = trace_options();
- if (options & kInternalRecordContinuously)
- return new TraceBufferRingBuffer(kTraceEventRingBufferChunks);
- else if ((options & kInternalEnableSampling) && mode_ == MONITORING_MODE)
- return new TraceBufferRingBuffer(kMonitorTraceEventBufferChunks);
- else if (options & kInternalEchoToConsole)
- return new TraceBufferRingBuffer(kEchoToConsoleTraceEventBufferChunks);
- else if (options & kInternalRecordAsMuchAsPossible)
- return CreateTraceBufferVectorOfSize(kTraceEventVectorBigBufferChunks);
- return CreateTraceBufferVectorOfSize(kTraceEventVectorBufferChunks);
-}
-
-TraceBuffer* TraceLog::CreateTraceBufferVectorOfSize(size_t max_chunks) {
- return new TraceBufferVector(max_chunks);
-}
-
-TraceEvent* TraceLog::AddEventToThreadSharedChunkWhileLocked(
- TraceEventHandle* handle, bool check_buffer_is_full) {
- lock_.AssertAcquired();
-
- if (thread_shared_chunk_ && thread_shared_chunk_->IsFull()) {
- logged_events_->ReturnChunk(thread_shared_chunk_index_,
- thread_shared_chunk_.Pass());
- }
-
- if (!thread_shared_chunk_) {
- thread_shared_chunk_ = logged_events_->GetChunk(
- &thread_shared_chunk_index_);
- if (check_buffer_is_full)
- CheckIfBufferIsFullWhileLocked();
- }
- if (!thread_shared_chunk_)
- return NULL;
-
- size_t event_index;
- TraceEvent* trace_event = thread_shared_chunk_->AddTraceEvent(&event_index);
- if (trace_event && handle) {
- MakeHandle(thread_shared_chunk_->seq(), thread_shared_chunk_index_,
- event_index, handle);
- }
- return trace_event;
-}
-
-void TraceLog::CheckIfBufferIsFullWhileLocked() {
- lock_.AssertAcquired();
- if (logged_events_->IsFull()) {
- if (buffer_limit_reached_timestamp_.is_null()) {
- buffer_limit_reached_timestamp_ = OffsetNow();
- }
- SetDisabledWhileLocked();
- }
-}
-
-void TraceLog::SetEventCallbackEnabled(const TraceConfig& trace_config,
- EventCallback cb) {
- AutoLock lock(lock_);
- subtle::NoBarrier_Store(&event_callback_,
- reinterpret_cast<subtle::AtomicWord>(cb));
- event_callback_trace_config_ = trace_config;
- UpdateCategoryGroupEnabledFlags();
-};
-
-void TraceLog::SetEventCallbackDisabled() {
- AutoLock lock(lock_);
- subtle::NoBarrier_Store(&event_callback_, 0);
- UpdateCategoryGroupEnabledFlags();
-}
-
-// Flush() works as the following:
-// 1. Flush() is called in thread A whose task runner is saved in
-// flush_task_runner_;
-// 2. If thread_message_loops_ is not empty, thread A posts task to each message
-// loop to flush the thread local buffers; otherwise finish the flush;
-// 3. FlushCurrentThread() deletes the thread local event buffer:
-// - The last batch of events of the thread are flushed into the main buffer;
-// - The message loop will be removed from thread_message_loops_;
-// If this is the last message loop, finish the flush;
-// 4. If any thread hasn't finish its flush in time, finish the flush.
-void TraceLog::Flush(const TraceLog::OutputCallback& cb,
- bool use_worker_thread) {
- use_worker_thread_ = use_worker_thread;
- if (IsEnabled()) {
- // Can't flush when tracing is enabled because otherwise PostTask would
- // - generate more trace events;
- // - deschedule the calling thread on some platforms causing inaccurate
- // timing of the trace events.
- scoped_refptr<RefCountedString> empty_result = new RefCountedString;
- if (!cb.is_null())
- cb.Run(empty_result, false);
- LOG(WARNING) << "Ignored TraceLog::Flush called when tracing is enabled";
- return;
- }
-
- int generation = this->generation();
- // Copy of thread_message_loops_ to be used without locking.
- std::vector<scoped_refptr<SingleThreadTaskRunner> >
- thread_message_loop_task_runners;
- {
- AutoLock lock(lock_);
- DCHECK(!flush_task_runner_);
- flush_task_runner_ = ThreadTaskRunnerHandle::IsSet()
- ? ThreadTaskRunnerHandle::Get()
- : nullptr;
- DCHECK_IMPLIES(thread_message_loops_.size(), flush_task_runner_);
- flush_output_callback_ = cb;
-
- if (thread_shared_chunk_) {
- logged_events_->ReturnChunk(thread_shared_chunk_index_,
- thread_shared_chunk_.Pass());
- }
-
- if (thread_message_loops_.size()) {
- for (hash_set<MessageLoop*>::const_iterator it =
- thread_message_loops_.begin();
- it != thread_message_loops_.end(); ++it) {
- thread_message_loop_task_runners.push_back((*it)->task_runner());
- }
- }
- }
-
- if (thread_message_loop_task_runners.size()) {
- for (size_t i = 0; i < thread_message_loop_task_runners.size(); ++i) {
- thread_message_loop_task_runners[i]->PostTask(
- FROM_HERE,
- Bind(&TraceLog::FlushCurrentThread, Unretained(this), generation));
- }
- flush_task_runner_->PostDelayedTask(
- FROM_HERE,
- Bind(&TraceLog::OnFlushTimeout, Unretained(this), generation),
- TimeDelta::FromMilliseconds(kThreadFlushTimeoutMs));
- return;
- }
-
- FinishFlush(generation);
-}
-
-// Usually it runs on a different thread.
-void TraceLog::ConvertTraceEventsToTraceFormat(
- scoped_ptr<TraceBuffer> logged_events,
- const OutputCallback& flush_output_callback,
- const TraceEvent::ArgumentFilterPredicate& argument_filter_predicate) {
- if (flush_output_callback.is_null())
- return;
-
- // The callback need to be called at least once even if there is no events
- // to let the caller know the completion of flush.
- bool has_more_events = true;
- do {
- scoped_refptr<RefCountedString> json_events_str_ptr =
- new RefCountedString();
-
- while (json_events_str_ptr->size() < kTraceEventBufferSizeInBytes) {
- const TraceBufferChunk* chunk = logged_events->NextChunk();
- has_more_events = chunk != NULL;
- if (!chunk)
- break;
- for (size_t j = 0; j < chunk->size(); ++j) {
- if (json_events_str_ptr->size())
- json_events_str_ptr->data().append(",\n");
- chunk->GetEventAt(j)->AppendAsJSON(&(json_events_str_ptr->data()),
- argument_filter_predicate);
- }
- }
- flush_output_callback.Run(json_events_str_ptr, has_more_events);
- } while (has_more_events);
-}
-
-void TraceLog::FinishFlush(int generation) {
- scoped_ptr<TraceBuffer> previous_logged_events;
- OutputCallback flush_output_callback;
- TraceEvent::ArgumentFilterPredicate argument_filter_predicate;
-
- if (!CheckGeneration(generation))
- return;
-
- {
- AutoLock lock(lock_);
-
- previous_logged_events.swap(logged_events_);
- UseNextTraceBuffer();
- thread_message_loops_.clear();
-
- flush_task_runner_ = NULL;
- flush_output_callback = flush_output_callback_;
- flush_output_callback_.Reset();
-
- if (trace_options() & kInternalEnableArgumentFilter) {
- CHECK(!argument_filter_predicate_.is_null());
- argument_filter_predicate = argument_filter_predicate_;
- }
- }
-
- if (use_worker_thread_ &&
- WorkerPool::PostTask(
- FROM_HERE, Bind(&TraceLog::ConvertTraceEventsToTraceFormat,
- Passed(&previous_logged_events),
- flush_output_callback, argument_filter_predicate),
- true)) {
- return;
- }
-
- ConvertTraceEventsToTraceFormat(previous_logged_events.Pass(),
- flush_output_callback,
- argument_filter_predicate);
-}
-
-// Run in each thread holding a local event buffer.
-void TraceLog::FlushCurrentThread(int generation) {
- {
- AutoLock lock(lock_);
- if (!CheckGeneration(generation) || !flush_task_runner_) {
- // This is late. The corresponding flush has finished.
- return;
- }
- }
-
- // This will flush the thread local buffer.
- delete thread_local_event_buffer_.Get();
-
- AutoLock lock(lock_);
- if (!CheckGeneration(generation) || !flush_task_runner_ ||
- thread_message_loops_.size())
- return;
-
- flush_task_runner_->PostTask(
- FROM_HERE, Bind(&TraceLog::FinishFlush, Unretained(this), generation));
-}
-
-void TraceLog::OnFlushTimeout(int generation) {
- {
- AutoLock lock(lock_);
- if (!CheckGeneration(generation) || !flush_task_runner_) {
- // Flush has finished before timeout.
- return;
- }
-
- LOG(WARNING) <<
- "The following threads haven't finished flush in time. "
- "If this happens stably for some thread, please call "
- "TraceLog::GetInstance()->SetCurrentThreadBlocksMessageLoop() from "
- "the thread to avoid its trace events from being lost.";
- for (hash_set<MessageLoop*>::const_iterator it =
- thread_message_loops_.begin();
- it != thread_message_loops_.end(); ++it) {
- LOG(WARNING) << "Thread: " << (*it)->thread_name();
- }
- }
- FinishFlush(generation);
-}
-
-void TraceLog::FlushButLeaveBufferIntact(
- const TraceLog::OutputCallback& flush_output_callback) {
- scoped_ptr<TraceBuffer> previous_logged_events;
- TraceEvent::ArgumentFilterPredicate argument_filter_predicate;
- {
- AutoLock lock(lock_);
- AddMetadataEventsWhileLocked();
- if (thread_shared_chunk_) {
- // Return the chunk to the main buffer to flush the sampling data.
- logged_events_->ReturnChunk(thread_shared_chunk_index_,
- thread_shared_chunk_.Pass());
- }
- previous_logged_events = logged_events_->CloneForIteration().Pass();
-
- if (trace_options() & kInternalEnableArgumentFilter) {
- CHECK(!argument_filter_predicate_.is_null());
- argument_filter_predicate = argument_filter_predicate_;
- }
- } // release lock
-
- ConvertTraceEventsToTraceFormat(previous_logged_events.Pass(),
- flush_output_callback,
- argument_filter_predicate);
-}
-
-void TraceLog::UseNextTraceBuffer() {
- logged_events_.reset(CreateTraceBuffer());
- subtle::NoBarrier_AtomicIncrement(&generation_, 1);
- thread_shared_chunk_.reset();
- thread_shared_chunk_index_ = 0;
-}
-
-TraceEventHandle 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,
- const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
- unsigned char flags) {
- int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
- base::TraceTicks now = base::TraceTicks::Now();
- return AddTraceEventWithThreadIdAndTimestamp(phase, category_group_enabled,
- name, id, thread_id, now,
- num_args, arg_names,
- arg_types, arg_values,
- convertable_values, flags);
-}
-
-TraceEventHandle TraceLog::AddTraceEventWithThreadIdAndTimestamp(
- char phase,
- const unsigned char* category_group_enabled,
- const char* name,
- unsigned long long id,
- int thread_id,
- const TraceTicks& timestamp,
- int num_args,
- const char** arg_names,
- const unsigned char* arg_types,
- const unsigned long long* arg_values,
- const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
- unsigned char flags) {
- TraceEventHandle handle = { 0, 0, 0 };
- if (!*category_group_enabled)
- return handle;
-
- // Avoid re-entrance of AddTraceEvent. This may happen in GPU process when
- // ECHO_TO_CONSOLE is enabled: AddTraceEvent -> LOG(ERROR) ->
- // GpuProcessLogMessageHandler -> PostPendingTask -> TRACE_EVENT ...
- if (thread_is_in_trace_event_.Get())
- return handle;
-
- AutoThreadLocalBoolean thread_is_in_trace_event(&thread_is_in_trace_event_);
-
- DCHECK(name);
- DCHECK(!timestamp.is_null());
-
- if (flags & TRACE_EVENT_FLAG_MANGLE_ID)
- id = MangleEventId(id);
-
- TraceTicks offset_event_timestamp = OffsetTimestamp(timestamp);
- TraceTicks now = flags & TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP ?
- OffsetNow() : offset_event_timestamp;
- ThreadTicks thread_now = ThreadNow();
-
- ThreadLocalEventBuffer* thread_local_event_buffer = NULL;
- // A ThreadLocalEventBuffer needs the message loop
- // - to know when the thread exits;
- // - to handle the final flush.
- // For a thread without a message loop or the message loop may be blocked, the
- // trace events will be added into the main buffer directly.
- if (!thread_blocks_message_loop_.Get() && MessageLoop::current()) {
- thread_local_event_buffer = thread_local_event_buffer_.Get();
- if (thread_local_event_buffer &&
- !CheckGeneration(thread_local_event_buffer->generation())) {
- delete thread_local_event_buffer;
- thread_local_event_buffer = NULL;
- }
- if (!thread_local_event_buffer) {
- thread_local_event_buffer = new ThreadLocalEventBuffer(this);
- thread_local_event_buffer_.Set(thread_local_event_buffer);
- }
- }
-
- // 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<int>(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 thread_info_lock(thread_info_lock_);
-
- hash_map<int, std::string>::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<StringPiece> 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) {
- if (existing_names.size())
- existing_name->second.push_back(',');
- existing_name->second.append(new_name);
- }
- }
- }
- }
-
-#if defined(OS_WIN)
- // This is done sooner rather than later, to avoid creating the event and
- // acquiring the lock, which is not needed for ETW as it's already threadsafe.
- if (*category_group_enabled & ENABLED_FOR_ETW_EXPORT)
- TraceEventETWExport::AddEvent(phase, category_group_enabled, name, id,
- num_args, arg_names, arg_types, arg_values,
- convertable_values);
-#endif // OS_WIN
-
- std::string console_message;
- if (*category_group_enabled &
- (ENABLED_FOR_RECORDING | ENABLED_FOR_MONITORING)) {
- OptionalAutoLock lock(&lock_);
-
- TraceEvent* trace_event = NULL;
- if (thread_local_event_buffer) {
- trace_event = thread_local_event_buffer->AddTraceEvent(&handle);
- } else {
- lock.EnsureAcquired();
- trace_event = AddEventToThreadSharedChunkWhileLocked(&handle, true);
- }
-
- if (trace_event) {
- trace_event->Initialize(thread_id, offset_event_timestamp, thread_now,
- phase, category_group_enabled, name, id,
- num_args, arg_names, arg_types, arg_values,
- convertable_values, flags);
-
-#if defined(OS_ANDROID)
- trace_event->SendToATrace();
-#endif
- }
-
- if (trace_options() & kInternalEchoToConsole) {
- console_message = EventToConsoleMessage(
- phase == TRACE_EVENT_PHASE_COMPLETE ? TRACE_EVENT_PHASE_BEGIN : phase,
- timestamp, trace_event);
- }
- }
-
- if (console_message.size())
- LOG(ERROR) << console_message;
-
- if (reinterpret_cast<const unsigned char*>(subtle::NoBarrier_Load(
- &watch_category_)) == category_group_enabled) {
- bool event_name_matches;
- WatchEventCallback watch_event_callback_copy;
- {
- AutoLock lock(lock_);
- event_name_matches = watch_event_name_ == name;
- watch_event_callback_copy = watch_event_callback_;
- }
- if (event_name_matches) {
- if (!watch_event_callback_copy.is_null())
- watch_event_callback_copy.Run();
- }
- }
-
- if (*category_group_enabled & ENABLED_FOR_EVENT_CALLBACK) {
- EventCallback event_callback = reinterpret_cast<EventCallback>(
- subtle::NoBarrier_Load(&event_callback_));
- if (event_callback) {
- event_callback(offset_event_timestamp,
- phase == TRACE_EVENT_PHASE_COMPLETE ?
- TRACE_EVENT_PHASE_BEGIN : phase,
- category_group_enabled, name, id,
- num_args, arg_names, arg_types, arg_values,
- flags);
- }
- }
-
- if (thread_local_event_buffer)
- thread_local_event_buffer->ReportOverhead(now, thread_now);
-
- return handle;
-}
-
-// May be called when a COMPELETE event ends and the unfinished event has been
-// recycled (phase == TRACE_EVENT_PHASE_END and trace_event == NULL).
-std::string TraceLog::EventToConsoleMessage(unsigned char phase,
- const TraceTicks& timestamp,
- TraceEvent* trace_event) {
- AutoLock thread_info_lock(thread_info_lock_);
-
- // The caller should translate TRACE_EVENT_PHASE_COMPLETE to
- // TRACE_EVENT_PHASE_BEGIN or TRACE_EVENT_END.
- DCHECK(phase != TRACE_EVENT_PHASE_COMPLETE);
-
- TimeDelta duration;
- int thread_id = trace_event ?
- trace_event->thread_id() : PlatformThread::CurrentId();
- 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 << "| ";
-
- if (trace_event)
- trace_event->AppendPrettyPrinted(&log);
- if (phase == TRACE_EVENT_PHASE_END)
- log << base::StringPrintf(" (%.3f ms)", duration.InMillisecondsF());
-
- log << "\x1b[0;m";
-
- if (phase == TRACE_EVENT_PHASE_BEGIN)
- thread_event_start_times_[thread_id].push(timestamp);
-
- return log.str();
-}
-
-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::UpdateTraceEventDuration(
- const unsigned char* category_group_enabled,
- const char* name,
- TraceEventHandle handle) {
- // Avoid re-entrance of AddTraceEvent. This may happen in GPU process when
- // ECHO_TO_CONSOLE is enabled: AddTraceEvent -> LOG(ERROR) ->
- // GpuProcessLogMessageHandler -> PostPendingTask -> TRACE_EVENT ...
- if (thread_is_in_trace_event_.Get())
- return;
-
- AutoThreadLocalBoolean thread_is_in_trace_event(&thread_is_in_trace_event_);
-
- ThreadTicks thread_now = ThreadNow();
- TraceTicks now = OffsetNow();
-
- std::string console_message;
- if (*category_group_enabled & ENABLED_FOR_RECORDING) {
- OptionalAutoLock lock(&lock_);
-
- TraceEvent* trace_event = GetEventByHandleInternal(handle, &lock);
- if (trace_event) {
- DCHECK(trace_event->phase() == TRACE_EVENT_PHASE_COMPLETE);
- trace_event->UpdateDuration(now, thread_now);
-#if defined(OS_ANDROID)
- trace_event->SendToATrace();
-#endif
- }
-
- if (trace_options() & kInternalEchoToConsole) {
- console_message = EventToConsoleMessage(TRACE_EVENT_PHASE_END,
- now, trace_event);
- }
- }
-
- if (console_message.size())
- LOG(ERROR) << console_message;
-
- if (*category_group_enabled & ENABLED_FOR_EVENT_CALLBACK) {
- EventCallback event_callback = reinterpret_cast<EventCallback>(
- subtle::NoBarrier_Load(&event_callback_));
- if (event_callback) {
- event_callback(now, TRACE_EVENT_PHASE_END, category_group_enabled, name,
- trace_event_internal::kNoEventId, 0, NULL, NULL, NULL,
- TRACE_EVENT_FLAG_NONE);
- }
- }
-}
-
-void TraceLog::SetWatchEvent(const std::string& category_name,
- const std::string& event_name,
- const WatchEventCallback& callback) {
- const unsigned char* category = GetCategoryGroupEnabled(
- category_name.c_str());
- AutoLock lock(lock_);
- subtle::NoBarrier_Store(&watch_category_,
- reinterpret_cast<subtle::AtomicWord>(category));
- watch_event_name_ = event_name;
- watch_event_callback_ = callback;
-}
-
-void TraceLog::CancelWatchEvent() {
- AutoLock lock(lock_);
- subtle::NoBarrier_Store(&watch_category_, 0);
- watch_event_name_ = "";
- watch_event_callback_.Reset();
-}
-
-uint64 TraceLog::MangleEventId(uint64 id) {
- return id ^ process_id_hash_;
-}
-
-void TraceLog::AddMetadataEventsWhileLocked() {
- lock_.AssertAcquired();
-
-#if !defined(OS_NACL) // NaCl shouldn't expose the process id.
- InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
- 0,
- "num_cpus", "number",
- base::SysInfo::NumberOfProcessors());
-#endif
-
-
- int current_thread_id = static_cast<int>(base::PlatformThread::CurrentId());
- if (process_sort_index_ != 0) {
- InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
- current_thread_id,
- "process_sort_index", "sort_index",
- process_sort_index_);
- }
-
- if (process_name_.size()) {
- InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
- current_thread_id,
- "process_name", "name",
- process_name_);
- }
-
- if (process_labels_.size() > 0) {
- std::vector<std::string> labels;
- for(base::hash_map<int, std::string>::iterator it = process_labels_.begin();
- it != process_labels_.end();
- it++) {
- labels.push_back(it->second);
- }
- InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
- current_thread_id,
- "process_labels", "labels",
- JoinString(labels, ','));
- }
-
- // Thread sort indices.
- for(hash_map<int, int>::iterator it = thread_sort_indices_.begin();
- it != thread_sort_indices_.end();
- it++) {
- if (it->second == 0)
- continue;
- InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
- it->first,
- "thread_sort_index", "sort_index",
- it->second);
- }
-
- // Thread names.
- AutoLock thread_info_lock(thread_info_lock_);
- for(hash_map<int, std::string>::iterator it = thread_names_.begin();
- it != thread_names_.end();
- it++) {
- if (it->second.empty())
- continue;
- InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
- it->first,
- "thread_name", "name",
- it->second);
- }
-
- // If buffer is full, add a metadata record to report this.
- if (!buffer_limit_reached_timestamp_.is_null()) {
- InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
- current_thread_id,
- "trace_buffer_overflowed",
- "overflowed_at_ts",
- buffer_limit_reached_timestamp_);
- }
-}
-
-void TraceLog::WaitSamplingEventForTesting() {
- if (!sampling_thread_)
- return;
- sampling_thread_->WaitSamplingEventForTesting();
-}
-
-void TraceLog::DeleteForTesting() {
- DeleteTraceLogForTesting::Delete();
-}
-
-TraceEvent* TraceLog::GetEventByHandle(TraceEventHandle handle) {
- return GetEventByHandleInternal(handle, NULL);
-}
-
-TraceEvent* TraceLog::GetEventByHandleInternal(TraceEventHandle handle,
- OptionalAutoLock* lock) {
- if (!handle.chunk_seq)
- return NULL;
-
- if (thread_local_event_buffer_.Get()) {
- TraceEvent* trace_event =
- thread_local_event_buffer_.Get()->GetEventByHandle(handle);
- if (trace_event)
- return trace_event;
- }
-
- // The event has been out-of-control of the thread local buffer.
- // Try to get the event from the main buffer with a lock.
- if (lock)
- lock->EnsureAcquired();
-
- if (thread_shared_chunk_ &&
- handle.chunk_index == thread_shared_chunk_index_) {
- return handle.chunk_seq == thread_shared_chunk_->seq() ?
- thread_shared_chunk_->GetEventAt(handle.event_index) : NULL;
- }
-
- return logged_events_->GetEventByHandle(handle);
-}
-
-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<unsigned long long>(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<int, std::string>::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<int>(thread_id)] = sort_index;
-}
-
-void TraceLog::SetTimeOffset(TimeDelta offset) {
- time_offset_ = offset;
-}
-
-size_t TraceLog::GetObserverCountForTest() const {
- return enabled_state_observer_list_.size();
-}
-
-void TraceLog::SetCurrentThreadBlocksMessageLoop() {
- thread_blocks_message_loop_.Set(true);
- if (thread_local_event_buffer_.Get()) {
- // This will flush the thread local buffer.
- delete thread_local_event_buffer_.Get();
- }
-}
-
-void ConvertableToTraceFormat::EstimateTraceMemoryOverhead(
- TraceEventMemoryOverhead* overhead) {
- overhead->Add("ConvertableToTraceFormat(Unknown)", sizeof(*this));
-}
-
} // namespace trace_event
} // namespace base
-
-namespace trace_event_internal {
-
-ScopedTraceBinaryEfficient::ScopedTraceBinaryEfficient(
- const char* category_group, const char* name) {
- // The single atom works because for now the category_group can only be "gpu".
- DCHECK_EQ(strcmp(category_group, "gpu"), 0);
- static TRACE_EVENT_API_ATOMIC_WORD atomic = 0;
- INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO_CUSTOM_VARIABLES(
- category_group, atomic, category_group_enabled_);
- name_ = name;
- if (*category_group_enabled_) {
- event_handle_ =
- TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
- TRACE_EVENT_PHASE_COMPLETE, category_group_enabled_, name,
- trace_event_internal::kNoEventId,
- static_cast<int>(base::PlatformThread::CurrentId()),
- base::TraceTicks::Now(), 0, NULL, NULL, NULL, NULL,
- TRACE_EVENT_FLAG_NONE);
- }
-}
-
-ScopedTraceBinaryEfficient::~ScopedTraceBinaryEfficient() {
- if (*category_group_enabled_) {
- TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(category_group_enabled_,
- name_, event_handle_);
- }
-}
-
-} // namespace trace_event_internal
diff --git a/base/trace_event/trace_event_impl.h b/base/trace_event/trace_event_impl.h
index 2b0de29311..36461e2b52 100644
--- a/base/trace_event/trace_event_impl.h
+++ b/base/trace_event/trace_event_impl.h
@@ -6,6 +6,8 @@
#ifndef BASE_TRACE_EVENT_TRACE_EVENT_IMPL_H_
#define BASE_TRACE_EVENT_TRACE_EVENT_IMPL_H_
+#include <stdint.h>
+
#include <stack>
#include <string>
#include <vector>
@@ -14,9 +16,8 @@
#include "base/base_export.h"
#include "base/callback.h"
#include "base/containers/hash_tables.h"
-#include "base/gtest_prod_util.h"
+#include "base/macros.h"
#include "base/memory/ref_counted_memory.h"
-#include "base/memory/scoped_vector.h"
#include "base/observer_list.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string_util.h"
@@ -24,30 +25,8 @@
#include "base/synchronization/lock.h"
#include "base/threading/thread.h"
#include "base/threading/thread_local.h"
-#include "base/trace_event/memory_dump_provider.h"
-#include "base/trace_event/trace_config.h"
#include "base/trace_event/trace_event_memory_overhead.h"
-
-// Older style trace macros with explicit id and extra data
-// Only these macros result in publishing data to ETW as currently implemented.
-// TODO(georgesak): Update/replace these with new ETW macros.
-#define TRACE_EVENT_BEGIN_ETW(name, id, extra) \
- base::trace_event::TraceLog::AddTraceEventEtw( \
- TRACE_EVENT_PHASE_BEGIN, \
- name, reinterpret_cast<const void*>(id), extra)
-
-#define TRACE_EVENT_END_ETW(name, id, extra) \
- base::trace_event::TraceLog::AddTraceEventEtw( \
- TRACE_EVENT_PHASE_END, \
- name, reinterpret_cast<const void*>(id), extra)
-
-#define TRACE_EVENT_INSTANT_ETW(name, id, extra) \
- base::trace_event::TraceLog::AddTraceEventEtw( \
- TRACE_EVENT_PHASE_INSTANT, \
- name, reinterpret_cast<const void*>(id), extra)
-
-template <typename Type>
-struct DefaultSingletonTraits;
+#include "build/build_config.h"
namespace base {
@@ -56,6 +35,13 @@ class MessageLoop;
namespace trace_event {
+typedef base::Callback<bool(const char* arg_name)> ArgumentNameFilterPredicate;
+
+typedef base::Callback<bool(const char* category_group_name,
+ const char* event_name,
+ ArgumentNameFilterPredicate*)>
+ ArgumentFilterPredicate;
+
// For any argument of type TRACE_VALUE_TYPE_CONVERTABLE the provided
// class must implement this interface.
class BASE_EXPORT ConvertableToTraceFormat
@@ -82,14 +68,17 @@ class BASE_EXPORT ConvertableToTraceFormat
friend class RefCounted<ConvertableToTraceFormat>;
};
+const int kTraceMaxNumArgs = 2;
+
struct TraceEventHandle {
- uint32 chunk_seq;
- uint16 chunk_index;
- uint16 event_index;
+ uint32_t chunk_seq;
+ // These numbers of bits must be kept consistent with
+ // TraceBufferChunk::kMaxTrunkIndex and
+ // TraceBufferChunk::kTraceBufferChunkSize (in trace_buffer.h).
+ unsigned chunk_index : 26;
+ unsigned event_index : 6;
};
-const int kTraceMaxNumArgs = 2;
-
class BASE_EXPORT TraceEvent {
public:
union TraceValue {
@@ -110,28 +99,27 @@ class BASE_EXPORT TraceEvent {
void Initialize(
int thread_id,
- TraceTicks timestamp,
+ TimeTicks timestamp,
ThreadTicks thread_timestamp,
char phase,
const unsigned char* category_group_enabled,
const char* name,
unsigned long long id,
+ unsigned long long bind_id,
int num_args,
const char** arg_names,
const unsigned char* arg_types,
const unsigned long long* arg_values,
const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
- unsigned char flags);
+ unsigned int flags);
void Reset();
- void UpdateDuration(const TraceTicks& now, const ThreadTicks& thread_now);
+ void UpdateDuration(const TimeTicks& now, const ThreadTicks& thread_now);
- void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead*);
+ void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead);
// Serialize event data to JSON
- typedef base::Callback<bool(const char* category_group_name,
- const char* event_name)> ArgumentFilterPredicate;
void AppendAsJSON(
std::string* out,
const ArgumentFilterPredicate& argument_filter_predicate) const;
@@ -141,14 +129,14 @@ class BASE_EXPORT TraceEvent {
TraceValue value,
std::string* out);
- TraceTicks timestamp() const { return timestamp_; }
+ TimeTicks timestamp() const { return timestamp_; }
ThreadTicks thread_timestamp() const { return thread_timestamp_; }
char phase() const { return phase_; }
int thread_id() const { return thread_id_; }
TimeDelta duration() const { return duration_; }
TimeDelta thread_duration() const { return thread_duration_; }
unsigned long long id() const { return id_; }
- unsigned char flags() const { return flags_; }
+ unsigned int flags() const { return flags_; }
// Exposed for unittesting:
@@ -168,538 +156,33 @@ class BASE_EXPORT TraceEvent {
private:
// Note: these are ordered by size (largest first) for optimal packing.
- TraceTicks timestamp_;
+ TimeTicks timestamp_;
ThreadTicks thread_timestamp_;
TimeDelta duration_;
TimeDelta thread_duration_;
// id_ can be used to store phase-specific data.
unsigned long long id_;
- scoped_ptr<TraceEventMemoryOverhead> cached_memory_overhead_estimate_;
TraceValue arg_values_[kTraceMaxNumArgs];
const char* arg_names_[kTraceMaxNumArgs];
scoped_refptr<ConvertableToTraceFormat> convertable_values_[kTraceMaxNumArgs];
const unsigned char* category_group_enabled_;
const char* name_;
scoped_refptr<base::RefCountedString> parameter_copy_storage_;
- int thread_id_;
- char phase_;
- unsigned char flags_;
+ // Depending on TRACE_EVENT_FLAG_HAS_PROCESS_ID the event will have either:
+ // tid: thread_id_, pid: current_process_id (default case).
+ // tid: -1, pid: process_id_ (when flags_ & TRACE_EVENT_FLAG_HAS_PROCESS_ID).
+ union {
+ int thread_id_;
+ int process_id_;
+ };
+ unsigned int flags_;
+ unsigned long long bind_id_;
unsigned char arg_types_[kTraceMaxNumArgs];
+ char phase_;
DISALLOW_COPY_AND_ASSIGN(TraceEvent);
};
-// TraceBufferChunk is the basic unit of TraceBuffer.
-class BASE_EXPORT TraceBufferChunk {
- public:
- explicit TraceBufferChunk(uint32 seq);
- ~TraceBufferChunk();
-
- void Reset(uint32 new_seq);
- TraceEvent* AddTraceEvent(size_t* event_index);
- bool IsFull() const { return next_free_ == kTraceBufferChunkSize; }
-
- uint32 seq() const { return seq_; }
- size_t capacity() const { return kTraceBufferChunkSize; }
- size_t size() const { return next_free_; }
-
- TraceEvent* GetEventAt(size_t index) {
- DCHECK(index < size());
- return &chunk_[index];
- }
- const TraceEvent* GetEventAt(size_t index) const {
- DCHECK(index < size());
- return &chunk_[index];
- }
-
- scoped_ptr<TraceBufferChunk> Clone() const;
-
- void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead);
-
- static const size_t kTraceBufferChunkSize = 64;
-
- private:
- size_t next_free_;
- scoped_ptr<TraceEventMemoryOverhead> cached_overhead_estimate_when_full_;
- TraceEvent chunk_[kTraceBufferChunkSize];
- uint32 seq_;
-};
-
-// TraceBuffer holds the events as they are collected.
-class BASE_EXPORT TraceBuffer {
- public:
- virtual ~TraceBuffer() {}
-
- virtual scoped_ptr<TraceBufferChunk> GetChunk(size_t *index) = 0;
- virtual void ReturnChunk(size_t index,
- scoped_ptr<TraceBufferChunk> chunk) = 0;
-
- virtual bool IsFull() const = 0;
- virtual size_t Size() const = 0;
- virtual size_t Capacity() const = 0;
- virtual TraceEvent* GetEventByHandle(TraceEventHandle handle) = 0;
-
- // For iteration. Each TraceBuffer can only be iterated once.
- virtual const TraceBufferChunk* NextChunk() = 0;
-
- virtual scoped_ptr<TraceBuffer> CloneForIteration() const = 0;
-
- // Computes an estimate of the size of the buffer, including all the retained
- // objects.
- virtual void EstimateTraceMemoryOverhead(
- TraceEventMemoryOverhead* overhead) = 0;
-};
-
-// TraceResultBuffer collects and converts trace fragments returned by TraceLog
-// to JSON output.
-class BASE_EXPORT TraceResultBuffer {
- public:
- typedef base::Callback<void(const std::string&)> 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 TraceSamplingThread;
-
-struct BASE_EXPORT TraceLogStatus {
- TraceLogStatus();
- ~TraceLogStatus();
- size_t event_capacity;
- size_t event_count;
-};
-
-class BASE_EXPORT TraceLog : public MemoryDumpProvider {
- public:
- enum Mode {
- DISABLED = 0,
- RECORDING_MODE,
- MONITORING_MODE,
- };
-
- // 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.
- // These values must be in sync with macro values in TraceEvent.h in Blink.
- enum CategoryGroupEnabledFlags {
- // Category group enabled for the recording mode.
- ENABLED_FOR_RECORDING = 1 << 0,
- // Category group enabled for the monitoring mode.
- ENABLED_FOR_MONITORING = 1 << 1,
- // Category group enabled by SetEventCallbackEnabled().
- ENABLED_FOR_EVENT_CALLBACK = 1 << 2,
- // Category group enabled to export events to ETW.
- ENABLED_FOR_ETW_EXPORT = 1 << 3
- };
-
- static TraceLog* GetInstance();
-
- // 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<std::string>* category_groups);
-
- // Retrieves a copy (for thread-safety) of the current TraceConfig.
- TraceConfig GetCurrentTraceConfig() const;
-
- // Enables normal tracing (recording trace events in the trace buffer).
- // See TraceConfig comments for details on how to control what categories
- // will be traced. If tracing has already been enabled, |category_filter| will
- // be merged into the current category filter.
- void SetEnabled(const TraceConfig& trace_config, Mode mode);
-
- // Disables normal tracing for all categories.
- void SetDisabled();
-
- bool IsEnabled() { return mode_ != DISABLED; }
-
- // 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();
- void AddClockSyncMetadataEvent();
-#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 BASE_EXPORT EnabledStateObserver {
- public:
- virtual ~EnabledStateObserver() = default;
-
- // 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;
-
- TraceLogStatus GetStatus() const;
- bool BufferIsFull() const;
-
- // Computes an estimate of the size of the TraceLog including all the retained
- // objects.
- void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead);
-
- // 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 SetEventCallbackEnabled() that replaces or a call to
- // SetEventCallbackDisabled() that disables the callback.
- // This callback may be invoked on any thread.
- // For TRACE_EVENT_PHASE_COMPLETE events, the client will still receive pairs
- // of TRACE_EVENT_PHASE_BEGIN and TRACE_EVENT_PHASE_END events to keep the
- // interface simple.
- typedef void (*EventCallback)(TraceTicks timestamp,
- 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);
-
- // Enable tracing for EventCallback.
- void SetEventCallbackEnabled(const TraceConfig& trace_config,
- EventCallback cb);
- void SetEventCallbackDisabled();
- void SetArgumentFilterPredicate(
- const TraceEvent::ArgumentFilterPredicate& argument_filter_predicate);
-
- // Flush all collected events to the given output callback. The callback will
- // be called one or more times either synchronously or asynchronously from
- // the current thread with IPC-bite-size chunks. The string format is
- // undefined. Use TraceResultBuffer to convert one or more trace strings to
- // JSON. The callback can be null if the caller doesn't want any data.
- // Due to the implementation of thread-local buffers, flush can't be
- // done when tracing is enabled. If called when tracing is enabled, the
- // callback will be called directly with (empty_string, false) to indicate
- // the end of this unsuccessful flush. Flush does the serialization
- // on the same thread if the caller doesn't set use_worker_thread explicitly.
- typedef base::Callback<void(const scoped_refptr<base::RefCountedString>&,
- bool has_more_events)> OutputCallback;
- void Flush(const OutputCallback& cb, bool use_worker_thread = false);
- void FlushButLeaveBufferIntact(const OutputCallback& flush_output_callback);
-
- // 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.
- TraceEventHandle 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,
- const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
- unsigned char flags);
- TraceEventHandle AddTraceEventWithThreadIdAndTimestamp(
- char phase,
- const unsigned char* category_group_enabled,
- const char* name,
- unsigned long long id,
- int thread_id,
- const TraceTicks& timestamp,
- int num_args,
- const char** arg_names,
- const unsigned char* arg_types,
- const unsigned long long* arg_values,
- const scoped_refptr<ConvertableToTraceFormat>* 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);
-
- void UpdateTraceEventDuration(const unsigned char* category_group_enabled,
- const char* name,
- TraceEventHandle handle);
-
- // For every matching event, the callback will be called.
- typedef base::Callback<void()> WatchEventCallback;
- void SetWatchEvent(const std::string& category_name,
- const std::string& event_name,
- const WatchEventCallback& callback);
- // 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_; }
-
- uint64 MangleEventId(uint64 id);
-
- // Exposed for unittesting:
-
- void WaitSamplingEventForTesting();
-
- // Allows deleting our singleton instance.
- static void DeleteForTesting();
-
- // Allow tests to inspect TraceEvents.
- TraceEvent* GetEventByHandle(TraceEventHandle handle);
-
- 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 TraceTicks time and the time
- // that should be reported.
- void SetTimeOffset(TimeDelta offset);
-
- size_t GetObserverCountForTest() const;
-
- // Call this method if the current thread may block the message loop to
- // prevent the thread from using the thread-local buffer because the thread
- // may not handle the flush request in time causing lost of unflushed events.
- void SetCurrentThreadBlocksMessageLoop();
-
- private:
- typedef unsigned int InternalTraceOptions;
-
- FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture,
- TraceBufferRingBufferGetReturnChunk);
- FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture,
- TraceBufferRingBufferHalfIteration);
- FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture,
- TraceBufferRingBufferFullIteration);
- FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture,
- TraceBufferVectorReportFull);
- FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture,
- ConvertTraceConfigToInternalOptions);
- FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture,
- TraceRecordAsMuchAsPossibleMode);
-
- // This allows constructor and destructor to be private and usable only
- // by the Singleton class.
- friend struct DefaultSingletonTraits<TraceLog>;
-
- // MemoryDumpProvider implementation.
- bool OnMemoryDump(ProcessMemoryDump* pmd) override;
-
- // Enable/disable each category group based on the current mode_,
- // category_filter_, event_callback_ and event_callback_category_filter_.
- // Enable the category group in the enabled mode if category_filter_ matches
- // the category group, or event_callback_ is not null and
- // event_callback_category_filter_ matches the category group.
- void UpdateCategoryGroupEnabledFlags();
- void UpdateCategoryGroupEnabledFlag(size_t category_index);
-
- // Configure synthetic delays based on the values set in the current
- // trace config.
- void UpdateSyntheticDelaysFromTraceConfig();
-
- InternalTraceOptions GetInternalOptionsFromTraceConfig(
- const TraceConfig& config);
-
- class ThreadLocalEventBuffer;
- class OptionalAutoLock;
-
- TraceLog();
- ~TraceLog() override;
- const unsigned char* GetCategoryGroupEnabledInternal(const char* name);
- void AddMetadataEventsWhileLocked();
-
- InternalTraceOptions trace_options() const {
- return static_cast<InternalTraceOptions>(
- subtle::NoBarrier_Load(&trace_options_));
- }
-
- TraceBuffer* trace_buffer() const { return logged_events_.get(); }
- TraceBuffer* CreateTraceBuffer();
- TraceBuffer* CreateTraceBufferVectorOfSize(size_t max_chunks);
-
- std::string EventToConsoleMessage(unsigned char phase,
- const TraceTicks& timestamp,
- TraceEvent* trace_event);
-
- TraceEvent* AddEventToThreadSharedChunkWhileLocked(TraceEventHandle* handle,
- bool check_buffer_is_full);
- void CheckIfBufferIsFullWhileLocked();
- void SetDisabledWhileLocked();
-
- TraceEvent* GetEventByHandleInternal(TraceEventHandle handle,
- OptionalAutoLock* lock);
-
- // |generation| is used in the following callbacks to check if the callback
- // is called for the flush of the current |logged_events_|.
- void FlushCurrentThread(int generation);
- // Usually it runs on a different thread.
- static void ConvertTraceEventsToTraceFormat(
- scoped_ptr<TraceBuffer> logged_events,
- const TraceLog::OutputCallback& flush_output_callback,
- const TraceEvent::ArgumentFilterPredicate& argument_filter_predicate);
- void FinishFlush(int generation);
- void OnFlushTimeout(int generation);
-
- int generation() const {
- return static_cast<int>(subtle::NoBarrier_Load(&generation_));
- }
- bool CheckGeneration(int generation) const {
- return generation == this->generation();
- }
- void UseNextTraceBuffer();
-
- TraceTicks OffsetNow() const {
- return OffsetTimestamp(TraceTicks::Now());
- }
- TraceTicks OffsetTimestamp(const TraceTicks& timestamp) const {
- return timestamp - time_offset_;
- }
-
- // Internal representation of trace options since we store the currently used
- // trace option as an AtomicWord.
- static const InternalTraceOptions kInternalNone;
- static const InternalTraceOptions kInternalRecordUntilFull;
- static const InternalTraceOptions kInternalRecordContinuously;
- static const InternalTraceOptions kInternalEchoToConsole;
- static const InternalTraceOptions kInternalEnableSampling;
- static const InternalTraceOptions kInternalRecordAsMuchAsPossible;
- static const InternalTraceOptions kInternalEnableArgumentFilter;
-
- // This lock protects TraceLog member accesses (except for members protected
- // by thread_info_lock_) from arbitrary threads.
- mutable Lock lock_;
- // This lock protects accesses to thread_names_, thread_event_start_times_
- // and thread_colors_.
- Lock thread_info_lock_;
- Mode mode_;
- int num_traces_recorded_;
- scoped_ptr<TraceBuffer> logged_events_;
- subtle::AtomicWord /* EventCallback */ event_callback_;
- bool dispatching_to_observer_list_;
- std::vector<EnabledStateObserver*> enabled_state_observer_list_;
-
- std::string process_name_;
- base::hash_map<int, std::string> process_labels_;
- int process_sort_index_;
- base::hash_map<int, int> thread_sort_indices_;
- base::hash_map<int, std::string> thread_names_;
-
- // The following two maps are used only when ECHO_TO_CONSOLE.
- base::hash_map<int, std::stack<TraceTicks> > thread_event_start_times_;
- base::hash_map<std::string, int> thread_colors_;
-
- TraceTicks buffer_limit_reached_timestamp_;
-
- // 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.
- WatchEventCallback watch_event_callback_;
- subtle::AtomicWord /* const unsigned char* */ watch_category_;
- std::string watch_event_name_;
-
- subtle::AtomicWord /* Options */ trace_options_;
-
- // Sampling thread handles.
- scoped_ptr<TraceSamplingThread> sampling_thread_;
- PlatformThreadHandle sampling_thread_handle_;
-
- TraceConfig trace_config_;
- TraceConfig event_callback_trace_config_;
-
- ThreadLocalPointer<ThreadLocalEventBuffer> thread_local_event_buffer_;
- ThreadLocalBoolean thread_blocks_message_loop_;
- ThreadLocalBoolean thread_is_in_trace_event_;
-
- // Contains the message loops of threads that have had at least one event
- // added into the local event buffer. Not using SingleThreadTaskRunner
- // because we need to know the life time of the message loops.
- hash_set<MessageLoop*> thread_message_loops_;
-
- // For events which can't be added into the thread local buffer, e.g. events
- // from threads without a message loop.
- scoped_ptr<TraceBufferChunk> thread_shared_chunk_;
- size_t thread_shared_chunk_index_;
-
- // Set when asynchronous Flush is in progress.
- OutputCallback flush_output_callback_;
- scoped_refptr<SingleThreadTaskRunner> flush_task_runner_;
- TraceEvent::ArgumentFilterPredicate argument_filter_predicate_;
- subtle::AtomicWord generation_;
- bool use_worker_thread_;
-
- DISALLOW_COPY_AND_ASSIGN(TraceLog);
-};
-
} // namespace trace_event
} // namespace base
diff --git a/base/trace_event/trace_event_memory.cc b/base/trace_event/trace_event_memory.cc
deleted file mode 100644
index ece006554e..0000000000
--- a/base/trace_event/trace_event_memory.cc
+++ /dev/null
@@ -1,436 +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/trace_event/trace_event_memory.h"
-
-#include "base/lazy_instance.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/single_thread_task_runner.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
-#include "base/threading/thread_local_storage.h"
-#include "base/trace_event/trace_event.h"
-
-namespace base {
-namespace trace_event {
-
-namespace {
-
-// Maximum number of nested TRACE_EVENT scopes to record. Must be less than
-// or equal to HeapProfileTable::kMaxStackDepth / 2 because we record two
-// entries on the pseudo-stack per scope.
-const size_t kMaxScopeDepth = 16;
-
-/////////////////////////////////////////////////////////////////////////////
-// Holds a memory dump until the tracing system needs to serialize it.
-class MemoryDumpHolder : public base::trace_event::ConvertableToTraceFormat {
- public:
- // Takes ownership of dump, which must be a JSON string, allocated with
- // malloc() and NULL terminated.
- explicit MemoryDumpHolder(char* dump) : dump_(dump) {}
-
- // base::trace_event::ConvertableToTraceFormat overrides:
- void AppendAsTraceFormat(std::string* out) const override {
- AppendHeapProfileAsTraceFormat(dump_, out);
- }
-
- private:
- ~MemoryDumpHolder() override { free(dump_); }
-
- char* dump_;
-
- DISALLOW_COPY_AND_ASSIGN(MemoryDumpHolder);
-};
-
-/////////////////////////////////////////////////////////////////////////////
-// Records a stack of TRACE_MEMORY events. One per thread is required.
-struct TraceMemoryStack {
- TraceMemoryStack() : scope_depth(0) {
- memset(scope_data, 0, kMaxScopeDepth * sizeof(scope_data[0]));
- }
-
- // Depth of the currently nested TRACE_EVENT scopes. Allowed to be greater
- // than kMaxScopeDepth so we can match scope pushes and pops even if we don't
- // have enough space to store the EventData.
- size_t scope_depth;
-
- // Stack of categories and names.
- ScopedTraceMemory::ScopeData scope_data[kMaxScopeDepth];
-};
-
-// 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<TraceMemoryStack*>(value);
- delete stack;
-}
-
-// Initializes the thread-local TraceMemoryStack pointer.
-void InitThreadLocalStorage() {
- if (tls_trace_memory_stack.initialized())
- return;
- // Initialize the thread-local storage key.
- 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<TraceMemoryStack*>(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<TraceMemoryStack*>(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 event categories and names.
-// Because tcmalloc stores one pointer per stack frame this converts N nested
-// trace events into N * 2 pseudo-stack entries. Thus this macro invocation:
-// TRACE_EVENT0("category1", "name1");
-// TRACE_EVENT0("category2", "name2");
-// becomes this pseudo-stack:
-// stack_out[0] = "category1"
-// stack_out[1] = "name1"
-// stack_out[2] = "category2"
-// stack_out[3] = "name2"
-// Returns int instead of size_t to match the signature required by tcmalloc.
-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<TraceMemoryStack*>(tls_trace_memory_stack.Get());
- // Copy at most kMaxScopeDepth scope entries.
- const size_t count = std::min(stack->scope_depth, kMaxScopeDepth);
- // Notes that memcpy() works for zero bytes.
- memcpy(stack_out,
- stack->scope_data,
- count * sizeof(stack->scope_data[0]));
- // Each item in the trace event stack contains both name and category so tell
- // tcmalloc that we have returned |count| * 2 stack frames.
- return static_cast<int>(count * 2);
-}
-
-} // namespace
-
-//////////////////////////////////////////////////////////////////////////////
-
-TraceMemoryController::TraceMemoryController(
- scoped_refptr<SingleThreadTaskRunner> task_runner,
- HeapProfilerStartFunction heap_profiler_start_function,
- HeapProfilerStopFunction heap_profiler_stop_function,
- GetHeapProfileFunction get_heap_profile_function)
- : task_runner_(task_runner.Pass()),
- 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::trace_event::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";
- task_runner_->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";
- task_runner_->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";
- InitThreadLocalStorage();
- 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_();
- const int kSnapshotId = 1;
- TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
- TRACE_DISABLED_BY_DEFAULT("memory"),
- "memory::Heap",
- kSnapshotId,
- scoped_refptr<ConvertableToTraceFormat>(new MemoryDumpHolder(dump)));
-}
-
-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;
-
-void ScopedTraceMemory::Initialize(const char* category, const char* name) {
- DCHECK(enabled_);
- // Get our thread's copy of the stack.
- TraceMemoryStack* trace_memory_stack = GetTraceMemoryStack();
- const size_t index = trace_memory_stack->scope_depth;
- // Don't record data for deeply nested scopes, but continue to increment
- // |stack_depth| so we can match pushes and pops.
- if (index < kMaxScopeDepth) {
- ScopeData& event = trace_memory_stack->scope_data[index];
- event.category = category;
- event.name = name;
- }
- trace_memory_stack->scope_depth++;
-}
-
-void ScopedTraceMemory::Destroy() {
- DCHECK(enabled_);
- // 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->scope_depth > 0)
- trace_memory_stack->scope_depth--;
-}
-
-// static
-void ScopedTraceMemory::InitForTest() {
- InitThreadLocalStorage();
- enabled_ = true;
-}
-
-// static
-void ScopedTraceMemory::CleanupForTest() {
- enabled_ = false;
- CleanupThreadLocalStorage();
-}
-
-// static
-int ScopedTraceMemory::GetStackDepthForTest() {
- TraceMemoryStack* stack = GetTraceMemoryStack();
- return static_cast<int>(stack->scope_depth);
-}
-
-// static
-ScopedTraceMemory::ScopeData ScopedTraceMemory::GetScopeDataForTest(
- int stack_index) {
- TraceMemoryStack* stack = GetTraceMemoryStack();
- return stack->scope_data[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<std::string> 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<std::string> 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 categories
- // and names.
- std::vector<std::string> 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 pairs of "stack addresses" into category and name strings.
- const std::string kSingleQuote = "'";
- for (size_t t = 4; t < tokens.size(); t += 2) {
- // Casting strings into pointers is ugly but otherwise tcmalloc would need
- // to gain a special output serializer just for pseudo-stacks.
- const char* trace_category = StringFromHexAddress(tokens[t]);
- DCHECK_LT(t + 1, tokens.size());
- const char* trace_name = StringFromHexAddress(tokens[t + 1]);
-
- // TODO(jamescook): Report the trace category and name separately to the
- // trace viewer and allow it to decide what decorations to apply. For now
- // just hard-code a decoration for posted tasks (toplevel).
- std::string trace_string(trace_name);
- if (!strcmp(trace_category, "toplevel"))
- trace_string.append("->PostTask");
-
- // Some trace name strings have double quotes, convert them to single.
- ReplaceChars(trace_string, "\"", kSingleQuote, &trace_string);
-
- output->append(trace_string);
-
- // Trace viewer expects a trailing space.
- output->append(" ");
- }
- output->append("\"}");
- return true;
-}
-
-const char* StringFromHexAddress(const std::string& hex_address) {
- uint64 address = 0;
- if (!base::HexStringToUInt64(hex_address, &address))
- return "error";
- if (!address)
- return "null";
- // Note that this cast handles 64-bit to 32-bit conversion if necessary.
- return reinterpret_cast<const char*>(address);
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/base/trace_event/trace_event_memory.h b/base/trace_event/trace_event_memory.h
deleted file mode 100644
index e2b3ae9306..0000000000
--- a/base/trace_event/trace_event_memory.h
+++ /dev/null
@@ -1,171 +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_TRACE_EVENT_TRACE_EVENT_MEMORY_H_
-#define BASE_TRACE_EVENT_TRACE_EVENT_MEMORY_H_
-
-#include "base/base_export.h"
-#include "base/gtest_prod_util.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/timer/timer.h"
-#include "base/trace_event/trace_event_impl.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 SingleThreadTaskRunner;
-
-namespace trace_event {
-
-// 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)();
-
- // |task_runner| must be a task runner for 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<SingleThreadTaskRunner> task_runner,
- HeapProfilerStartFunction heap_profiler_start_function,
- HeapProfilerStopFunction heap_profiler_stop_function,
- GetHeapProfileFunction get_heap_profile_function);
- virtual ~TraceMemoryController();
-
- // base::trace_event::TraceLog::EnabledStateChangedObserver overrides:
- void OnTraceLogEnabled() override;
- 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<SingleThreadTaskRunner> task_runner_;
-
- // 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<TraceMemoryController> dump_timer_;
-
- WeakPtrFactory<TraceMemoryController> 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:
- struct ScopeData {
- const char* category;
- const char* name;
- };
-
- // Memory for |category| and |name| must be static, for example, literal
- // strings in a TRACE_EVENT macro.
- ScopedTraceMemory(const char* category, const char* name) {
- if (!enabled_)
- return;
- Initialize(category, name);
- }
- ~ScopedTraceMemory() {
- if (!enabled_)
- return;
- Destroy();
- }
-
- // 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 GetStackDepthForTest();
- static ScopeData GetScopeDataForTest(int stack_index);
-
- private:
- void Initialize(const char* category, const char* name);
- void Destroy();
-
- 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);
-
-// Returns a pointer to a string given its hexadecimal address in |hex_address|.
-// Handles both 32-bit and 64-bit addresses. Returns "null" for null pointers
-// and "error" if |address| could not be parsed. Visible for testing.
-BASE_EXPORT const char* StringFromHexAddress(const std::string& hex_address);
-
-} // namespace trace_event
-} // 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.
-#if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED)
-#define INTERNAL_TRACE_MEMORY(category, name) \
- base::trace_event::ScopedTraceMemory INTERNAL_TRACE_MEMORY_ID(category, 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_TRACE_EVENT_TRACE_EVENT_MEMORY_H_
diff --git a/base/trace_event/trace_event_memory_overhead.cc b/base/trace_event/trace_event_memory_overhead.cc
index 0cc3d59890..ba7207d616 100644
--- a/base/trace_event/trace_event_memory_overhead.cc
+++ b/base/trace_event/trace_event_memory_overhead.cc
@@ -6,18 +6,13 @@
#include <algorithm>
+#include "base/bits.h"
#include "base/memory/ref_counted_memory.h"
#include "base/strings/stringprintf.h"
#include "base/trace_event/memory_allocator_dump.h"
#include "base/trace_event/process_memory_dump.h"
#include "base/values.h"
-namespace {
-size_t RoundUp(size_t size, size_t alignment) {
- return (size + alignment - 1) & ~(alignment - 1);
-}
-} // namespace
-
namespace base {
namespace trace_event {
@@ -61,9 +56,9 @@ void TraceEventMemoryOverhead::AddString(const std::string& str) {
// The number below are empirical and mainly based on profiling of real-world
// std::string implementations:
// - even short string end up malloc()-inc at least 32 bytes.
- // - longer stings seem to malloc() multiples of 16 bytes.
- Add("std::string",
- sizeof(std::string) + std::max<size_t>(RoundUp(str.capacity(), 16), 32u));
+ // - longer strings seem to malloc() multiples of 16 bytes.
+ const size_t capacity = bits::Align(str.capacity(), 16);
+ Add("std::string", sizeof(std::string) + std::max<size_t>(capacity, 32u));
}
void TraceEventMemoryOverhead::AddRefCountedString(
@@ -127,6 +122,13 @@ void TraceEventMemoryOverhead::AddSelf() {
Add("TraceEventMemoryOverhead", estimated_size);
}
+size_t TraceEventMemoryOverhead::GetCount(const char* object_type) const {
+ const auto& it = allocated_objects_.find(object_type);
+ if (it == allocated_objects_.end())
+ return 0u;
+ return it->second.count;
+}
+
void TraceEventMemoryOverhead::Update(const TraceEventMemoryOverhead& other) {
for (const auto& it : other.allocated_objects_) {
AddOrCreateInternal(it.first, it.second.count,
@@ -145,7 +147,7 @@ void TraceEventMemoryOverhead::DumpInto(const char* base_name,
it.second.allocated_size_in_bytes);
mad->AddScalar("resident_size", MemoryAllocatorDump::kUnitsBytes,
it.second.resident_size_in_bytes);
- mad->AddScalar(MemoryAllocatorDump::kNameObjectsCount,
+ mad->AddScalar(MemoryAllocatorDump::kNameObjectCount,
MemoryAllocatorDump::kUnitsObjects, it.second.count);
}
}
diff --git a/base/trace_event/trace_event_memory_overhead.h b/base/trace_event/trace_event_memory_overhead.h
index 8ecf12dc96..a69c93fed2 100644
--- a/base/trace_event/trace_event_memory_overhead.h
+++ b/base/trace_event/trace_event_memory_overhead.h
@@ -5,9 +5,12 @@
#ifndef BASE_TRACE_EVENT_TRACE_EVENT_MEMORY_OVERHEAD_H_
#define BASE_TRACE_EVENT_TRACE_EVENT_MEMORY_OVERHEAD_H_
+#include <stddef.h>
+
#include "base/base_export.h"
#include "base/containers/hash_tables.h"
#include "base/containers/small_map.h"
+#include "base/macros.h"
namespace base {
@@ -43,6 +46,9 @@ class BASE_EXPORT TraceEventMemoryOverhead {
// this TraceEventMemoryOverhead instance itself.
void AddSelf();
+ // Retrieves the count, that is, the count of Add*(|object_type|, ...) calls.
+ size_t GetCount(const char* object_type) const;
+
// Adds up and merges all the values from |other| to this instance.
void Update(const TraceEventMemoryOverhead& other);
diff --git a/base/trace_event/trace_event_memory_unittest.cc b/base/trace_event/trace_event_memory_unittest.cc
deleted file mode 100644
index 781a0544c4..0000000000
--- a/base/trace_event/trace_event_memory_unittest.cc
+++ /dev/null
@@ -1,236 +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/trace_event/trace_event_memory.h"
-
-#include <sstream>
-#include <string>
-
-#include "base/trace_event/trace_event_impl.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 trace_event {
-
-// 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() {}
- ~TraceMemoryTest() override {}
-
- 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<TraceMemoryController> controller(new TraceMemoryController(
- message_loop.task_runner(), ::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::GetStackDepthForTest());
-
- {
- // Push an item.
- ScopedTraceMemory scope1("cat1", "name1");
- EXPECT_EQ(1, ScopedTraceMemory::GetStackDepthForTest());
- EXPECT_EQ("cat1", ScopedTraceMemory::GetScopeDataForTest(0).category);
- EXPECT_EQ("name1", ScopedTraceMemory::GetScopeDataForTest(0).name);
-
- {
- // One more item.
- ScopedTraceMemory scope2("cat2", "name2");
- EXPECT_EQ(2, ScopedTraceMemory::GetStackDepthForTest());
- EXPECT_EQ("cat2", ScopedTraceMemory::GetScopeDataForTest(1).category);
- EXPECT_EQ("name2", ScopedTraceMemory::GetScopeDataForTest(1).name);
- }
-
- // Ended scope 2.
- EXPECT_EQ(1, ScopedTraceMemory::GetStackDepthForTest());
- }
-
- // Ended scope 1.
- EXPECT_EQ(0, ScopedTraceMemory::GetStackDepthForTest());
-
- ScopedTraceMemory::CleanupForTest();
-}
-
-void TestDeepScopeNesting(int current, int depth) {
- EXPECT_EQ(current, ScopedTraceMemory::GetStackDepthForTest());
- ScopedTraceMemory scope("category", "name");
- if (current < depth)
- TestDeepScopeNesting(current + 1, depth);
- EXPECT_EQ(current + 1, ScopedTraceMemory::GetStackDepthForTest());
-}
-
-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 normal category and name entries.
- const char kCategory[] = "category";
- const char kName[] = "name";
- std::ostringstream input;
- input << " 68: 4195 [ 1087: 98009] @ " << &kCategory << " "
- << &kName;
- const std::string kExpectedOutput =
- ",\n"
- "{"
- "\"current_allocs\": 68, "
- "\"current_bytes\": 4195, "
- "\"trace\": \"name \""
- "}";
- std::string output;
- EXPECT_TRUE(
- AppendHeapProfileLineAsTraceFormat(input.str().c_str(), &output));
- EXPECT_EQ(kExpectedOutput, output);
-
- // Input with with the category "toplevel".
- // TODO(jamescook): Eliminate this special case and move the logic to the
- // trace viewer code.
- const char kTaskCategory[] = "toplevel";
- const char kTaskName[] = "TaskName";
- std::ostringstream input2;
- input2 << " 68: 4195 [ 1087: 98009] @ " << &kTaskCategory << " "
- << &kTaskName;
- const std::string kExpectedOutput2 =
- ",\n"
- "{"
- "\"current_allocs\": 68, "
- "\"current_bytes\": 4195, "
- "\"trace\": \"TaskName->PostTask \""
- "}";
- std::string output2;
- EXPECT_TRUE(
- AppendHeapProfileLineAsTraceFormat(input2.str().c_str(), &output2));
- EXPECT_EQ(kExpectedOutput2, output2);
-
- // Zero current allocations is skipped.
- std::ostringstream zero_input;
- zero_input << " 0: 0 [ 1087: 98009] @ " << &kCategory << " "
- << &kName;
- 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 \""
- "}]\n";
- std::string output;
- AppendHeapProfileAsTraceFormat(input, &output);
- EXPECT_EQ(kExpectedOutput, output);
-}
-
-TEST_F(TraceMemoryTest, StringFromHexAddress) {
- EXPECT_STREQ("null", StringFromHexAddress("0x0"));
- EXPECT_STREQ("error", StringFromHexAddress("not an address"));
- const char kHello[] = "hello";
- std::ostringstream hex_address;
- hex_address << &kHello;
- EXPECT_STREQ(kHello, StringFromHexAddress(hex_address.str()));
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/base/trace_event/trace_event_synthetic_delay.cc b/base/trace_event/trace_event_synthetic_delay.cc
index 3fb3684c23..b6ce2845c4 100644
--- a/base/trace_event/trace_event_synthetic_delay.cc
+++ b/base/trace_event/trace_event_synthetic_delay.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/macros.h"
#include "base/memory/singleton.h"
#include "base/trace_event/trace_event_synthetic_delay.h"
@@ -23,7 +24,7 @@ class TraceEventSyntheticDelayRegistry : public TraceEventSyntheticDelayClock {
void ResetAllDelays();
// TraceEventSyntheticDelayClock implementation.
- base::TimeTicks Now() override;
+ TimeTicks Now() override;
private:
TraceEventSyntheticDelayRegistry();
@@ -33,7 +34,7 @@ class TraceEventSyntheticDelayRegistry : public TraceEventSyntheticDelayClock {
Lock lock_;
TraceEventSyntheticDelay delays_[kMaxSyntheticDelays];
TraceEventSyntheticDelay dummy_delay_;
- base::subtle::Atomic32 delay_count_;
+ subtle::Atomic32 delay_count_;
DISALLOW_COPY_AND_ASSIGN(TraceEventSyntheticDelayRegistry);
};
@@ -56,8 +57,7 @@ void TraceEventSyntheticDelay::Initialize(
clock_ = clock;
}
-void TraceEventSyntheticDelay::SetTargetDuration(
- base::TimeDelta target_duration) {
+void TraceEventSyntheticDelay::SetTargetDuration(TimeDelta target_duration) {
AutoLock lock(lock_);
target_duration_ = target_duration;
trigger_count_ = 0;
@@ -83,7 +83,7 @@ void TraceEventSyntheticDelay::Begin() {
if (!target_duration_.ToInternalValue())
return;
- base::TimeTicks start_time = clock_->Now();
+ TimeTicks start_time = clock_->Now();
{
AutoLock lock(lock_);
if (++begin_count_ != 1)
@@ -92,14 +92,14 @@ void TraceEventSyntheticDelay::Begin() {
}
}
-void TraceEventSyntheticDelay::BeginParallel(base::TimeTicks* out_end_time) {
+void TraceEventSyntheticDelay::BeginParallel(TimeTicks* out_end_time) {
// See note in Begin().
if (!target_duration_.ToInternalValue()) {
- *out_end_time = base::TimeTicks();
+ *out_end_time = TimeTicks();
return;
}
- base::TimeTicks start_time = clock_->Now();
+ TimeTicks start_time = clock_->Now();
{
AutoLock lock(lock_);
*out_end_time = CalculateEndTimeLocked(start_time);
@@ -111,7 +111,7 @@ void TraceEventSyntheticDelay::End() {
if (!target_duration_.ToInternalValue())
return;
- base::TimeTicks end_time;
+ TimeTicks end_time;
{
AutoLock lock(lock_);
if (!begin_count_ || --begin_count_ != 0)
@@ -122,21 +122,21 @@ void TraceEventSyntheticDelay::End() {
ApplyDelay(end_time);
}
-void TraceEventSyntheticDelay::EndParallel(base::TimeTicks end_time) {
+void TraceEventSyntheticDelay::EndParallel(TimeTicks end_time) {
if (!end_time.is_null())
ApplyDelay(end_time);
}
-base::TimeTicks TraceEventSyntheticDelay::CalculateEndTimeLocked(
- base::TimeTicks start_time) {
+TimeTicks TraceEventSyntheticDelay::CalculateEndTimeLocked(
+ TimeTicks start_time) {
if (mode_ == ONE_SHOT && trigger_count_++)
- return base::TimeTicks();
+ return TimeTicks();
else if (mode_ == ALTERNATING && trigger_count_++ % 2)
- return base::TimeTicks();
+ return TimeTicks();
return start_time + target_duration_;
}
-void TraceEventSyntheticDelay::ApplyDelay(base::TimeTicks end_time) {
+void TraceEventSyntheticDelay::ApplyDelay(TimeTicks end_time) {
TRACE_EVENT0("synthetic_delay", name_.c_str());
while (clock_->Now() < end_time) {
// Busy loop.
@@ -157,14 +157,14 @@ TraceEventSyntheticDelay* TraceEventSyntheticDelayRegistry::GetOrCreateDelay(
const char* name) {
// Try to find an existing delay first without locking to make the common case
// fast.
- int delay_count = base::subtle::Acquire_Load(&delay_count_);
+ int delay_count = subtle::Acquire_Load(&delay_count_);
for (int i = 0; i < delay_count; ++i) {
if (!strcmp(name, delays_[i].name_.c_str()))
return &delays_[i];
}
AutoLock lock(lock_);
- delay_count = base::subtle::Acquire_Load(&delay_count_);
+ delay_count = subtle::Acquire_Load(&delay_count_);
for (int i = 0; i < delay_count; ++i) {
if (!strcmp(name, delays_[i].name_.c_str()))
return &delays_[i];
@@ -176,19 +176,19 @@ TraceEventSyntheticDelay* TraceEventSyntheticDelayRegistry::GetOrCreateDelay(
return &dummy_delay_;
delays_[delay_count].Initialize(std::string(name), this);
- base::subtle::Release_Store(&delay_count_, delay_count + 1);
+ subtle::Release_Store(&delay_count_, delay_count + 1);
return &delays_[delay_count];
}
-base::TimeTicks TraceEventSyntheticDelayRegistry::Now() {
- return base::TimeTicks::Now();
+TimeTicks TraceEventSyntheticDelayRegistry::Now() {
+ return TimeTicks::Now();
}
void TraceEventSyntheticDelayRegistry::ResetAllDelays() {
AutoLock lock(lock_);
- int delay_count = base::subtle::Acquire_Load(&delay_count_);
+ int delay_count = subtle::Acquire_Load(&delay_count_);
for (int i = 0; i < delay_count; ++i) {
- delays_[i].SetTargetDuration(base::TimeDelta());
+ delays_[i].SetTargetDuration(TimeDelta());
delays_[i].SetClock(this);
}
}
diff --git a/base/trace_event/trace_event_synthetic_delay.h b/base/trace_event/trace_event_synthetic_delay.h
index 0df794b46c..59e2842f71 100644
--- a/base/trace_event/trace_event_synthetic_delay.h
+++ b/base/trace_event/trace_event_synthetic_delay.h
@@ -33,6 +33,7 @@
#define BASE_TRACE_EVENT_TRACE_EVENT_SYNTHETIC_DELAY_H_
#include "base/atomicops.h"
+#include "base/macros.h"
#include "base/synchronization/lock.h"
#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
diff --git a/base/trace_event/trace_event_synthetic_delay_unittest.cc b/base/trace_event/trace_event_synthetic_delay_unittest.cc
index 1dc0fc26f5..97a4580b3b 100644
--- a/base/trace_event/trace_event_synthetic_delay_unittest.cc
+++ b/base/trace_event/trace_event_synthetic_delay_unittest.cc
@@ -4,6 +4,9 @@
#include "base/trace_event/trace_event_synthetic_delay.h"
+#include <stdint.h>
+
+#include "base/macros.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
@@ -39,19 +42,19 @@ class TraceEventSyntheticDelayTest : public testing::Test,
void AdvanceTime(base::TimeDelta delta) { now_ += delta; }
- int64 TestFunction() {
+ int64_t TestFunction() {
base::TimeTicks start = Now();
{ TRACE_EVENT_SYNTHETIC_DELAY("test.Delay"); }
return (Now() - start).InMilliseconds();
}
- int64 AsyncTestFunctionBegin() {
+ int64_t AsyncTestFunctionBegin() {
base::TimeTicks start = Now();
{ TRACE_EVENT_SYNTHETIC_DELAY_BEGIN("test.AsyncDelay"); }
return (Now() - start).InMilliseconds();
}
- int64 AsyncTestFunctionEnd() {
+ int64_t AsyncTestFunctionEnd() {
base::TimeTicks start = Now();
{ TRACE_EVENT_SYNTHETIC_DELAY_END("test.AsyncDelay"); }
return (Now() - start).InMilliseconds();
diff --git a/base/trace_event/trace_event_system_stats_monitor.h b/base/trace_event/trace_event_system_stats_monitor.h
index 051669a35f..14aa5681fe 100644
--- a/base/trace_event/trace_event_system_stats_monitor.h
+++ b/base/trace_event/trace_event_system_stats_monitor.h
@@ -7,11 +7,12 @@
#include "base/base_export.h"
#include "base/gtest_prod_util.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/process/process_metrics.h"
#include "base/timer/timer.h"
-#include "base/trace_event/trace_event_impl.h"
+#include "base/trace_event/trace_log.h"
namespace base {
@@ -33,7 +34,7 @@ class BASE_EXPORT TraceEventSystemStatsMonitor
explicit TraceEventSystemStatsMonitor(
scoped_refptr<SingleThreadTaskRunner> task_runner);
- virtual ~TraceEventSystemStatsMonitor();
+ ~TraceEventSystemStatsMonitor() override;
// base::trace_event::TraceLog::EnabledStateChangedObserver overrides:
void OnTraceLogEnabled() override;
@@ -56,7 +57,7 @@ class BASE_EXPORT TraceEventSystemStatsMonitor
scoped_refptr<SingleThreadTaskRunner> task_runner_;
// Timer to schedule system profile dumps.
- RepeatingTimer<TraceEventSystemStatsMonitor> dump_timer_;
+ RepeatingTimer dump_timer_;
WeakPtrFactory<TraceEventSystemStatsMonitor> weak_factory_;
diff --git a/base/trace_event/trace_event_unittest.cc b/base/trace_event/trace_event_unittest.cc
index 796c386f4d..09f2a916c3 100644
--- a/base/trace_event/trace_event_unittest.cc
+++ b/base/trace_event/trace_event_unittest.cc
@@ -3,6 +3,9 @@
// found in the LICENSE file.
#include <math.h>
+#include <stddef.h>
+#include <stdint.h>
+
#include <cstdlib>
#include "base/bind.h"
@@ -10,16 +13,20 @@
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/location.h"
+#include "base/macros.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/single_thread_task_runner.h"
+#include "base/stl_util.h"
+#include "base/strings/pattern.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/time/time.h"
+#include "base/trace_event/trace_buffer.h"
#include "base/trace_event/trace_event.h"
#include "base/trace_event/trace_event_synthetic_delay.h"
#include "base/values.h"
@@ -87,7 +94,14 @@ class TraceEventTestFixture : public testing::Test {
TraceLog::RECORDING_MODE);
}
+ void CancelTrace() {
+ WaitableEvent flush_complete_event(false, false);
+ CancelTraceAsync(&flush_complete_event);
+ flush_complete_event.Wait();
+ }
+
void EndTraceAndFlush() {
+ num_flush_callbacks_ = 0;
WaitableEvent flush_complete_event(false, false);
EndTraceAndFlushAsync(&flush_complete_event);
flush_complete_event.Wait();
@@ -105,6 +119,13 @@ class TraceEventTestFixture : public testing::Test {
flush_complete_event.Wait();
}
+ void CancelTraceAsync(WaitableEvent* flush_complete_event) {
+ TraceLog::GetInstance()->CancelTracing(
+ base::Bind(&TraceEventTestFixture::OnTraceDataCollected,
+ base::Unretained(static_cast<TraceEventTestFixture*>(this)),
+ base::Unretained(flush_complete_event)));
+ }
+
void EndTraceAndFlushAsync(WaitableEvent* flush_complete_event) {
TraceLog::GetInstance()->SetDisabled();
TraceLog::GetInstance()->Flush(
@@ -136,6 +157,7 @@ class TraceEventTestFixture : public testing::Test {
ASSERT_FALSE(tracelog->IsEnabled());
trace_buffer_.SetOutputCallback(json_output_.GetCallback());
event_watch_notification_ = 0;
+ num_flush_callbacks_ = 0;
}
void TearDown() override {
if (TraceLog::GetInstance())
@@ -152,6 +174,7 @@ class TraceEventTestFixture : public testing::Test {
TraceResultBuffer trace_buffer_;
TraceResultBuffer::SimpleOutput json_output_;
int event_watch_notification_;
+ size_t num_flush_callbacks_;
private:
// We want our singleton torn down after each test.
@@ -163,15 +186,18 @@ void TraceEventTestFixture::OnTraceDataCollected(
WaitableEvent* flush_complete_event,
const scoped_refptr<base::RefCountedString>& events_str,
bool has_more_events) {
+ num_flush_callbacks_++;
+ if (num_flush_callbacks_ > 1) {
+ EXPECT_FALSE(events_str->data().empty());
+ }
AutoLock lock(lock_);
json_output_.json_output.clear();
trace_buffer_.Start();
trace_buffer_.AddFragment(events_str->data());
trace_buffer_.Finish();
- scoped_ptr<Value> root;
- root.reset(base::JSONReader::DeprecatedRead(
- json_output_.json_output, JSON_PARSE_RFC | JSON_DETACHABLE_CHILDREN));
+ scoped_ptr<Value> root = base::JSONReader::Read(
+ json_output_.json_output, JSON_PARSE_RFC | JSON_DETACHABLE_CHILDREN);
if (!root.get()) {
LOG(ERROR) << json_output_.json_output;
@@ -381,11 +407,6 @@ const char kControlCharacters[] = "\001\002\003\n\r";
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",
@@ -438,18 +459,16 @@ void TraceWithAllMacroVariants(WaitableEvent* task_complete_event) {
TRACE_EVENT_FLOW_END_BIND_TO_ENCLOSING0("all",
"TRACE_EVENT_FLOW_END_BIND_TO_ENCLOSING0 call", kFlowId);
- 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_WITH_TIMESTAMP1("all", "TRACE_COUNTER_WITH_TIMESTAMP1 call",
+ 42, 31415);
+ TRACE_COUNTER_WITH_TIMESTAMP2("all", "TRACE_COUNTER_WITH_TIMESTAMP2 call",
+ 42, "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);
@@ -503,17 +522,6 @@ void ValidateAllTraceMacrosCreatedData(const ListValue& trace_parsed) {
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;
@@ -632,37 +640,6 @@ void ValidateAllTraceMacrosCreatedData(const ListValue& trace_parsed) {
EXPECT_SUB_FIND_("id");
EXPECT_SUB_FIND_(kFlowIdStr);
- 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;
@@ -688,6 +665,39 @@ void ValidateAllTraceMacrosCreatedData(const ListValue& trace_parsed) {
EXPECT_EQ(1415, value);
}
+ EXPECT_FIND_("TRACE_COUNTER_WITH_TIMESTAMP1 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);
+
+ int ts;
+ EXPECT_TRUE((item && item->GetInteger("ts", &ts)));
+ EXPECT_EQ(42, ts);
+ }
+
+ EXPECT_FIND_("TRACE_COUNTER_WITH_TIMESTAMP2 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);
+
+ int ts;
+ EXPECT_TRUE((item && item->GetInteger("ts", &ts)));
+ EXPECT_EQ(42, ts);
+ }
+
EXPECT_FIND_("TRACE_COUNTER_ID1 call");
{
std::string id;
@@ -901,6 +911,19 @@ TEST_F(TraceEventTestFixture, DataCaptured) {
ValidateAllTraceMacrosCreatedData(trace_parsed_);
}
+// Emit some events and validate that only empty strings are received
+// if we tell Flush() to discard events.
+TEST_F(TraceEventTestFixture, DataDiscarded) {
+ TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
+ TraceLog::RECORDING_MODE);
+
+ TraceWithAllMacroVariants(NULL);
+
+ CancelTrace();
+
+ EXPECT_TRUE(trace_parsed_.empty());
+}
+
class MockEnabledStateChangedObserver :
public TraceLog::EnabledStateObserver {
public:
@@ -987,7 +1010,7 @@ class AfterStateChangeEnabledStateObserver
: public TraceLog::EnabledStateObserver {
public:
AfterStateChangeEnabledStateObserver() {}
- virtual ~AfterStateChangeEnabledStateObserver() {}
+ ~AfterStateChangeEnabledStateObserver() override {}
// TraceLog::EnabledStateObserver overrides:
void OnTraceLogEnabled() override {
@@ -1018,7 +1041,7 @@ class SelfRemovingEnabledStateObserver
: public TraceLog::EnabledStateObserver {
public:
SelfRemovingEnabledStateObserver() {}
- virtual ~SelfRemovingEnabledStateObserver() {}
+ ~SelfRemovingEnabledStateObserver() override {}
// TraceLog::EnabledStateObserver overrides:
void OnTraceLogEnabled() override {}
@@ -1071,6 +1094,100 @@ TEST_F(TraceEventTestFixture, NewTraceRecording) {
EndTraceAndFlush();
}
+TEST_F(TraceEventTestFixture, TestTraceFlush) {
+ size_t min_traces = 1;
+ size_t max_traces = 1;
+ do {
+ max_traces *= 2;
+ TraceLog::GetInstance()->SetEnabled(TraceConfig(),
+ TraceLog::RECORDING_MODE);
+ for (size_t i = 0; i < max_traces; i++) {
+ TRACE_EVENT_INSTANT0("x", "y", TRACE_EVENT_SCOPE_THREAD);
+ }
+ EndTraceAndFlush();
+ } while (num_flush_callbacks_ < 2);
+
+ while (min_traces + 50 < max_traces) {
+ size_t traces = (min_traces + max_traces) / 2;
+ TraceLog::GetInstance()->SetEnabled(TraceConfig(),
+ TraceLog::RECORDING_MODE);
+ for (size_t i = 0; i < traces; i++) {
+ TRACE_EVENT_INSTANT0("x", "y", TRACE_EVENT_SCOPE_THREAD);
+ }
+ EndTraceAndFlush();
+ if (num_flush_callbacks_ < 2) {
+ min_traces = traces - 10;
+ } else {
+ max_traces = traces + 10;
+ }
+ }
+
+ for (size_t traces = min_traces; traces < max_traces; traces++) {
+ TraceLog::GetInstance()->SetEnabled(TraceConfig(),
+ TraceLog::RECORDING_MODE);
+ for (size_t i = 0; i < traces; i++) {
+ TRACE_EVENT_INSTANT0("x", "y", TRACE_EVENT_SCOPE_THREAD);
+ }
+ EndTraceAndFlush();
+ }
+}
+
+TEST_F(TraceEventTestFixture, AddMetadataEvent) {
+ int num_calls = 0;
+
+ class Convertable : public ConvertableToTraceFormat {
+ public:
+ explicit Convertable(int* num_calls) : num_calls_(num_calls) {}
+ void AppendAsTraceFormat(std::string* out) const override {
+ (*num_calls_)++;
+ out->append("\"metadata_value\"");
+ }
+
+ private:
+ ~Convertable() override {}
+ int* num_calls_;
+ };
+
+ scoped_refptr<ConvertableToTraceFormat> convertable =
+ new Convertable(&num_calls);
+
+ BeginTrace();
+ TRACE_EVENT_API_ADD_METADATA_EVENT("metadata_event_name", "metadata_arg_name",
+ convertable);
+
+ // |AppendAsTraceFormat| should only be called on flush, not when the event
+ // is added.
+ ASSERT_EQ(0, num_calls);
+ EndTraceAndFlush();
+ ASSERT_EQ(1, num_calls);
+ EXPECT_TRUE(FindNamePhaseKeyValue("metadata_event_name", "M",
+ "metadata_arg_name", "metadata_value"));
+
+ // The metadata event should only be adde to the current trace. In this new
+ // trace, the event should not appear.
+ BeginTrace();
+ EndTraceAndFlush();
+ ASSERT_EQ(1, num_calls);
+
+ // Flushing should cause |AppendAsTraceFormat| to be called, but if the buffer
+ // is left intact, it the flush at the end of the trace should still call it;
+ // the metadata event should not be removed.
+ TraceLog::GetInstance()->SetEnabled(
+ TraceConfig(kRecordAllCategoryFilter,
+ "record-until-full,enable-sampling"),
+ TraceLog::MONITORING_MODE);
+ TRACE_EVENT_API_ADD_METADATA_EVENT("metadata_event_name", "metadata_arg_name",
+ convertable);
+ FlushMonitoring();
+ ASSERT_EQ(2, num_calls);
+
+ // Flushing the trace at this point will case |AppendAsTraceFormat| to be
+ // called twice: once for the event that was added by the monitoring flush,
+ // and once for the end trace flush; the metadata event will be duplicated.
+ // This is consistent with the other metadata events.
+ EndTraceAndFlush();
+ ASSERT_EQ(4, num_calls);
+}
// Test that categories work.
TEST_F(TraceEventTestFixture, Categories) {
@@ -1090,24 +1207,15 @@ TEST_F(TraceEventTestFixture, Categories) {
EndTraceAndFlush();
std::vector<std::string> 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());
+ EXPECT_TRUE(ContainsValue(cat_groups, "c1"));
+ EXPECT_TRUE(ContainsValue(cat_groups, "c2"));
+ EXPECT_TRUE(ContainsValue(cat_groups, "c3"));
+ EXPECT_TRUE(ContainsValue(cat_groups, "c4"));
+ EXPECT_TRUE(ContainsValue(cat_groups, "c5,c6"));
+ EXPECT_TRUE(ContainsValue(cat_groups, "c7,c8"));
+ EXPECT_TRUE(ContainsValue(cat_groups, "disabled-by-default-c9"));
// Make sure metadata isn't returned.
- EXPECT_TRUE(std::find(cat_groups.begin(),
- cat_groups.end(), "__metadata") == cat_groups.end());
+ EXPECT_FALSE(ContainsValue(cat_groups, "__metadata"));
const std::vector<std::string> empty_categories;
std::vector<std::string> included_categories;
@@ -1353,11 +1461,13 @@ TEST_F(TraceEventTestFixture, StaticStringVsString) {
TraceEventHandle handle1 =
trace_event_internal::AddTraceEvent(
TRACE_EVENT_PHASE_INSTANT, category_group_enabled, "name1", 0, 0,
+ trace_event_internal::kNoId,
"arg1", std::string("argval"), "arg2", std::string("argval"));
// Test that static TRACE_STR_COPY string arguments are copied.
TraceEventHandle handle2 =
trace_event_internal::AddTraceEvent(
TRACE_EVENT_PHASE_INSTANT, category_group_enabled, "name2", 0, 0,
+ trace_event_internal::kNoId,
"arg1", TRACE_STR_COPY("argval"),
"arg2", TRACE_STR_COPY("argval"));
EXPECT_GT(tracer->GetStatus().event_count, 1u);
@@ -1380,6 +1490,7 @@ TEST_F(TraceEventTestFixture, StaticStringVsString) {
TraceEventHandle handle1 =
trace_event_internal::AddTraceEvent(
TRACE_EVENT_PHASE_INSTANT, category_group_enabled, "name1", 0, 0,
+ trace_event_internal::kNoId,
"arg1", "argval", "arg2", "argval");
// Test that static TRACE_STR_COPY NULL string arguments are not copied.
const char* str1 = NULL;
@@ -1387,6 +1498,7 @@ TEST_F(TraceEventTestFixture, StaticStringVsString) {
TraceEventHandle handle2 =
trace_event_internal::AddTraceEvent(
TRACE_EVENT_PHASE_INSTANT, category_group_enabled, "name2", 0, 0,
+ trace_event_internal::kNoId,
"arg1", TRACE_STR_COPY(str1),
"arg2", TRACE_STR_COPY(str2));
EXPECT_GT(tracer->GetStatus().event_count, 1u);
@@ -1478,7 +1590,7 @@ TEST_F(TraceEventTestFixture, ThreadNames) {
for (int i = 0; i < kNumThreads; i++) {
task_complete_events[i] = new WaitableEvent(false, false);
threads[i]->Start();
- thread_ids[i] = threads[i]->thread_id();
+ thread_ids[i] = threads[i]->GetThreadId();
threads[i]->task_runner()->PostTask(
FROM_HERE, base::Bind(&TraceManyInstantEvents, i, kNumEvents,
task_complete_events[i]));
@@ -2166,10 +2278,21 @@ TEST_F(TraceEventTestFixture, PrimitiveArgs) {
namespace {
+bool IsArgNameWhitelisted(const char* arg_name) {
+ return base::MatchPattern(arg_name, "granular_arg_whitelisted");
+}
+
bool IsTraceEventArgsWhitelisted(const char* category_group_name,
- const char* event_name) {
- if (MatchPattern(category_group_name, "toplevel") &&
- MatchPattern(event_name, "*")) {
+ const char* event_name,
+ ArgumentNameFilterPredicate* arg_filter) {
+ if (base::MatchPattern(category_group_name, "toplevel") &&
+ base::MatchPattern(event_name, "*")) {
+ return true;
+ }
+
+ if (base::MatchPattern(category_group_name, "benchmark") &&
+ base::MatchPattern(event_name, "granularly_whitelisted")) {
+ *arg_filter = base::Bind(&IsArgNameWhitelisted);
return true;
}
@@ -2188,6 +2311,11 @@ TEST_F(TraceEventTestFixture, ArgsWhitelisting) {
TRACE_EVENT1("toplevel", "event1", "int_one", 1);
TRACE_EVENT1("whitewashed", "event2", "int_two", 1);
+
+ TRACE_EVENT2("benchmark", "granularly_whitelisted",
+ "granular_arg_whitelisted", "whitelisted_value",
+ "granular_arg_blacklisted", "blacklisted_value");
+
EndTraceAndFlush();
const DictionaryValue* args_dict = NULL;
@@ -2210,6 +2338,17 @@ TEST_F(TraceEventTestFixture, ArgsWhitelisting) {
std::string args_string;
EXPECT_TRUE(dict->GetString("args", &args_string));
EXPECT_EQ(args_string, "__stripped__");
+
+ dict = FindNamePhase("granularly_whitelisted", "X");
+ ASSERT_TRUE(dict);
+ dict->GetDictionary("args", &args_dict);
+ ASSERT_TRUE(args_dict);
+
+ EXPECT_TRUE(args_dict->GetString("granular_arg_whitelisted", &args_string));
+ EXPECT_EQ(args_string, "whitelisted_value");
+
+ EXPECT_TRUE(args_dict->GetString("granular_arg_blacklisted", &args_string));
+ EXPECT_EQ(args_string, "__stripped__");
}
class TraceEventCallbackTest : public TraceEventTestFixture {
@@ -2257,10 +2396,10 @@ class TraceEventCallbackTest : public TraceEventTestFixture {
std::vector<std::string> collected_events_categories_;
std::vector<std::string> collected_events_names_;
std::vector<unsigned char> collected_events_phases_;
- std::vector<TraceTicks> collected_events_timestamps_;
+ std::vector<TimeTicks> collected_events_timestamps_;
static TraceEventCallbackTest* s_instance;
- static void Callback(TraceTicks timestamp,
+ static void Callback(TimeTicks timestamp,
char phase,
const unsigned char* category_group_enabled,
const char* name,
@@ -2269,7 +2408,7 @@ class TraceEventCallbackTest : public TraceEventTestFixture {
const char* const arg_names[],
const unsigned char arg_types[],
const unsigned long long arg_values[],
- unsigned char flags) {
+ unsigned int flags) {
s_instance->collected_events_phases_.push_back(phase);
s_instance->collected_events_categories_.push_back(
TraceLog::GetCategoryGroupName(category_group_enabled));
@@ -2443,12 +2582,12 @@ TEST_F(TraceEventTestFixture, TraceBufferVectorReportFull) {
trace_log->SetEnabled(
TraceConfig(kRecordAllCategoryFilter, ""), TraceLog::RECORDING_MODE);
trace_log->logged_events_.reset(
- trace_log->CreateTraceBufferVectorOfSize(100));
+ TraceBuffer::CreateTraceBufferVectorOfSize(100));
do {
TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0(
- "all", "with_timestamp", 0, 0, TraceTicks::Now().ToInternalValue());
+ "all", "with_timestamp", 0, 0, TimeTicks::Now().ToInternalValue());
TRACE_EVENT_END_WITH_ID_TID_AND_TIMESTAMP0(
- "all", "with_timestamp", 0, 0, TraceTicks::Now().ToInternalValue());
+ "all", "with_timestamp", 0, 0, TimeTicks::Now().ToInternalValue());
} while (!trace_log->BufferIsFull());
EndTraceAndFlush();
@@ -2490,7 +2629,7 @@ TEST_F(TraceEventTestFixture, TraceBufferRingBufferGetReturnChunk) {
TraceBuffer* buffer = TraceLog::GetInstance()->trace_buffer();
size_t capacity = buffer->Capacity();
size_t num_chunks = capacity / TraceBufferChunk::kTraceBufferChunkSize;
- uint32 last_seq = 0;
+ uint32_t last_seq = 0;
size_t chunk_index;
EXPECT_EQ(0u, buffer->Size());
@@ -2821,7 +2960,7 @@ TEST_F(TraceEventTestFixture, EchoToConsoleTraceEventRecursion) {
TEST_F(TraceEventTestFixture, TimeOffset) {
BeginTrace();
// Let TraceLog timer start from 0.
- TimeDelta time_offset = TraceTicks::Now() - TraceTicks();
+ TimeDelta time_offset = TimeTicks::Now() - TimeTicks();
TraceLog::GetInstance()->SetTimeOffset(time_offset);
{
@@ -2829,15 +2968,15 @@ TEST_F(TraceEventTestFixture, TimeOffset) {
TRACE_EVENT0("all", "duration2");
}
TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0(
- "all", "with_timestamp", 0, 0, TraceTicks::Now().ToInternalValue());
+ "all", "with_timestamp", 0, 0, TimeTicks::Now().ToInternalValue());
TRACE_EVENT_END_WITH_ID_TID_AND_TIMESTAMP0(
- "all", "with_timestamp", 0, 0, TraceTicks::Now().ToInternalValue());
+ "all", "with_timestamp", 0, 0, TimeTicks::Now().ToInternalValue());
EndTraceAndFlush();
DropTracedMetadataRecords();
double end_time = static_cast<double>(
- (TraceTicks::Now() - time_offset).ToInternalValue());
+ (TimeTicks::Now() - time_offset).ToInternalValue());
double last_timestamp = 0;
for (size_t i = 0; i < trace_parsed_.GetSize(); ++i) {
const DictionaryValue* item;
diff --git a/base/trace_event/trace_log.cc b/base/trace_event/trace_log.cc
new file mode 100644
index 0000000000..17f6b66f16
--- /dev/null
+++ b/base/trace_event/trace_log.cc
@@ -0,0 +1,1741 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/trace_log.h"
+
+#include <algorithm>
+#include <cmath>
+#include <utility>
+
+#include "base/base_switches.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/lazy_instance.h"
+#include "base/location.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.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/stringprintf.h"
+#include "base/sys_info.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread_id_name_manager.h"
+#include "base/threading/worker_pool.h"
+#include "base/time/time.h"
+#include "base/trace_event/heap_profiler_allocation_context_tracker.h"
+#include "base/trace_event/memory_dump_manager.h"
+#include "base/trace_event/memory_dump_provider.h"
+#include "base/trace_event/process_memory_dump.h"
+#include "base/trace_event/trace_buffer.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_synthetic_delay.h"
+#include "base/trace_event/trace_sampling_thread.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include "base/trace_event/trace_event_etw_export_win.h"
+#endif
+
+// The thread buckets for the sampling profiler.
+BASE_EXPORT TRACE_EVENT_API_ATOMIC_WORD g_trace_state[3];
+
+namespace base {
+namespace internal {
+
+class DeleteTraceLogForTesting {
+ public:
+ static void Delete() {
+ Singleton<trace_event::TraceLog,
+ LeakySingletonTraits<trace_event::TraceLog>>::OnExit(0);
+ }
+};
+
+} // namespace internal
+
+namespace trace_event {
+
+namespace {
+
+// Controls the number of trace events we will buffer in-memory
+// before throwing them away.
+const size_t kTraceBufferChunkSize = TraceBufferChunk::kTraceBufferChunkSize;
+
+const size_t kTraceEventVectorBigBufferChunks =
+ 512000000 / kTraceBufferChunkSize;
+static_assert(
+ kTraceEventVectorBigBufferChunks <= TraceBufferChunk::kMaxChunkIndex,
+ "Too many big buffer chunks");
+const size_t kTraceEventVectorBufferChunks = 256000 / kTraceBufferChunkSize;
+static_assert(
+ kTraceEventVectorBufferChunks <= TraceBufferChunk::kMaxChunkIndex,
+ "Too many vector buffer chunks");
+const size_t kTraceEventRingBufferChunks = kTraceEventVectorBufferChunks / 4;
+
+// Can store results for 30 seconds with 1 ms sampling interval.
+const size_t kMonitorTraceEventBufferChunks = 30000 / kTraceBufferChunkSize;
+// ECHO_TO_CONSOLE needs a small buffer to hold the unfinished COMPLETE events.
+const size_t kEchoToConsoleTraceEventBufferChunks = 256;
+
+const size_t kTraceEventBufferSizeInBytes = 100 * 1024;
+const int kThreadFlushTimeoutMs = 3000;
+
+#define MAX_CATEGORY_GROUPS 100
+
+// 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] = {
+ "toplevel",
+ "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};
+// Indexes here have to match the g_category_groups array indexes above.
+const int g_category_already_shutdown = 1;
+const int g_category_categories_exhausted = 2;
+const int g_category_metadata = 3;
+const int g_num_builtin_categories = 4;
+// Skip default categories.
+base::subtle::AtomicWord g_category_index = g_num_builtin_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<ThreadLocalPointer<const char>>::Leaky g_current_thread_name =
+ LAZY_INSTANCE_INITIALIZER;
+
+ThreadTicks ThreadNow() {
+ return ThreadTicks::IsSupported() ? ThreadTicks::Now() : ThreadTicks();
+}
+
+template <typename T>
+void InitializeMetadataEvent(TraceEvent* trace_event,
+ int thread_id,
+ const char* metadata_name,
+ const char* arg_name,
+ const T& value) {
+ if (!trace_event)
+ return;
+
+ int num_args = 1;
+ unsigned char arg_type;
+ unsigned long long arg_value;
+ ::trace_event_internal::SetTraceValue(value, &arg_type, &arg_value);
+ trace_event->Initialize(
+ thread_id,
+ TimeTicks(),
+ ThreadTicks(),
+ TRACE_EVENT_PHASE_METADATA,
+ &g_category_group_enabled[g_category_metadata],
+ metadata_name,
+ trace_event_internal::kNoId, // id
+ trace_event_internal::kNoId, // bind_id
+ num_args,
+ &arg_name,
+ &arg_type,
+ &arg_value,
+ nullptr,
+ TRACE_EVENT_FLAG_NONE);
+}
+
+class AutoThreadLocalBoolean {
+ public:
+ explicit AutoThreadLocalBoolean(ThreadLocalBoolean* thread_local_boolean)
+ : thread_local_boolean_(thread_local_boolean) {
+ DCHECK(!thread_local_boolean_->Get());
+ thread_local_boolean_->Set(true);
+ }
+ ~AutoThreadLocalBoolean() { thread_local_boolean_->Set(false); }
+
+ private:
+ ThreadLocalBoolean* thread_local_boolean_;
+ DISALLOW_COPY_AND_ASSIGN(AutoThreadLocalBoolean);
+};
+
+// Use this function instead of TraceEventHandle constructor to keep the
+// overhead of ScopedTracer (trace_event.h) constructor minimum.
+void MakeHandle(uint32_t chunk_seq,
+ size_t chunk_index,
+ size_t event_index,
+ TraceEventHandle* handle) {
+ DCHECK(chunk_seq);
+ DCHECK(chunk_index <= TraceBufferChunk::kMaxChunkIndex);
+ DCHECK(event_index < TraceBufferChunk::kTraceBufferChunkSize);
+ handle->chunk_seq = chunk_seq;
+ handle->chunk_index = static_cast<uint16_t>(chunk_index);
+ handle->event_index = static_cast<uint16_t>(event_index);
+}
+
+} // namespace
+
+// A helper class that allows the lock to be acquired in the middle of the scope
+// and unlocks at the end of scope if locked.
+class TraceLog::OptionalAutoLock {
+ public:
+ explicit OptionalAutoLock(Lock* lock) : lock_(lock), locked_(false) {}
+
+ ~OptionalAutoLock() {
+ if (locked_)
+ lock_->Release();
+ }
+
+ void EnsureAcquired() {
+ if (!locked_) {
+ lock_->Acquire();
+ locked_ = true;
+ }
+ }
+
+ private:
+ Lock* lock_;
+ bool locked_;
+ DISALLOW_COPY_AND_ASSIGN(OptionalAutoLock);
+};
+
+class TraceLog::ThreadLocalEventBuffer
+ : public MessageLoop::DestructionObserver,
+ public MemoryDumpProvider {
+ public:
+ explicit ThreadLocalEventBuffer(TraceLog* trace_log);
+ ~ThreadLocalEventBuffer() override;
+
+ TraceEvent* AddTraceEvent(TraceEventHandle* handle);
+
+ TraceEvent* GetEventByHandle(TraceEventHandle handle) {
+ if (!chunk_ || handle.chunk_seq != chunk_->seq() ||
+ handle.chunk_index != chunk_index_) {
+ return nullptr;
+ }
+
+ return chunk_->GetEventAt(handle.event_index);
+ }
+
+ int generation() const { return generation_; }
+
+ private:
+ // MessageLoop::DestructionObserver
+ void WillDestroyCurrentMessageLoop() override;
+
+ // MemoryDumpProvider implementation.
+ bool OnMemoryDump(const MemoryDumpArgs& args,
+ ProcessMemoryDump* pmd) override;
+
+ void FlushWhileLocked();
+
+ void CheckThisIsCurrentBuffer() const {
+ DCHECK(trace_log_->thread_local_event_buffer_.Get() == this);
+ }
+
+ // Since TraceLog is a leaky singleton, trace_log_ will always be valid
+ // as long as the thread exists.
+ TraceLog* trace_log_;
+ scoped_ptr<TraceBufferChunk> chunk_;
+ size_t chunk_index_;
+ int generation_;
+
+ DISALLOW_COPY_AND_ASSIGN(ThreadLocalEventBuffer);
+};
+
+TraceLog::ThreadLocalEventBuffer::ThreadLocalEventBuffer(TraceLog* trace_log)
+ : trace_log_(trace_log),
+ chunk_index_(0),
+ generation_(trace_log->generation()) {
+ // ThreadLocalEventBuffer is created only if the thread has a message loop, so
+ // the following message_loop won't be NULL.
+ MessageLoop* message_loop = MessageLoop::current();
+ message_loop->AddDestructionObserver(this);
+
+ // This is to report the local memory usage when memory-infra is enabled.
+ MemoryDumpManager::GetInstance()->RegisterDumpProvider(
+ this, "ThreadLocalEventBuffer", ThreadTaskRunnerHandle::Get());
+
+ AutoLock lock(trace_log->lock_);
+ trace_log->thread_message_loops_.insert(message_loop);
+}
+
+TraceLog::ThreadLocalEventBuffer::~ThreadLocalEventBuffer() {
+ CheckThisIsCurrentBuffer();
+ MessageLoop::current()->RemoveDestructionObserver(this);
+ MemoryDumpManager::GetInstance()->UnregisterDumpProvider(this);
+
+ {
+ AutoLock lock(trace_log_->lock_);
+ FlushWhileLocked();
+ trace_log_->thread_message_loops_.erase(MessageLoop::current());
+ }
+ trace_log_->thread_local_event_buffer_.Set(NULL);
+}
+
+TraceEvent* TraceLog::ThreadLocalEventBuffer::AddTraceEvent(
+ TraceEventHandle* handle) {
+ CheckThisIsCurrentBuffer();
+
+ if (chunk_ && chunk_->IsFull()) {
+ AutoLock lock(trace_log_->lock_);
+ FlushWhileLocked();
+ chunk_.reset();
+ }
+ if (!chunk_) {
+ AutoLock lock(trace_log_->lock_);
+ chunk_ = trace_log_->logged_events_->GetChunk(&chunk_index_);
+ trace_log_->CheckIfBufferIsFullWhileLocked();
+ }
+ if (!chunk_)
+ return NULL;
+
+ size_t event_index;
+ TraceEvent* trace_event = chunk_->AddTraceEvent(&event_index);
+ if (trace_event && handle)
+ MakeHandle(chunk_->seq(), chunk_index_, event_index, handle);
+
+ return trace_event;
+}
+
+void TraceLog::ThreadLocalEventBuffer::WillDestroyCurrentMessageLoop() {
+ delete this;
+}
+
+bool TraceLog::ThreadLocalEventBuffer::OnMemoryDump(
+ const MemoryDumpArgs& /* args */,
+ ProcessMemoryDump* pmd) {
+ if (!chunk_)
+ return true;
+ std::string dump_base_name = StringPrintf(
+ "tracing/thread_%d", static_cast<int>(PlatformThread::CurrentId()));
+ TraceEventMemoryOverhead overhead;
+ chunk_->EstimateTraceMemoryOverhead(&overhead);
+ overhead.DumpInto(dump_base_name.c_str(), pmd);
+ return true;
+}
+
+void TraceLog::ThreadLocalEventBuffer::FlushWhileLocked() {
+ if (!chunk_)
+ return;
+
+ trace_log_->lock_.AssertAcquired();
+ if (trace_log_->CheckGeneration(generation_)) {
+ // Return the chunk to the buffer only if the generation matches.
+ trace_log_->logged_events_->ReturnChunk(chunk_index_, std::move(chunk_));
+ }
+ // Otherwise this method may be called from the destructor, or TraceLog will
+ // find the generation mismatch and delete this buffer soon.
+}
+
+TraceLogStatus::TraceLogStatus() : event_capacity(0), event_count(0) {}
+
+TraceLogStatus::~TraceLogStatus() {}
+
+// static
+TraceLog* TraceLog::GetInstance() {
+ return Singleton<TraceLog, LeakySingletonTraits<TraceLog>>::get();
+}
+
+TraceLog::TraceLog()
+ : mode_(DISABLED),
+ num_traces_recorded_(0),
+ event_callback_(0),
+ dispatching_to_observer_list_(false),
+ process_sort_index_(0),
+ process_id_hash_(0),
+ process_id_(0),
+ watch_category_(0),
+ trace_options_(kInternalRecordUntilFull),
+ sampling_thread_handle_(0),
+ trace_config_(TraceConfig()),
+ event_callback_trace_config_(TraceConfig()),
+ thread_shared_chunk_index_(0),
+ generation_(0),
+ use_worker_thread_(false) {
+ // 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");
+#if defined(OS_NACL) // NaCl shouldn't expose the process id.
+ SetProcessID(0);
+#else
+ SetProcessID(static_cast<int>(GetCurrentProcId()));
+#endif
+
+ logged_events_.reset(CreateTraceBuffer());
+
+ MemoryDumpManager::GetInstance()->RegisterDumpProvider(this, "TraceLog",
+ nullptr);
+}
+
+TraceLog::~TraceLog() {}
+
+void TraceLog::InitializeThreadLocalEventBufferIfSupported() {
+ // A ThreadLocalEventBuffer needs the message loop
+ // - to know when the thread exits;
+ // - to handle the final flush.
+ // For a thread without a message loop or the message loop may be blocked, the
+ // trace events will be added into the main buffer directly.
+ if (thread_blocks_message_loop_.Get() || !MessageLoop::current())
+ return;
+ auto thread_local_event_buffer = thread_local_event_buffer_.Get();
+ if (thread_local_event_buffer &&
+ !CheckGeneration(thread_local_event_buffer->generation())) {
+ delete thread_local_event_buffer;
+ thread_local_event_buffer = NULL;
+ }
+ if (!thread_local_event_buffer) {
+ thread_local_event_buffer = new ThreadLocalEventBuffer(this);
+ thread_local_event_buffer_.Set(thread_local_event_buffer);
+ }
+}
+
+bool TraceLog::OnMemoryDump(const MemoryDumpArgs& /* args */,
+ ProcessMemoryDump* pmd) {
+ // TODO(ssid): Use MemoryDumpArgs to create light dumps when requested
+ // (crbug.com/499731).
+ TraceEventMemoryOverhead overhead;
+ overhead.Add("TraceLog", sizeof(*this));
+ {
+ AutoLock lock(lock_);
+ if (logged_events_)
+ logged_events_->EstimateTraceMemoryOverhead(&overhead);
+
+ for (auto& metadata_event : metadata_events_)
+ metadata_event->EstimateTraceMemoryOverhead(&overhead);
+ }
+ overhead.AddSelf();
+ overhead.DumpInto("tracing/main_trace_log", pmd);
+ return true;
+}
+
+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<uintptr_t>(g_category_group_enabled);
+ uintptr_t category_ptr = reinterpret_cast<uintptr_t>(category_group_enabled);
+ DCHECK(category_ptr >= category_begin &&
+ category_ptr < reinterpret_cast<uintptr_t>(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(size_t category_index) {
+ unsigned char enabled_flag = 0;
+ const char* category_group = g_category_groups[category_index];
+ if (mode_ == RECORDING_MODE &&
+ trace_config_.IsCategoryGroupEnabled(category_group))
+ enabled_flag |= ENABLED_FOR_RECORDING;
+ else if (mode_ == MONITORING_MODE &&
+ trace_config_.IsCategoryGroupEnabled(category_group))
+ enabled_flag |= ENABLED_FOR_MONITORING;
+ if (event_callback_ &&
+ event_callback_trace_config_.IsCategoryGroupEnabled(category_group))
+ enabled_flag |= ENABLED_FOR_EVENT_CALLBACK;
+#if defined(OS_WIN)
+ if (base::trace_event::TraceEventETWExport::IsCategoryGroupEnabled(
+ category_group)) {
+ enabled_flag |= ENABLED_FOR_ETW_EXPORT;
+ }
+#endif
+
+ g_category_group_enabled[category_index] = enabled_flag;
+}
+
+void TraceLog::UpdateCategoryGroupEnabledFlags() {
+ size_t category_index = base::subtle::NoBarrier_Load(&g_category_index);
+ for (size_t i = 0; i < category_index; i++)
+ UpdateCategoryGroupEnabledFlag(i);
+}
+
+void TraceLog::UpdateSyntheticDelaysFromTraceConfig() {
+ ResetTraceEventSyntheticDelays();
+ const TraceConfig::StringList& delays =
+ trace_config_.GetSyntheticDelayValues();
+ TraceConfig::StringList::const_iterator ci;
+ for (ci = delays.begin(); ci != delays.end(); ++ci) {
+ StringTokenizer tokens(*ci, ";");
+ if (!tokens.GetNext())
+ continue;
+ TraceEventSyntheticDelay* delay =
+ TraceEventSyntheticDelay::Lookup(tokens.token());
+ while (tokens.GetNext()) {
+ std::string token = tokens.token();
+ char* duration_end;
+ double target_duration = strtod(token.c_str(), &duration_end);
+ if (duration_end != token.c_str()) {
+ delay->SetTargetDuration(TimeDelta::FromMicroseconds(
+ static_cast<int64_t>(target_duration * 1e6)));
+ } else if (token == "static") {
+ delay->SetMode(TraceEventSyntheticDelay::STATIC);
+ } else if (token == "oneshot") {
+ delay->SetMode(TraceEventSyntheticDelay::ONE_SHOT);
+ } else if (token == "alternating") {
+ delay->SetMode(TraceEventSyntheticDelay::ALTERNATING);
+ }
+ }
+ }
+}
+
+const unsigned char* TraceLog::GetCategoryGroupEnabledInternal(
+ const char* category_group) {
+ DCHECK(!strchr(category_group, '"'))
+ << "Category groups may not contain double quote";
+ // The g_category_groups is append only, avoid using a lock for the fast path.
+ size_t current_category_index = base::subtle::Acquire_Load(&g_category_index);
+
+ // Search for pre-existing category group.
+ for (size_t i = 0; i < current_category_index; ++i) {
+ if (strcmp(g_category_groups[i], category_group) == 0) {
+ return &g_category_group_enabled[i];
+ }
+ }
+
+ unsigned char* category_group_enabled = NULL;
+ // This is the slow path: the lock is not held in the case above, so more
+ // than one thread could have reached here trying to add the same category.
+ // Only hold to lock when actually appending a new category, and
+ // check the categories groups again.
+ AutoLock lock(lock_);
+ size_t category_index = base::subtle::Acquire_Load(&g_category_index);
+ for (size_t i = 0; i < category_index; ++i) {
+ if (strcmp(g_category_groups[i], category_group) == 0) {
+ return &g_category_group_enabled[i];
+ }
+ }
+
+ // Create a new category group.
+ DCHECK(category_index < MAX_CATEGORY_GROUPS)
+ << "must increase MAX_CATEGORY_GROUPS";
+ if (category_index < MAX_CATEGORY_GROUPS) {
+ // 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);
+ g_category_groups[category_index] = new_group;
+ DCHECK(!g_category_group_enabled[category_index]);
+ // Note that if both included and excluded patterns in the
+ // TraceConfig are empty, we exclude nothing,
+ // thereby enabling this category group.
+ UpdateCategoryGroupEnabledFlag(category_index);
+ category_group_enabled = &g_category_group_enabled[category_index];
+ // Update the max index now.
+ base::subtle::Release_Store(&g_category_index, category_index + 1);
+ } else {
+ category_group_enabled =
+ &g_category_group_enabled[g_category_categories_exhausted];
+ }
+ return category_group_enabled;
+}
+
+void TraceLog::GetKnownCategoryGroups(
+ std::vector<std::string>* category_groups) {
+ AutoLock lock(lock_);
+ size_t category_index = base::subtle::NoBarrier_Load(&g_category_index);
+ for (size_t i = g_num_builtin_categories; i < category_index; i++)
+ category_groups->push_back(g_category_groups[i]);
+}
+
+void TraceLog::SetEnabled(const TraceConfig& trace_config, Mode mode) {
+ std::vector<EnabledStateObserver*> observer_list;
+ {
+ AutoLock lock(lock_);
+
+ // Can't enable tracing when Flush() is in progress.
+ DCHECK(!flush_task_runner_);
+
+ InternalTraceOptions new_options =
+ GetInternalOptionsFromTraceConfig(trace_config);
+
+ InternalTraceOptions old_options = trace_options();
+
+ if (IsEnabled()) {
+ if (new_options != old_options) {
+ DLOG(ERROR) << "Attempting to re-enable tracing with a different "
+ << "set of options.";
+ }
+
+ if (mode != mode_) {
+ DLOG(ERROR) << "Attempting to re-enable tracing with a different mode.";
+ }
+
+ trace_config_.Merge(trace_config);
+ UpdateCategoryGroupEnabledFlags();
+ return;
+ }
+
+ if (dispatching_to_observer_list_) {
+ DLOG(ERROR)
+ << "Cannot manipulate TraceLog::Enabled state from an observer.";
+ return;
+ }
+
+ mode_ = mode;
+
+ if (new_options != old_options) {
+ subtle::NoBarrier_Store(&trace_options_, new_options);
+ UseNextTraceBuffer();
+ }
+
+ num_traces_recorded_++;
+
+ trace_config_ = TraceConfig(trace_config);
+ UpdateCategoryGroupEnabledFlags();
+ UpdateSyntheticDelaysFromTraceConfig();
+
+ if (new_options & kInternalEnableSampling) {
+ sampling_thread_.reset(new TraceSamplingThread);
+ sampling_thread_->RegisterSampleBucket(
+ &g_trace_state[0], "bucket0",
+ Bind(&TraceSamplingThread::DefaultSamplingCallback));
+ sampling_thread_->RegisterSampleBucket(
+ &g_trace_state[1], "bucket1",
+ Bind(&TraceSamplingThread::DefaultSamplingCallback));
+ sampling_thread_->RegisterSampleBucket(
+ &g_trace_state[2], "bucket2",
+ Bind(&TraceSamplingThread::DefaultSamplingCallback));
+ 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;
+ }
+}
+
+void TraceLog::SetArgumentFilterPredicate(
+ const ArgumentFilterPredicate& argument_filter_predicate) {
+ AutoLock lock(lock_);
+ DCHECK(!argument_filter_predicate.is_null());
+ DCHECK(argument_filter_predicate_.is_null());
+ argument_filter_predicate_ = argument_filter_predicate;
+}
+
+TraceLog::InternalTraceOptions TraceLog::GetInternalOptionsFromTraceConfig(
+ const TraceConfig& config) {
+ InternalTraceOptions ret =
+ config.IsSamplingEnabled() ? kInternalEnableSampling : kInternalNone;
+ if (config.IsArgumentFilterEnabled())
+ ret |= kInternalEnableArgumentFilter;
+ switch (config.GetTraceRecordMode()) {
+ case RECORD_UNTIL_FULL:
+ return ret | kInternalRecordUntilFull;
+ case RECORD_CONTINUOUSLY:
+ return ret | kInternalRecordContinuously;
+ case ECHO_TO_CONSOLE:
+ return ret | kInternalEchoToConsole;
+ case RECORD_AS_MUCH_AS_POSSIBLE:
+ return ret | kInternalRecordAsMuchAsPossible;
+ }
+ NOTREACHED();
+ return kInternalNone;
+}
+
+TraceConfig TraceLog::GetCurrentTraceConfig() const {
+ AutoLock lock(lock_);
+ return trace_config_;
+}
+
+void TraceLog::SetDisabled() {
+ AutoLock lock(lock_);
+ SetDisabledWhileLocked();
+}
+
+void TraceLog::SetDisabledWhileLocked() {
+ lock_.AssertAcquired();
+
+ if (!IsEnabled())
+ return;
+
+ if (dispatching_to_observer_list_) {
+ DLOG(ERROR)
+ << "Cannot manipulate TraceLog::Enabled state from an observer.";
+ return;
+ }
+
+ mode_ = DISABLED;
+
+ 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();
+ }
+
+ trace_config_.Clear();
+ subtle::NoBarrier_Store(&watch_category_, 0);
+ watch_event_name_ = "";
+ UpdateCategoryGroupEnabledFlags();
+ AddMetadataEventsWhileLocked();
+
+ // Remove metadata events so they will not get added to a subsequent trace.
+ metadata_events_.clear();
+
+ dispatching_to_observer_list_ = true;
+ std::vector<EnabledStateObserver*> observer_list =
+ enabled_state_observer_list_;
+
+ {
+ // Dispatch to observers outside the lock in case the observer triggers a
+ // trace event.
+ AutoUnlock unlock(lock_);
+ for (size_t i = 0; i < observer_list.size(); ++i)
+ observer_list[i]->OnTraceLogDisabled();
+ }
+ dispatching_to_observer_list_ = false;
+}
+
+int TraceLog::GetNumTracesRecorded() {
+ AutoLock lock(lock_);
+ if (!IsEnabled())
+ return -1;
+ return num_traces_recorded_;
+}
+
+void TraceLog::AddEnabledStateObserver(EnabledStateObserver* listener) {
+ AutoLock lock(lock_);
+ enabled_state_observer_list_.push_back(listener);
+}
+
+void TraceLog::RemoveEnabledStateObserver(EnabledStateObserver* listener) {
+ AutoLock lock(lock_);
+ std::vector<EnabledStateObserver*>::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 {
+ AutoLock lock(lock_);
+ return ContainsValue(enabled_state_observer_list_, listener);
+}
+
+TraceLogStatus TraceLog::GetStatus() const {
+ AutoLock lock(lock_);
+ TraceLogStatus result;
+ result.event_capacity = logged_events_->Capacity();
+ result.event_count = logged_events_->Size();
+ return result;
+}
+
+bool TraceLog::BufferIsFull() const {
+ AutoLock lock(lock_);
+ return logged_events_->IsFull();
+}
+
+TraceEvent* TraceLog::AddEventToThreadSharedChunkWhileLocked(
+ TraceEventHandle* handle,
+ bool check_buffer_is_full) {
+ lock_.AssertAcquired();
+
+ if (thread_shared_chunk_ && thread_shared_chunk_->IsFull()) {
+ logged_events_->ReturnChunk(thread_shared_chunk_index_,
+ std::move(thread_shared_chunk_));
+ }
+
+ if (!thread_shared_chunk_) {
+ thread_shared_chunk_ =
+ logged_events_->GetChunk(&thread_shared_chunk_index_);
+ if (check_buffer_is_full)
+ CheckIfBufferIsFullWhileLocked();
+ }
+ if (!thread_shared_chunk_)
+ return NULL;
+
+ size_t event_index;
+ TraceEvent* trace_event = thread_shared_chunk_->AddTraceEvent(&event_index);
+ if (trace_event && handle) {
+ MakeHandle(thread_shared_chunk_->seq(), thread_shared_chunk_index_,
+ event_index, handle);
+ }
+ return trace_event;
+}
+
+void TraceLog::CheckIfBufferIsFullWhileLocked() {
+ lock_.AssertAcquired();
+ if (logged_events_->IsFull()) {
+ if (buffer_limit_reached_timestamp_.is_null()) {
+ buffer_limit_reached_timestamp_ = OffsetNow();
+ }
+ SetDisabledWhileLocked();
+ }
+}
+
+void TraceLog::SetEventCallbackEnabled(const TraceConfig& trace_config,
+ EventCallback cb) {
+ AutoLock lock(lock_);
+ subtle::NoBarrier_Store(&event_callback_,
+ reinterpret_cast<subtle::AtomicWord>(cb));
+ event_callback_trace_config_ = trace_config;
+ UpdateCategoryGroupEnabledFlags();
+}
+
+void TraceLog::SetEventCallbackDisabled() {
+ AutoLock lock(lock_);
+ subtle::NoBarrier_Store(&event_callback_, 0);
+ UpdateCategoryGroupEnabledFlags();
+}
+
+// Flush() works as the following:
+// 1. Flush() is called in thread A whose task runner is saved in
+// flush_task_runner_;
+// 2. If thread_message_loops_ is not empty, thread A posts task to each message
+// loop to flush the thread local buffers; otherwise finish the flush;
+// 3. FlushCurrentThread() deletes the thread local event buffer:
+// - The last batch of events of the thread are flushed into the main buffer;
+// - The message loop will be removed from thread_message_loops_;
+// If this is the last message loop, finish the flush;
+// 4. If any thread hasn't finish its flush in time, finish the flush.
+void TraceLog::Flush(const TraceLog::OutputCallback& cb,
+ bool use_worker_thread) {
+ FlushInternal(cb, use_worker_thread, false);
+}
+
+void TraceLog::CancelTracing(const OutputCallback& cb) {
+ SetDisabled();
+ FlushInternal(cb, false, true);
+}
+
+void TraceLog::FlushInternal(const TraceLog::OutputCallback& cb,
+ bool use_worker_thread,
+ bool discard_events) {
+ use_worker_thread_ = use_worker_thread;
+ if (IsEnabled()) {
+ // Can't flush when tracing is enabled because otherwise PostTask would
+ // - generate more trace events;
+ // - deschedule the calling thread on some platforms causing inaccurate
+ // timing of the trace events.
+ scoped_refptr<RefCountedString> empty_result = new RefCountedString;
+ if (!cb.is_null())
+ cb.Run(empty_result, false);
+ LOG(WARNING) << "Ignored TraceLog::Flush called when tracing is enabled";
+ return;
+ }
+
+ int generation = this->generation();
+ // Copy of thread_message_loops_ to be used without locking.
+ std::vector<scoped_refptr<SingleThreadTaskRunner>>
+ thread_message_loop_task_runners;
+ {
+ AutoLock lock(lock_);
+ DCHECK(!flush_task_runner_);
+ flush_task_runner_ = ThreadTaskRunnerHandle::IsSet()
+ ? ThreadTaskRunnerHandle::Get()
+ : nullptr;
+ DCHECK(!thread_message_loops_.size() || flush_task_runner_);
+ flush_output_callback_ = cb;
+
+ if (thread_shared_chunk_) {
+ logged_events_->ReturnChunk(thread_shared_chunk_index_,
+ std::move(thread_shared_chunk_));
+ }
+
+ if (thread_message_loops_.size()) {
+ for (hash_set<MessageLoop*>::const_iterator it =
+ thread_message_loops_.begin();
+ it != thread_message_loops_.end(); ++it) {
+ thread_message_loop_task_runners.push_back((*it)->task_runner());
+ }
+ }
+ }
+
+ if (thread_message_loop_task_runners.size()) {
+ for (size_t i = 0; i < thread_message_loop_task_runners.size(); ++i) {
+ thread_message_loop_task_runners[i]->PostTask(
+ FROM_HERE, Bind(&TraceLog::FlushCurrentThread, Unretained(this),
+ generation, discard_events));
+ }
+ flush_task_runner_->PostDelayedTask(
+ FROM_HERE, Bind(&TraceLog::OnFlushTimeout, Unretained(this), generation,
+ discard_events),
+ TimeDelta::FromMilliseconds(kThreadFlushTimeoutMs));
+ return;
+ }
+
+ FinishFlush(generation, discard_events);
+}
+
+// Usually it runs on a different thread.
+void TraceLog::ConvertTraceEventsToTraceFormat(
+ scoped_ptr<TraceBuffer> logged_events,
+ const OutputCallback& flush_output_callback,
+ const ArgumentFilterPredicate& argument_filter_predicate) {
+ if (flush_output_callback.is_null())
+ return;
+
+ // The callback need to be called at least once even if there is no events
+ // to let the caller know the completion of flush.
+ scoped_refptr<RefCountedString> json_events_str_ptr = new RefCountedString();
+ while (const TraceBufferChunk* chunk = logged_events->NextChunk()) {
+ for (size_t j = 0; j < chunk->size(); ++j) {
+ size_t size = json_events_str_ptr->size();
+ if (size > kTraceEventBufferSizeInBytes) {
+ flush_output_callback.Run(json_events_str_ptr, true);
+ json_events_str_ptr = new RefCountedString();
+ } else if (size) {
+ json_events_str_ptr->data().append(",\n");
+ }
+ chunk->GetEventAt(j)->AppendAsJSON(&(json_events_str_ptr->data()),
+ argument_filter_predicate);
+ }
+ }
+ flush_output_callback.Run(json_events_str_ptr, false);
+}
+
+void TraceLog::FinishFlush(int generation, bool discard_events) {
+ scoped_ptr<TraceBuffer> previous_logged_events;
+ OutputCallback flush_output_callback;
+ ArgumentFilterPredicate argument_filter_predicate;
+
+ if (!CheckGeneration(generation))
+ return;
+
+ {
+ AutoLock lock(lock_);
+
+ previous_logged_events.swap(logged_events_);
+ UseNextTraceBuffer();
+ thread_message_loops_.clear();
+
+ flush_task_runner_ = NULL;
+ flush_output_callback = flush_output_callback_;
+ flush_output_callback_.Reset();
+
+ if (trace_options() & kInternalEnableArgumentFilter) {
+ CHECK(!argument_filter_predicate_.is_null());
+ argument_filter_predicate = argument_filter_predicate_;
+ }
+ }
+
+ if (discard_events) {
+ if (!flush_output_callback.is_null()) {
+ scoped_refptr<RefCountedString> empty_result = new RefCountedString;
+ flush_output_callback.Run(empty_result, false);
+ }
+ return;
+ }
+
+ if (use_worker_thread_ &&
+ WorkerPool::PostTask(
+ FROM_HERE, Bind(&TraceLog::ConvertTraceEventsToTraceFormat,
+ Passed(&previous_logged_events),
+ flush_output_callback, argument_filter_predicate),
+ true)) {
+ return;
+ }
+
+ ConvertTraceEventsToTraceFormat(std::move(previous_logged_events),
+ flush_output_callback,
+ argument_filter_predicate);
+}
+
+// Run in each thread holding a local event buffer.
+void TraceLog::FlushCurrentThread(int generation, bool discard_events) {
+ {
+ AutoLock lock(lock_);
+ if (!CheckGeneration(generation) || !flush_task_runner_) {
+ // This is late. The corresponding flush has finished.
+ return;
+ }
+ }
+
+ // This will flush the thread local buffer.
+ delete thread_local_event_buffer_.Get();
+
+ AutoLock lock(lock_);
+ if (!CheckGeneration(generation) || !flush_task_runner_ ||
+ thread_message_loops_.size())
+ return;
+
+ flush_task_runner_->PostTask(
+ FROM_HERE, Bind(&TraceLog::FinishFlush, Unretained(this), generation,
+ discard_events));
+}
+
+void TraceLog::OnFlushTimeout(int generation, bool discard_events) {
+ {
+ AutoLock lock(lock_);
+ if (!CheckGeneration(generation) || !flush_task_runner_) {
+ // Flush has finished before timeout.
+ return;
+ }
+
+ LOG(WARNING)
+ << "The following threads haven't finished flush in time. "
+ "If this happens stably for some thread, please call "
+ "TraceLog::GetInstance()->SetCurrentThreadBlocksMessageLoop() from "
+ "the thread to avoid its trace events from being lost.";
+ for (hash_set<MessageLoop*>::const_iterator it =
+ thread_message_loops_.begin();
+ it != thread_message_loops_.end(); ++it) {
+ LOG(WARNING) << "Thread: " << (*it)->thread_name();
+ }
+ }
+ FinishFlush(generation, discard_events);
+}
+
+void TraceLog::FlushButLeaveBufferIntact(
+ const TraceLog::OutputCallback& flush_output_callback) {
+ scoped_ptr<TraceBuffer> previous_logged_events;
+ ArgumentFilterPredicate argument_filter_predicate;
+ {
+ AutoLock lock(lock_);
+ AddMetadataEventsWhileLocked();
+ if (thread_shared_chunk_) {
+ // Return the chunk to the main buffer to flush the sampling data.
+ logged_events_->ReturnChunk(thread_shared_chunk_index_,
+ std::move(thread_shared_chunk_));
+ }
+ previous_logged_events = logged_events_->CloneForIteration();
+
+ if (trace_options() & kInternalEnableArgumentFilter) {
+ CHECK(!argument_filter_predicate_.is_null());
+ argument_filter_predicate = argument_filter_predicate_;
+ }
+ } // release lock
+
+ ConvertTraceEventsToTraceFormat(std::move(previous_logged_events),
+ flush_output_callback,
+ argument_filter_predicate);
+}
+
+void TraceLog::UseNextTraceBuffer() {
+ logged_events_.reset(CreateTraceBuffer());
+ subtle::NoBarrier_AtomicIncrement(&generation_, 1);
+ thread_shared_chunk_.reset();
+ thread_shared_chunk_index_ = 0;
+}
+
+TraceEventHandle 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,
+ const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
+ unsigned int flags) {
+ int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
+ base::TimeTicks now = base::TimeTicks::Now();
+ return AddTraceEventWithThreadIdAndTimestamp(
+ phase,
+ category_group_enabled,
+ name,
+ id,
+ trace_event_internal::kNoId, // bind_id
+ thread_id,
+ now,
+ num_args,
+ arg_names,
+ arg_types,
+ arg_values,
+ convertable_values,
+ flags);
+}
+
+TraceEventHandle TraceLog::AddTraceEventWithBindId(
+ char phase,
+ const unsigned char* category_group_enabled,
+ const char* name,
+ unsigned long long id,
+ unsigned long long bind_id,
+ int num_args,
+ const char** arg_names,
+ const unsigned char* arg_types,
+ const unsigned long long* arg_values,
+ const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
+ unsigned int flags) {
+ int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
+ base::TimeTicks now = base::TimeTicks::Now();
+ return AddTraceEventWithThreadIdAndTimestamp(
+ phase,
+ category_group_enabled,
+ name,
+ id,
+ bind_id,
+ thread_id,
+ now,
+ num_args,
+ arg_names,
+ arg_types,
+ arg_values,
+ convertable_values,
+ flags | TRACE_EVENT_FLAG_HAS_CONTEXT_ID);
+}
+
+TraceEventHandle TraceLog::AddTraceEventWithProcessId(
+ char phase,
+ const unsigned char* category_group_enabled,
+ const char* name,
+ unsigned long long id,
+ int process_id,
+ int num_args,
+ const char** arg_names,
+ const unsigned char* arg_types,
+ const unsigned long long* arg_values,
+ const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
+ unsigned int flags) {
+ base::TimeTicks now = base::TimeTicks::Now();
+ return AddTraceEventWithThreadIdAndTimestamp(
+ phase,
+ category_group_enabled,
+ name,
+ id,
+ trace_event_internal::kNoId, // bind_id
+ process_id,
+ now,
+ num_args,
+ arg_names,
+ arg_types,
+ arg_values,
+ convertable_values,
+ flags | TRACE_EVENT_FLAG_HAS_PROCESS_ID);
+}
+
+// Handle legacy calls to AddTraceEventWithThreadIdAndTimestamp
+// with kNoId as bind_id
+TraceEventHandle 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,
+ const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
+ unsigned int flags) {
+ return AddTraceEventWithThreadIdAndTimestamp(
+ phase,
+ category_group_enabled,
+ name,
+ id,
+ trace_event_internal::kNoId, // bind_id
+ thread_id,
+ timestamp,
+ num_args,
+ arg_names,
+ arg_types,
+ arg_values,
+ convertable_values,
+ flags);
+}
+
+TraceEventHandle TraceLog::AddTraceEventWithThreadIdAndTimestamp(
+ char phase,
+ const unsigned char* category_group_enabled,
+ const char* name,
+ unsigned long long id,
+ unsigned long long bind_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,
+ const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
+ unsigned int flags) {
+ TraceEventHandle handle = {0, 0, 0};
+ if (!*category_group_enabled)
+ return handle;
+
+ // Avoid re-entrance of AddTraceEvent. This may happen in GPU process when
+ // ECHO_TO_CONSOLE is enabled: AddTraceEvent -> LOG(ERROR) ->
+ // GpuProcessLogMessageHandler -> PostPendingTask -> TRACE_EVENT ...
+ if (thread_is_in_trace_event_.Get())
+ return handle;
+
+ AutoThreadLocalBoolean thread_is_in_trace_event(&thread_is_in_trace_event_);
+
+ DCHECK(name);
+ DCHECK(!timestamp.is_null());
+
+ if (flags & TRACE_EVENT_FLAG_MANGLE_ID) {
+ if ((flags & TRACE_EVENT_FLAG_FLOW_IN) ||
+ (flags & TRACE_EVENT_FLAG_FLOW_OUT))
+ bind_id = MangleEventId(bind_id);
+ id = MangleEventId(id);
+ }
+
+ TimeTicks offset_event_timestamp = OffsetTimestamp(timestamp);
+ ThreadTicks thread_now = ThreadNow();
+
+ // |thread_local_event_buffer_| can be null if the current thread doesn't have
+ // a message loop or the message loop is blocked.
+ InitializeThreadLocalEventBufferIfSupported();
+ auto thread_local_event_buffer = thread_local_event_buffer_.Get();
+
+ // 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<int>(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 thread_info_lock(thread_info_lock_);
+
+ hash_map<int, std::string>::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<StringPiece> existing_names = base::SplitStringPiece(
+ existing_name->second, ",", base::KEEP_WHITESPACE,
+ base::SPLIT_WANT_NONEMPTY);
+ bool found = std::find(existing_names.begin(), existing_names.end(),
+ new_name) != existing_names.end();
+ if (!found) {
+ if (existing_names.size())
+ existing_name->second.push_back(',');
+ existing_name->second.append(new_name);
+ }
+ }
+ }
+ }
+
+#if defined(OS_WIN)
+ // This is done sooner rather than later, to avoid creating the event and
+ // acquiring the lock, which is not needed for ETW as it's already threadsafe.
+ if (*category_group_enabled & ENABLED_FOR_ETW_EXPORT)
+ TraceEventETWExport::AddEvent(phase, category_group_enabled, name, id,
+ num_args, arg_names, arg_types, arg_values,
+ convertable_values);
+#endif // OS_WIN
+
+ std::string console_message;
+ if (*category_group_enabled &
+ (ENABLED_FOR_RECORDING | ENABLED_FOR_MONITORING)) {
+ OptionalAutoLock lock(&lock_);
+
+ TraceEvent* trace_event = NULL;
+ if (thread_local_event_buffer) {
+ trace_event = thread_local_event_buffer->AddTraceEvent(&handle);
+ } else {
+ lock.EnsureAcquired();
+ trace_event = AddEventToThreadSharedChunkWhileLocked(&handle, true);
+ }
+
+ if (trace_event) {
+ trace_event->Initialize(thread_id,
+ offset_event_timestamp,
+ thread_now,
+ phase,
+ category_group_enabled,
+ name,
+ id,
+ bind_id,
+ num_args,
+ arg_names,
+ arg_types,
+ arg_values,
+ convertable_values,
+ flags);
+
+#if defined(OS_ANDROID)
+ trace_event->SendToATrace();
+#endif
+ }
+
+ if (trace_options() & kInternalEchoToConsole) {
+ console_message = EventToConsoleMessage(
+ phase == TRACE_EVENT_PHASE_COMPLETE ? TRACE_EVENT_PHASE_BEGIN : phase,
+ timestamp, trace_event);
+ }
+ }
+
+ if (console_message.size())
+ LOG(ERROR) << console_message;
+
+ if (reinterpret_cast<const unsigned char*>(
+ subtle::NoBarrier_Load(&watch_category_)) == category_group_enabled) {
+ bool event_name_matches;
+ WatchEventCallback watch_event_callback_copy;
+ {
+ AutoLock lock(lock_);
+ event_name_matches = watch_event_name_ == name;
+ watch_event_callback_copy = watch_event_callback_;
+ }
+ if (event_name_matches) {
+ if (!watch_event_callback_copy.is_null())
+ watch_event_callback_copy.Run();
+ }
+ }
+
+ if (*category_group_enabled & ENABLED_FOR_EVENT_CALLBACK) {
+ EventCallback event_callback = reinterpret_cast<EventCallback>(
+ subtle::NoBarrier_Load(&event_callback_));
+ if (event_callback) {
+ event_callback(
+ offset_event_timestamp,
+ phase == TRACE_EVENT_PHASE_COMPLETE ? TRACE_EVENT_PHASE_BEGIN : phase,
+ category_group_enabled, name, id, num_args, arg_names, arg_types,
+ arg_values, flags);
+ }
+ }
+
+ if (base::trace_event::AllocationContextTracker::capture_enabled()) {
+ if (phase == TRACE_EVENT_PHASE_BEGIN || phase == TRACE_EVENT_PHASE_COMPLETE)
+ base::trace_event::AllocationContextTracker::PushPseudoStackFrame(name);
+ else if (phase == TRACE_EVENT_PHASE_END)
+ // The pop for |TRACE_EVENT_PHASE_COMPLETE| events
+ // is in |TraceLog::UpdateTraceEventDuration|.
+ base::trace_event::AllocationContextTracker::PopPseudoStackFrame(name);
+ }
+
+ return handle;
+}
+
+void TraceLog::AddMetadataEvent(
+ const char* name,
+ int num_args,
+ const char** arg_names,
+ const unsigned char* arg_types,
+ const unsigned long long* arg_values,
+ const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
+ unsigned int flags) {
+ scoped_ptr<TraceEvent> trace_event(new TraceEvent);
+ AutoLock lock(lock_);
+ trace_event->Initialize(
+ 0, // thread_id
+ TimeTicks(), ThreadTicks(), TRACE_EVENT_PHASE_METADATA,
+ &g_category_group_enabled[g_category_metadata], name,
+ trace_event_internal::kNoId, // id
+ trace_event_internal::kNoId, // bind_id
+ num_args, arg_names, arg_types, arg_values, convertable_values, flags);
+ metadata_events_.push_back(std::move(trace_event));
+}
+
+// May be called when a COMPELETE event ends and the unfinished event has been
+// recycled (phase == TRACE_EVENT_PHASE_END and trace_event == NULL).
+std::string TraceLog::EventToConsoleMessage(unsigned char phase,
+ const TimeTicks& timestamp,
+ TraceEvent* trace_event) {
+ AutoLock thread_info_lock(thread_info_lock_);
+
+ // The caller should translate TRACE_EVENT_PHASE_COMPLETE to
+ // TRACE_EVENT_PHASE_BEGIN or TRACE_EVENT_END.
+ DCHECK(phase != TRACE_EVENT_PHASE_COMPLETE);
+
+ TimeDelta duration;
+ int thread_id =
+ trace_event ? trace_event->thread_id() : PlatformThread::CurrentId();
+ 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 << "| ";
+
+ if (trace_event)
+ trace_event->AppendPrettyPrinted(&log);
+ if (phase == TRACE_EVENT_PHASE_END)
+ log << base::StringPrintf(" (%.3f ms)", duration.InMillisecondsF());
+
+ log << "\x1b[0;m";
+
+ if (phase == TRACE_EVENT_PHASE_BEGIN)
+ thread_event_start_times_[thread_id].push(timestamp);
+
+ return log.str();
+}
+
+void TraceLog::UpdateTraceEventDuration(
+ const unsigned char* category_group_enabled,
+ const char* name,
+ TraceEventHandle handle) {
+ char category_group_enabled_local = *category_group_enabled;
+ if (!category_group_enabled_local)
+ return;
+
+ // Avoid re-entrance of AddTraceEvent. This may happen in GPU process when
+ // ECHO_TO_CONSOLE is enabled: AddTraceEvent -> LOG(ERROR) ->
+ // GpuProcessLogMessageHandler -> PostPendingTask -> TRACE_EVENT ...
+ if (thread_is_in_trace_event_.Get())
+ return;
+
+ AutoThreadLocalBoolean thread_is_in_trace_event(&thread_is_in_trace_event_);
+
+ ThreadTicks thread_now = ThreadNow();
+ TimeTicks now = OffsetNow();
+
+#if defined(OS_WIN)
+ // Generate an ETW event that marks the end of a complete event.
+ if (category_group_enabled_local & ENABLED_FOR_ETW_EXPORT)
+ TraceEventETWExport::AddCompleteEndEvent(name);
+#endif // OS_WIN
+
+ std::string console_message;
+ if (category_group_enabled_local & ENABLED_FOR_RECORDING) {
+ OptionalAutoLock lock(&lock_);
+
+ TraceEvent* trace_event = GetEventByHandleInternal(handle, &lock);
+ if (trace_event) {
+ DCHECK(trace_event->phase() == TRACE_EVENT_PHASE_COMPLETE);
+ trace_event->UpdateDuration(now, thread_now);
+#if defined(OS_ANDROID)
+ trace_event->SendToATrace();
+#endif
+ }
+
+ if (trace_options() & kInternalEchoToConsole) {
+ console_message =
+ EventToConsoleMessage(TRACE_EVENT_PHASE_END, now, trace_event);
+ }
+
+ if (base::trace_event::AllocationContextTracker::capture_enabled()) {
+ // The corresponding push is in |AddTraceEventWithThreadIdAndTimestamp|.
+ base::trace_event::AllocationContextTracker::PopPseudoStackFrame(name);
+ }
+ }
+
+ if (console_message.size())
+ LOG(ERROR) << console_message;
+
+ if (category_group_enabled_local & ENABLED_FOR_EVENT_CALLBACK) {
+ EventCallback event_callback = reinterpret_cast<EventCallback>(
+ subtle::NoBarrier_Load(&event_callback_));
+ if (event_callback) {
+ event_callback(now, TRACE_EVENT_PHASE_END, category_group_enabled, name,
+ trace_event_internal::kNoId, 0,
+ nullptr, nullptr, nullptr, TRACE_EVENT_FLAG_NONE);
+ }
+ }
+}
+
+void TraceLog::SetWatchEvent(const std::string& category_name,
+ const std::string& event_name,
+ const WatchEventCallback& callback) {
+ const unsigned char* category =
+ GetCategoryGroupEnabled(category_name.c_str());
+ AutoLock lock(lock_);
+ subtle::NoBarrier_Store(&watch_category_,
+ reinterpret_cast<subtle::AtomicWord>(category));
+ watch_event_name_ = event_name;
+ watch_event_callback_ = callback;
+}
+
+void TraceLog::CancelWatchEvent() {
+ AutoLock lock(lock_);
+ subtle::NoBarrier_Store(&watch_category_, 0);
+ watch_event_name_ = "";
+ watch_event_callback_.Reset();
+}
+
+uint64_t TraceLog::MangleEventId(uint64_t id) {
+ return id ^ process_id_hash_;
+}
+
+void TraceLog::AddMetadataEventsWhileLocked() {
+ lock_.AssertAcquired();
+
+ // Copy metadata added by |AddMetadataEvent| into the trace log.
+ for (const scoped_ptr<TraceEvent>& event : metadata_events_)
+ AddEventToThreadSharedChunkWhileLocked(nullptr, false)->CopyFrom(*event);
+
+#if !defined(OS_NACL) // NaCl shouldn't expose the process id.
+ InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
+ 0, "num_cpus", "number",
+ base::SysInfo::NumberOfProcessors());
+#endif
+
+ int current_thread_id = static_cast<int>(base::PlatformThread::CurrentId());
+ if (process_sort_index_ != 0) {
+ InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
+ current_thread_id, "process_sort_index",
+ "sort_index", process_sort_index_);
+ }
+
+ if (process_name_.size()) {
+ InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
+ current_thread_id, "process_name", "name",
+ process_name_);
+ }
+
+ if (process_labels_.size() > 0) {
+ std::vector<std::string> labels;
+ for (base::hash_map<int, std::string>::iterator it =
+ process_labels_.begin();
+ it != process_labels_.end(); it++) {
+ labels.push_back(it->second);
+ }
+ InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
+ current_thread_id, "process_labels", "labels",
+ base::JoinString(labels, ","));
+ }
+
+ // Thread sort indices.
+ for (hash_map<int, int>::iterator it = thread_sort_indices_.begin();
+ it != thread_sort_indices_.end(); it++) {
+ if (it->second == 0)
+ continue;
+ InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
+ it->first, "thread_sort_index", "sort_index",
+ it->second);
+ }
+
+ // Thread names.
+ AutoLock thread_info_lock(thread_info_lock_);
+ for (hash_map<int, std::string>::iterator it = thread_names_.begin();
+ it != thread_names_.end(); it++) {
+ if (it->second.empty())
+ continue;
+ InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
+ it->first, "thread_name", "name", it->second);
+ }
+
+ // If buffer is full, add a metadata record to report this.
+ if (!buffer_limit_reached_timestamp_.is_null()) {
+ InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
+ current_thread_id, "trace_buffer_overflowed",
+ "overflowed_at_ts",
+ buffer_limit_reached_timestamp_);
+ }
+}
+
+void TraceLog::WaitSamplingEventForTesting() {
+ if (!sampling_thread_)
+ return;
+ sampling_thread_->WaitSamplingEventForTesting();
+}
+
+void TraceLog::DeleteForTesting() {
+ internal::DeleteTraceLogForTesting::Delete();
+}
+
+TraceEvent* TraceLog::GetEventByHandle(TraceEventHandle handle) {
+ return GetEventByHandleInternal(handle, NULL);
+}
+
+TraceEvent* TraceLog::GetEventByHandleInternal(TraceEventHandle handle,
+ OptionalAutoLock* lock) {
+ if (!handle.chunk_seq)
+ return NULL;
+
+ if (thread_local_event_buffer_.Get()) {
+ TraceEvent* trace_event =
+ thread_local_event_buffer_.Get()->GetEventByHandle(handle);
+ if (trace_event)
+ return trace_event;
+ }
+
+ // The event has been out-of-control of the thread local buffer.
+ // Try to get the event from the main buffer with a lock.
+ if (lock)
+ lock->EnsureAcquired();
+
+ if (thread_shared_chunk_ &&
+ handle.chunk_index == thread_shared_chunk_index_) {
+ return handle.chunk_seq == thread_shared_chunk_->seq()
+ ? thread_shared_chunk_->GetEventAt(handle.event_index)
+ : NULL;
+ }
+
+ return logged_events_->GetEventByHandle(handle);
+}
+
+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<unsigned long long>(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<int, std::string>::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<int>(thread_id)] = sort_index;
+}
+
+void TraceLog::SetTimeOffset(TimeDelta offset) {
+ time_offset_ = offset;
+}
+
+size_t TraceLog::GetObserverCountForTest() const {
+ return enabled_state_observer_list_.size();
+}
+
+void TraceLog::SetCurrentThreadBlocksMessageLoop() {
+ thread_blocks_message_loop_.Set(true);
+ if (thread_local_event_buffer_.Get()) {
+ // This will flush the thread local buffer.
+ delete thread_local_event_buffer_.Get();
+ }
+}
+
+TraceBuffer* TraceLog::CreateTraceBuffer() {
+ InternalTraceOptions options = trace_options();
+ if (options & kInternalRecordContinuously)
+ return TraceBuffer::CreateTraceBufferRingBuffer(
+ kTraceEventRingBufferChunks);
+ else if ((options & kInternalEnableSampling) && mode_ == MONITORING_MODE)
+ return TraceBuffer::CreateTraceBufferRingBuffer(
+ kMonitorTraceEventBufferChunks);
+ else if (options & kInternalEchoToConsole)
+ return TraceBuffer::CreateTraceBufferRingBuffer(
+ kEchoToConsoleTraceEventBufferChunks);
+ else if (options & kInternalRecordAsMuchAsPossible)
+ return TraceBuffer::CreateTraceBufferVectorOfSize(
+ kTraceEventVectorBigBufferChunks);
+ return TraceBuffer::CreateTraceBufferVectorOfSize(
+ kTraceEventVectorBufferChunks);
+}
+
+#if defined(OS_WIN)
+void TraceLog::UpdateETWCategoryGroupEnabledFlags() {
+ AutoLock lock(lock_);
+ size_t category_index = base::subtle::NoBarrier_Load(&g_category_index);
+ // Go through each category and set/clear the ETW bit depending on whether the
+ // category is enabled.
+ for (size_t i = 0; i < category_index; i++) {
+ const char* category_group = g_category_groups[i];
+ DCHECK(category_group);
+ if (base::trace_event::TraceEventETWExport::IsCategoryGroupEnabled(
+ category_group)) {
+ g_category_group_enabled[i] |= ENABLED_FOR_ETW_EXPORT;
+ } else {
+ g_category_group_enabled[i] &= ~ENABLED_FOR_ETW_EXPORT;
+ }
+ }
+}
+#endif // defined(OS_WIN)
+
+void ConvertableToTraceFormat::EstimateTraceMemoryOverhead(
+ TraceEventMemoryOverhead* overhead) {
+ overhead->Add("ConvertableToTraceFormat(Unknown)", sizeof(*this));
+}
+
+} // namespace trace_event
+} // namespace base
+
+namespace trace_event_internal {
+
+ScopedTraceBinaryEfficient::ScopedTraceBinaryEfficient(
+ const char* category_group,
+ const char* name) {
+ // The single atom works because for now the category_group can only be "gpu".
+ DCHECK_EQ(strcmp(category_group, "gpu"), 0);
+ static TRACE_EVENT_API_ATOMIC_WORD atomic = 0;
+ INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO_CUSTOM_VARIABLES(
+ category_group, atomic, category_group_enabled_);
+ name_ = name;
+ if (*category_group_enabled_) {
+ event_handle_ =
+ TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
+ TRACE_EVENT_PHASE_COMPLETE,
+ category_group_enabled_,
+ name,
+ trace_event_internal::kNoId, // id
+ static_cast<int>(base::PlatformThread::CurrentId()), // thread_id
+ base::TimeTicks::Now(),
+ trace_event_internal::kZeroNumArgs,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ TRACE_EVENT_FLAG_NONE);
+ }
+}
+
+ScopedTraceBinaryEfficient::~ScopedTraceBinaryEfficient() {
+ if (*category_group_enabled_) {
+ TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(category_group_enabled_, name_,
+ event_handle_);
+ }
+}
+
+} // namespace trace_event_internal
diff --git a/base/trace_event/trace_log.h b/base/trace_event/trace_log.h
new file mode 100644
index 0000000000..a079f04378
--- /dev/null
+++ b/base/trace_event/trace_log.h
@@ -0,0 +1,503 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_TRACE_LOG_H_
+#define BASE_TRACE_EVENT_TRACE_LOG_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include "base/atomicops.h"
+#include "base/containers/hash_tables.h"
+#include "base/gtest_prod_util.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "base/trace_event/memory_dump_provider.h"
+#include "base/trace_event/trace_config.h"
+#include "base/trace_event/trace_event_impl.h"
+#include "build/build_config.h"
+
+namespace base {
+
+template <typename Type>
+struct DefaultSingletonTraits;
+class RefCountedString;
+
+namespace trace_event {
+
+class TraceBuffer;
+class TraceBufferChunk;
+class TraceEvent;
+class TraceEventMemoryOverhead;
+class TraceSamplingThread;
+
+struct BASE_EXPORT TraceLogStatus {
+ TraceLogStatus();
+ ~TraceLogStatus();
+ size_t event_capacity;
+ size_t event_count;
+};
+
+class BASE_EXPORT TraceLog : public MemoryDumpProvider {
+ public:
+ enum Mode {
+ DISABLED = 0,
+ RECORDING_MODE,
+ MONITORING_MODE,
+ };
+
+ // 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.
+ // These values must be in sync with macro values in TraceEvent.h in Blink.
+ enum CategoryGroupEnabledFlags {
+ // Category group enabled for the recording mode.
+ ENABLED_FOR_RECORDING = 1 << 0,
+ // Category group enabled for the monitoring mode.
+ ENABLED_FOR_MONITORING = 1 << 1,
+ // Category group enabled by SetEventCallbackEnabled().
+ ENABLED_FOR_EVENT_CALLBACK = 1 << 2,
+ // Category group enabled to export events to ETW.
+ ENABLED_FOR_ETW_EXPORT = 1 << 3
+ };
+
+ static TraceLog* GetInstance();
+
+ // 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<std::string>* category_groups);
+
+ // Retrieves a copy (for thread-safety) of the current TraceConfig.
+ TraceConfig GetCurrentTraceConfig() const;
+
+ // Initializes the thread-local event buffer, if not already initialized and
+ // if the current thread supports that (has a message loop).
+ void InitializeThreadLocalEventBufferIfSupported();
+
+ // Enables normal tracing (recording trace events in the trace buffer).
+ // See TraceConfig comments for details on how to control what categories
+ // will be traced. If tracing has already been enabled, |category_filter| will
+ // be merged into the current category filter.
+ void SetEnabled(const TraceConfig& trace_config, Mode mode);
+
+ // Disables normal tracing for all categories.
+ void SetDisabled();
+
+ bool IsEnabled() { return mode_ != DISABLED; }
+
+ // 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();
+ void AddClockSyncMetadataEvent();
+#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 BASE_EXPORT EnabledStateObserver {
+ public:
+ virtual ~EnabledStateObserver() = default;
+
+ // 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;
+
+ TraceLogStatus GetStatus() const;
+ bool BufferIsFull() const;
+
+ // Computes an estimate of the size of the TraceLog including all the retained
+ // objects.
+ void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead);
+
+ // 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 SetEventCallbackEnabled() that replaces or a call to
+ // SetEventCallbackDisabled() that disables the callback.
+ // This callback may be invoked on any thread.
+ // For TRACE_EVENT_PHASE_COMPLETE events, the client will still receive pairs
+ // of TRACE_EVENT_PHASE_BEGIN and TRACE_EVENT_PHASE_END events to keep the
+ // interface simple.
+ typedef void (*EventCallback)(TimeTicks timestamp,
+ 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 int flags);
+
+ // Enable tracing for EventCallback.
+ void SetEventCallbackEnabled(const TraceConfig& trace_config,
+ EventCallback cb);
+ void SetEventCallbackDisabled();
+ void SetArgumentFilterPredicate(
+ const ArgumentFilterPredicate& argument_filter_predicate);
+
+ // Flush all collected events to the given output callback. The callback will
+ // be called one or more times either synchronously or asynchronously from
+ // the current thread with IPC-bite-size chunks. The string format is
+ // undefined. Use TraceResultBuffer to convert one or more trace strings to
+ // JSON. The callback can be null if the caller doesn't want any data.
+ // Due to the implementation of thread-local buffers, flush can't be
+ // done when tracing is enabled. If called when tracing is enabled, the
+ // callback will be called directly with (empty_string, false) to indicate
+ // the end of this unsuccessful flush. Flush does the serialization
+ // on the same thread if the caller doesn't set use_worker_thread explicitly.
+ typedef base::Callback<void(const scoped_refptr<base::RefCountedString>&,
+ bool has_more_events)> OutputCallback;
+ void Flush(const OutputCallback& cb, bool use_worker_thread = false);
+ void FlushButLeaveBufferIntact(const OutputCallback& flush_output_callback);
+
+ // Cancels tracing and discards collected data.
+ void CancelTracing(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.
+ TraceEventHandle 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,
+ const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
+ unsigned int flags);
+ TraceEventHandle AddTraceEventWithBindId(
+ char phase,
+ const unsigned char* category_group_enabled,
+ const char* name,
+ unsigned long long id,
+ unsigned long long bind_id,
+ int num_args,
+ const char** arg_names,
+ const unsigned char* arg_types,
+ const unsigned long long* arg_values,
+ const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
+ unsigned int flags);
+ TraceEventHandle AddTraceEventWithProcessId(
+ char phase,
+ const unsigned char* category_group_enabled,
+ const char* name,
+ unsigned long long id,
+ int process_id,
+ int num_args,
+ const char** arg_names,
+ const unsigned char* arg_types,
+ const unsigned long long* arg_values,
+ const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
+ unsigned int flags);
+ TraceEventHandle 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,
+ const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
+ unsigned int flags);
+ TraceEventHandle AddTraceEventWithThreadIdAndTimestamp(
+ char phase,
+ const unsigned char* category_group_enabled,
+ const char* name,
+ unsigned long long id,
+ unsigned long long bind_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,
+ const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
+ unsigned int flags);
+
+ // Adds a metadata event that will be written when the trace log is flushed.
+ void AddMetadataEvent(
+ const char* name,
+ int num_args,
+ const char** arg_names,
+ const unsigned char* arg_types,
+ const unsigned long long* arg_values,
+ const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
+ unsigned int flags);
+
+ void UpdateTraceEventDuration(const unsigned char* category_group_enabled,
+ const char* name,
+ TraceEventHandle handle);
+
+ // For every matching event, the callback will be called.
+ typedef base::Callback<void()> WatchEventCallback;
+ void SetWatchEvent(const std::string& category_name,
+ const std::string& event_name,
+ const WatchEventCallback& callback);
+ // 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_; }
+
+ uint64_t MangleEventId(uint64_t id);
+
+ // Exposed for unittesting:
+
+ void WaitSamplingEventForTesting();
+
+ // Allows deleting our singleton instance.
+ static void DeleteForTesting();
+
+ // Allow tests to inspect TraceEvents.
+ TraceEvent* GetEventByHandle(TraceEventHandle handle);
+
+ 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 thread_id, 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;
+
+ // Call this method if the current thread may block the message loop to
+ // prevent the thread from using the thread-local buffer because the thread
+ // may not handle the flush request in time causing lost of unflushed events.
+ void SetCurrentThreadBlocksMessageLoop();
+
+#if defined(OS_WIN)
+ // This function is called by the ETW exporting module whenever the ETW
+ // keyword (flags) changes. This keyword indicates which categories should be
+ // exported, so whenever it changes, we adjust accordingly.
+ void UpdateETWCategoryGroupEnabledFlags();
+#endif
+
+ private:
+ typedef unsigned int InternalTraceOptions;
+
+ FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture,
+ TraceBufferRingBufferGetReturnChunk);
+ FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture,
+ TraceBufferRingBufferHalfIteration);
+ FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture,
+ TraceBufferRingBufferFullIteration);
+ FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture, TraceBufferVectorReportFull);
+ FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture,
+ ConvertTraceConfigToInternalOptions);
+ FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture,
+ TraceRecordAsMuchAsPossibleMode);
+
+ // This allows constructor and destructor to be private and usable only
+ // by the Singleton class.
+ friend struct DefaultSingletonTraits<TraceLog>;
+
+ // MemoryDumpProvider implementation.
+ bool OnMemoryDump(const MemoryDumpArgs& args,
+ ProcessMemoryDump* pmd) override;
+
+ // Enable/disable each category group based on the current mode_,
+ // category_filter_, event_callback_ and event_callback_category_filter_.
+ // Enable the category group in the enabled mode if category_filter_ matches
+ // the category group, or event_callback_ is not null and
+ // event_callback_category_filter_ matches the category group.
+ void UpdateCategoryGroupEnabledFlags();
+ void UpdateCategoryGroupEnabledFlag(size_t category_index);
+
+ // Configure synthetic delays based on the values set in the current
+ // trace config.
+ void UpdateSyntheticDelaysFromTraceConfig();
+
+ InternalTraceOptions GetInternalOptionsFromTraceConfig(
+ const TraceConfig& config);
+
+ class ThreadLocalEventBuffer;
+ class OptionalAutoLock;
+
+ TraceLog();
+ ~TraceLog() override;
+ const unsigned char* GetCategoryGroupEnabledInternal(const char* name);
+ void AddMetadataEventsWhileLocked();
+
+ InternalTraceOptions trace_options() const {
+ return static_cast<InternalTraceOptions>(
+ subtle::NoBarrier_Load(&trace_options_));
+ }
+
+ TraceBuffer* trace_buffer() const { return logged_events_.get(); }
+ TraceBuffer* CreateTraceBuffer();
+
+ std::string EventToConsoleMessage(unsigned char phase,
+ const TimeTicks& timestamp,
+ TraceEvent* trace_event);
+
+ TraceEvent* AddEventToThreadSharedChunkWhileLocked(TraceEventHandle* handle,
+ bool check_buffer_is_full);
+ void CheckIfBufferIsFullWhileLocked();
+ void SetDisabledWhileLocked();
+
+ TraceEvent* GetEventByHandleInternal(TraceEventHandle handle,
+ OptionalAutoLock* lock);
+
+ void FlushInternal(const OutputCallback& cb,
+ bool use_worker_thread,
+ bool discard_events);
+
+ // |generation| is used in the following callbacks to check if the callback
+ // is called for the flush of the current |logged_events_|.
+ void FlushCurrentThread(int generation, bool discard_events);
+ // Usually it runs on a different thread.
+ static void ConvertTraceEventsToTraceFormat(
+ scoped_ptr<TraceBuffer> logged_events,
+ const TraceLog::OutputCallback& flush_output_callback,
+ const ArgumentFilterPredicate& argument_filter_predicate);
+ void FinishFlush(int generation, bool discard_events);
+ void OnFlushTimeout(int generation, bool discard_events);
+
+ int generation() const {
+ return static_cast<int>(subtle::NoBarrier_Load(&generation_));
+ }
+ bool CheckGeneration(int generation) const {
+ return generation == this->generation();
+ }
+ void UseNextTraceBuffer();
+
+ TimeTicks OffsetNow() const { return OffsetTimestamp(TimeTicks::Now()); }
+ TimeTicks OffsetTimestamp(const TimeTicks& timestamp) const {
+ return timestamp - time_offset_;
+ }
+
+ // Internal representation of trace options since we store the currently used
+ // trace option as an AtomicWord.
+ static const InternalTraceOptions kInternalNone;
+ static const InternalTraceOptions kInternalRecordUntilFull;
+ static const InternalTraceOptions kInternalRecordContinuously;
+ static const InternalTraceOptions kInternalEchoToConsole;
+ static const InternalTraceOptions kInternalEnableSampling;
+ static const InternalTraceOptions kInternalRecordAsMuchAsPossible;
+ static const InternalTraceOptions kInternalEnableArgumentFilter;
+
+ // This lock protects TraceLog member accesses (except for members protected
+ // by thread_info_lock_) from arbitrary threads.
+ mutable Lock lock_;
+ // This lock protects accesses to thread_names_, thread_event_start_times_
+ // and thread_colors_.
+ Lock thread_info_lock_;
+ Mode mode_;
+ int num_traces_recorded_;
+ scoped_ptr<TraceBuffer> logged_events_;
+ std::vector<scoped_ptr<TraceEvent>> metadata_events_;
+ subtle::AtomicWord /* EventCallback */ event_callback_;
+ bool dispatching_to_observer_list_;
+ std::vector<EnabledStateObserver*> enabled_state_observer_list_;
+
+ std::string process_name_;
+ base::hash_map<int, std::string> process_labels_;
+ int process_sort_index_;
+ base::hash_map<int, int> thread_sort_indices_;
+ base::hash_map<int, std::string> thread_names_;
+
+ // The following two maps are used only when ECHO_TO_CONSOLE.
+ base::hash_map<int, std::stack<TimeTicks>> thread_event_start_times_;
+ base::hash_map<std::string, int> thread_colors_;
+
+ TimeTicks buffer_limit_reached_timestamp_;
+
+ // 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.
+ WatchEventCallback watch_event_callback_;
+ subtle::AtomicWord /* const unsigned char* */ watch_category_;
+ std::string watch_event_name_;
+
+ subtle::AtomicWord /* Options */ trace_options_;
+
+ // Sampling thread handles.
+ scoped_ptr<TraceSamplingThread> sampling_thread_;
+ PlatformThreadHandle sampling_thread_handle_;
+
+ TraceConfig trace_config_;
+ TraceConfig event_callback_trace_config_;
+
+ ThreadLocalPointer<ThreadLocalEventBuffer> thread_local_event_buffer_;
+ ThreadLocalBoolean thread_blocks_message_loop_;
+ ThreadLocalBoolean thread_is_in_trace_event_;
+
+ // Contains the message loops of threads that have had at least one event
+ // added into the local event buffer. Not using SingleThreadTaskRunner
+ // because we need to know the life time of the message loops.
+ hash_set<MessageLoop*> thread_message_loops_;
+
+ // For events which can't be added into the thread local buffer, e.g. events
+ // from threads without a message loop.
+ scoped_ptr<TraceBufferChunk> thread_shared_chunk_;
+ size_t thread_shared_chunk_index_;
+
+ // Set when asynchronous Flush is in progress.
+ OutputCallback flush_output_callback_;
+ scoped_refptr<SingleThreadTaskRunner> flush_task_runner_;
+ ArgumentFilterPredicate argument_filter_predicate_;
+ subtle::AtomicWord generation_;
+ bool use_worker_thread_;
+
+ DISALLOW_COPY_AND_ASSIGN(TraceLog);
+};
+
+} // namespace trace_event
+} // namespace base
+
+#endif // BASE_TRACE_EVENT_TRACE_LOG_H_
diff --git a/base/trace_event/trace_event_impl_constants.cc b/base/trace_event/trace_log_constants.cc
index b7f3b4c4a2..cd2ff0dad3 100644
--- a/base/trace_event/trace_event_impl_constants.cc
+++ b/base/trace_event/trace_log_constants.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/trace_event/trace_event_impl.h"
+#include "base/trace_event/trace_log.h"
namespace base {
namespace trace_event {
diff --git a/base/trace_event/trace_sampling_thread.cc b/base/trace_event/trace_sampling_thread.cc
new file mode 100644
index 0000000000..ec4602ccc1
--- /dev/null
+++ b/base/trace_event/trace_sampling_thread.cc
@@ -0,0 +1,103 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stddef.h>
+
+#include "base/trace_event/trace_event_impl.h"
+#include "base/trace_event/trace_log.h"
+#include "base/trace_event/trace_sampling_thread.h"
+
+namespace base {
+namespace trace_event {
+
+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;
+};
+
+TraceSamplingThread::TraceSamplingThread()
+ : thread_running_(false), waitable_event_for_testing_(false, false) {}
+
+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();
+ waitable_event_for_testing_.Signal();
+ }
+}
+
+// static
+void TraceSamplingThread::DefaultSamplingCallback(
+ 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<const char* const>(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) {
+ // Access to sample_buckets_ doesn't cause races with the sampling thread
+ // that uses the sample_buckets_, because it is guaranteed that
+ // RegisterSampleBucket is called before the sampling thread is created.
+ 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::WaitSamplingEventForTesting() {
+ waitable_event_for_testing_.Wait();
+}
+
+TraceBucketData::TraceBucketData(base::subtle::AtomicWord* bucket,
+ const char* name,
+ TraceSampleCallback callback)
+ : bucket(bucket), bucket_name(name), callback(callback) {}
+
+TraceBucketData::~TraceBucketData() {}
+
+} // namespace trace_event
+} // namespace base
diff --git a/base/trace_event/trace_sampling_thread.h b/base/trace_event/trace_sampling_thread.h
new file mode 100644
index 0000000000..f976a80e07
--- /dev/null
+++ b/base/trace_event/trace_sampling_thread.h
@@ -0,0 +1,54 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_TRACE_SAMPLING_THREAD_H_
+#define BASE_TRACE_EVENT_TRACE_SAMPLING_THREAD_H_
+
+#include "base/synchronization/cancellation_flag.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/trace_event/trace_event.h"
+
+namespace base {
+namespace trace_event {
+
+class TraceBucketData;
+typedef base::Callback<void(TraceBucketData*)> TraceSampleCallback;
+
+// This object must be created on the IO thread.
+class TraceSamplingThread : public PlatformThread::Delegate {
+ public:
+ TraceSamplingThread();
+ ~TraceSamplingThread() override;
+
+ // Implementation of PlatformThread::Delegate:
+ void ThreadMain() override;
+
+ static void DefaultSamplingCallback(TraceBucketData* bucket_data);
+
+ void Stop();
+ void WaitSamplingEventForTesting();
+
+ 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<TraceBucketData> sample_buckets_;
+ bool thread_running_;
+ CancellationFlag cancellation_flag_;
+ WaitableEvent waitable_event_for_testing_;
+};
+
+} // namespace trace_event
+} // namespace base
+
+#endif // BASE_TRACE_EVENT_TRACE_SAMPLING_THREAD_H_
diff --git a/base/tracked_objects.cc b/base/tracked_objects.cc
index 93bac6d872..8953554a29 100644
--- a/base/tracked_objects.cc
+++ b/base/tracked_objects.cc
@@ -16,6 +16,7 @@
#include "base/profiler/alternate_timer.h"
#include "base/strings/stringprintf.h"
#include "base/tracking_info.h"
+#include "build/build_config.h"
#include "third_party/valgrind/memcheck.h"
using base::TimeDelta;
@@ -130,27 +131,31 @@ DeathData::~DeathData() {
// We use a macro rather than a template to force this to inline.
// Related code for calculating max is discussed on the web.
#define CONDITIONAL_ASSIGN(assign_it, target, source) \
- ((target) ^= ((target) ^ (source)) & -static_cast<int32>(assign_it))
+ ((target) ^= ((target) ^ (source)) & -static_cast<int32_t>(assign_it))
-void DeathData::RecordDeath(const int32 queue_duration,
- const int32 run_duration,
- const uint32 random_number) {
+void DeathData::RecordDeath(const int32_t queue_duration,
+ const int32_t run_duration,
+ const uint32_t random_number) {
// We'll just clamp at INT_MAX, but we should note this in the UI as such.
if (count_ < INT_MAX)
- ++count_;
+ base::subtle::NoBarrier_Store(&count_, count_ + 1);
- int sample_probability_count = sample_probability_count_;
+ int sample_probability_count =
+ base::subtle::NoBarrier_Load(&sample_probability_count_);
if (sample_probability_count < INT_MAX)
++sample_probability_count;
- sample_probability_count_ = sample_probability_count;
+ base::subtle::NoBarrier_Store(&sample_probability_count_,
+ sample_probability_count);
- queue_duration_sum_ += queue_duration;
- run_duration_sum_ += run_duration;
+ base::subtle::NoBarrier_Store(&queue_duration_sum_,
+ queue_duration_sum_ + queue_duration);
+ base::subtle::NoBarrier_Store(&run_duration_sum_,
+ run_duration_sum_ + run_duration);
- if (queue_duration_max_ < queue_duration)
- queue_duration_max_ = queue_duration;
- if (run_duration_max_ < run_duration)
- run_duration_max_ = run_duration;
+ if (queue_duration_max() < queue_duration)
+ base::subtle::NoBarrier_Store(&queue_duration_max_, queue_duration);
+ if (run_duration_max() < run_duration)
+ base::subtle::NoBarrier_Store(&run_duration_max_, run_duration);
// Take a uniformly distributed sample over all durations ever supplied during
// the current profiling phase.
@@ -162,17 +167,17 @@ void DeathData::RecordDeath(const int32 queue_duration,
// used them to generate random_number).
CHECK_GT(sample_probability_count, 0);
if (0 == (random_number % sample_probability_count)) {
- queue_duration_sample_ = queue_duration;
- run_duration_sample_ = run_duration;
+ base::subtle::NoBarrier_Store(&queue_duration_sample_, queue_duration);
+ base::subtle::NoBarrier_Store(&run_duration_sample_, run_duration);
}
}
void DeathData::OnProfilingPhaseCompleted(int profiling_phase) {
// Snapshotting and storing current state.
last_phase_snapshot_ = new DeathDataPhaseSnapshot(
- profiling_phase, count_, run_duration_sum_, run_duration_max_,
- run_duration_sample_, queue_duration_sum_, queue_duration_max_,
- queue_duration_sample_, last_phase_snapshot_);
+ profiling_phase, count(), run_duration_sum(), run_duration_max(),
+ run_duration_sample(), queue_duration_sum(), queue_duration_max(),
+ queue_duration_sample(), last_phase_snapshot_);
// Not touching fields for which a delta can be computed by comparing with a
// snapshot from the previous phase. Resetting other fields. Sample values
@@ -191,15 +196,17 @@ void DeathData::OnProfilingPhaseCompleted(int profiling_phase) {
// resets.
// sample_probability_count_ is incrementable, but must be reset to 0 at the
// phase end, so that we start a new uniformly randomized sample selection
- // after the reset. Corruptions due to race conditions are possible, but the
- // damage is limited to selecting a wrong sample, which is not something that
- // can cause accumulating or cascading effects.
- // If there were no corruptions caused by race conditions, we never send a
+ // after the reset. These fields are updated using atomics. However, race
+ // conditions are possible since these are updated individually and not
+ // together atomically, resulting in the values being mutually inconsistent.
+ // The damage is limited to selecting a wrong sample, which is not something
+ // that can cause accumulating or cascading effects.
+ // If there were no inconsistencies caused by race conditions, we never send a
// sample for the previous phase in the next phase's snapshot because
// ThreadData::SnapshotExecutedTasks doesn't send deltas with 0 count.
- sample_probability_count_ = 0;
- run_duration_max_ = 0;
- queue_duration_max_ = 0;
+ base::subtle::NoBarrier_Store(&sample_probability_count_, 0);
+ base::subtle::NoBarrier_Store(&run_duration_max_, 0);
+ base::subtle::NoBarrier_Store(&queue_duration_max_, 0);
}
//------------------------------------------------------------------------------
@@ -214,20 +221,19 @@ DeathDataSnapshot::DeathDataSnapshot()
}
DeathDataSnapshot::DeathDataSnapshot(int count,
- int32 run_duration_sum,
- int32 run_duration_max,
- int32 run_duration_sample,
- int32 queue_duration_sum,
- int32 queue_duration_max,
- int32 queue_duration_sample)
+ int32_t run_duration_sum,
+ int32_t run_duration_max,
+ int32_t run_duration_sample,
+ int32_t queue_duration_sum,
+ int32_t queue_duration_max,
+ int32_t queue_duration_sample)
: count(count),
run_duration_sum(run_duration_sum),
run_duration_max(run_duration_max),
run_duration_sample(run_duration_sample),
queue_duration_sum(queue_duration_sum),
queue_duration_max(queue_duration_max),
- queue_duration_sample(queue_duration_sample) {
-}
+ queue_duration_sample(queue_duration_sample) {}
DeathDataSnapshot::~DeathDataSnapshot() {
}
@@ -309,7 +315,7 @@ base::LazyInstance<base::Lock>::Leaky
ThreadData::list_lock_ = LAZY_INSTANCE_INITIALIZER;
// static
-ThreadData::Status ThreadData::status_ = ThreadData::UNINITIALIZED;
+base::subtle::Atomic32 ThreadData::status_ = ThreadData::UNINITIALIZED;
ThreadData::ThreadData(const std::string& suggested_name)
: next_(NULL),
@@ -341,7 +347,7 @@ void ThreadData::PushToHeadOfList() {
(void)VALGRIND_MAKE_MEM_DEFINED_IF_ADDRESSABLE(&random_number_,
sizeof(random_number_));
MSAN_UNPOISON(&random_number_, sizeof(random_number_));
- random_number_ += static_cast<uint32>(this - static_cast<ThreadData*>(0));
+ random_number_ += static_cast<uint32_t>(this - static_cast<ThreadData*>(0));
random_number_ ^= (Now() - TrackedTime()).InMilliseconds();
DCHECK(!next_);
@@ -498,15 +504,16 @@ Births* ThreadData::TallyABirth(const Location& location) {
}
void ThreadData::TallyADeath(const Births& births,
- int32 queue_duration,
+ int32_t queue_duration,
const TaskStopwatch& stopwatch) {
- int32 run_duration = stopwatch.RunDurationMs();
+ int32_t run_duration = stopwatch.RunDurationMs();
// Stir in some randomness, plus add constant in case durations are zero.
- const uint32 kSomePrimeNumber = 2147483647;
+ const uint32_t kSomePrimeNumber = 2147483647;
random_number_ += queue_duration + run_duration + kSomePrimeNumber;
// An address is going to have some randomness to it as well ;-).
- random_number_ ^= static_cast<uint32>(&births - reinterpret_cast<Births*>(0));
+ random_number_ ^=
+ static_cast<uint32_t>(&births - reinterpret_cast<Births*>(0));
// We don't have queue durations without OS timer. OS timer is automatically
// used for task-post-timing, so the use of an alternate timer implies all
@@ -559,7 +566,7 @@ void ThreadData::TallyRunOnNamedThreadIfTracking(
// efficient by not calling for a genuine time value. For simplicity, we'll
// use a default zero duration when we can't calculate a true value.
TrackedTime start_of_run = stopwatch.StartTime();
- int32 queue_duration = 0;
+ int32_t queue_duration = 0;
if (!start_of_run.is_null()) {
queue_duration = (start_of_run - completed_task.EffectiveTimePosted())
.InMilliseconds();
@@ -592,7 +599,7 @@ void ThreadData::TallyRunOnWorkerThreadIfTracking(
return;
TrackedTime start_of_run = stopwatch.StartTime();
- int32 queue_duration = 0;
+ int32_t queue_duration = 0;
if (!start_of_run.is_null()) {
queue_duration = (start_of_run - time_posted).InMilliseconds();
}
@@ -613,7 +620,7 @@ void ThreadData::TallyRunInAScopedRegionIfTracking(
if (!current_thread_data)
return;
- int32 queue_duration = 0;
+ int32_t queue_duration = 0;
current_thread_data->TallyADeath(*births, queue_duration, stopwatch);
}
@@ -691,7 +698,7 @@ static void OptionallyInitializeAlternateTimer() {
}
void ThreadData::Initialize() {
- if (status_ >= DEACTIVATED)
+ if (base::subtle::Acquire_Load(&status_) >= DEACTIVATED)
return; // Someone else did the initialization.
// Due to racy lazy initialization in tests, we'll need to recheck status_
// after we acquire the lock.
@@ -700,7 +707,7 @@ void ThreadData::Initialize() {
// threaded in the product, but some tests may be racy and lazy about our
// initialization.
base::AutoLock lock(*list_lock_.Pointer());
- if (status_ >= DEACTIVATED)
+ if (base::subtle::Acquire_Load(&status_) >= DEACTIVATED)
return; // Someone raced in here and beat us.
// Put an alternate timer in place if the environment calls for it, such as
@@ -713,12 +720,12 @@ void ThreadData::Initialize() {
// Perform the "real" TLS initialization now, and leave it intact through
// process termination.
if (!tls_index_.initialized()) { // Testing may have initialized this.
- DCHECK_EQ(status_, UNINITIALIZED);
+ DCHECK_EQ(base::subtle::NoBarrier_Load(&status_), UNINITIALIZED);
tls_index_.Initialize(&ThreadData::OnThreadTermination);
DCHECK(tls_index_.initialized());
} else {
// TLS was initialzed for us earlier.
- DCHECK_EQ(status_, DORMANT_DURING_TESTS);
+ DCHECK_EQ(base::subtle::NoBarrier_Load(&status_), DORMANT_DURING_TESTS);
}
// Incarnation counter is only significant to testing, as it otherwise will
@@ -728,8 +735,8 @@ void ThreadData::Initialize() {
// The lock is not critical for setting status_, but it doesn't hurt. It also
// ensures that if we have a racy initialization, that we'll bail as soon as
// we get the lock earlier in this method.
- status_ = kInitialStartupState;
- DCHECK(status_ != UNINITIALIZED);
+ base::subtle::Release_Store(&status_, kInitialStartupState);
+ DCHECK(base::subtle::NoBarrier_Load(&status_) != UNINITIALIZED);
}
// static
@@ -741,17 +748,17 @@ void ThreadData::InitializeAndSetTrackingStatus(Status status) {
if (status > DEACTIVATED)
status = PROFILING_ACTIVE;
- status_ = status;
+ base::subtle::Release_Store(&status_, status);
}
// static
ThreadData::Status ThreadData::status() {
- return status_;
+ return static_cast<ThreadData::Status>(base::subtle::Acquire_Load(&status_));
}
// static
bool ThreadData::TrackingStatus() {
- return status_ > DEACTIVATED;
+ return base::subtle::Acquire_Load(&status_) > DEACTIVATED;
}
// static
@@ -817,7 +824,8 @@ void ThreadData::ShutdownSingleThreadedCleanup(bool leak) {
worker_thread_data_creation_count_ = 0;
cleanup_count_ = 0;
tls_index_.Set(NULL);
- status_ = DORMANT_DURING_TESTS; // Almost UNINITIALIZED.
+ // Almost UNINITIALIZED.
+ base::subtle::Release_Store(&status_, DORMANT_DURING_TESTS);
// To avoid any chance of racing in unit tests, which is the only place we
// call this function, we may sometimes leak all the data structures we
@@ -923,7 +931,7 @@ TrackedTime TaskStopwatch::StartTime() const {
return start_time_;
}
-int32 TaskStopwatch::RunDurationMs() const {
+int32_t TaskStopwatch::RunDurationMs() const {
#if DCHECK_IS_ON()
DCHECK(state_ == STOPPED);
#endif
@@ -945,12 +953,12 @@ ThreadData* TaskStopwatch::GetThreadData() const {
DeathDataPhaseSnapshot::DeathDataPhaseSnapshot(
int profiling_phase,
int count,
- int32 run_duration_sum,
- int32 run_duration_max,
- int32 run_duration_sample,
- int32 queue_duration_sum,
- int32 queue_duration_max,
- int32 queue_duration_sample,
+ int32_t run_duration_sum,
+ int32_t run_duration_max,
+ int32_t run_duration_sample,
+ int32_t queue_duration_sum,
+ int32_t queue_duration_max,
+ int32_t queue_duration_sample,
const DeathDataPhaseSnapshot* prev)
: profiling_phase(profiling_phase),
death_data(count,
@@ -960,8 +968,7 @@ DeathDataPhaseSnapshot::DeathDataPhaseSnapshot(
queue_duration_sum,
queue_duration_max,
queue_duration_sample),
- prev(prev) {
-}
+ prev(prev) {}
//------------------------------------------------------------------------------
// TaskSnapshot
diff --git a/base/tracked_objects.h b/base/tracked_objects.h
index 8f8379409d..1a00ec0be0 100644
--- a/base/tracked_objects.h
+++ b/base/tracked_objects.h
@@ -5,6 +5,8 @@
#ifndef BASE_TRACKED_OBJECTS_H_
#define BASE_TRACKED_OBJECTS_H_
+#include <stdint.h>
+
#include <map>
#include <set>
#include <stack>
@@ -12,12 +14,13 @@
#include <utility>
#include <vector>
+#include "base/atomicops.h"
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/containers/hash_tables.h"
#include "base/gtest_prod_util.h"
#include "base/lazy_instance.h"
#include "base/location.h"
+#include "base/macros.h"
#include "base/process/process_handle.h"
#include "base/profiler/alternate_timer.h"
#include "base/profiler/tracked_time.h"
@@ -199,7 +202,7 @@ class BASE_EXPORT BirthOnThread {
public:
BirthOnThread(const Location& location, const ThreadData& current);
- const Location location() const { return location_; }
+ const Location& location() const { return location_; }
const ThreadData* birth_thread() const { return birth_thread_; }
private:
@@ -258,12 +261,12 @@ struct BASE_EXPORT DeathDataSnapshot {
// a wrapper structure as a param or using an empty constructor for
// snapshotting DeathData would be less efficient.
DeathDataSnapshot(int count,
- int32 run_duration_sum,
- int32 run_duration_max,
- int32 run_duration_sample,
- int32 queue_duration_sum,
- int32 queue_duration_max,
- int32 queue_duration_sample);
+ int32_t run_duration_sum,
+ int32_t run_duration_max,
+ int32_t run_duration_sample,
+ int32_t queue_duration_sum,
+ int32_t queue_duration_max,
+ int32_t queue_duration_sample);
~DeathDataSnapshot();
// Calculates and returns the delta between this snapshot and an earlier
@@ -271,12 +274,12 @@ struct BASE_EXPORT DeathDataSnapshot {
DeathDataSnapshot Delta(const DeathDataSnapshot& older) const;
int count;
- int32 run_duration_sum;
- int32 run_duration_max;
- int32 run_duration_sample;
- int32 queue_duration_sum;
- int32 queue_duration_max;
- int32 queue_duration_sample;
+ int32_t run_duration_sum;
+ int32_t run_duration_max;
+ int32_t run_duration_sample;
+ int32_t queue_duration_sum;
+ int32_t queue_duration_max;
+ int32_t queue_duration_sample;
};
//------------------------------------------------------------------------------
@@ -286,12 +289,12 @@ struct BASE_EXPORT DeathDataSnapshot {
struct DeathDataPhaseSnapshot {
DeathDataPhaseSnapshot(int profiling_phase,
int count,
- int32 run_duration_sum,
- int32 run_duration_max,
- int32 run_duration_sample,
- int32 queue_duration_sum,
- int32 queue_duration_max,
- int32 queue_duration_sample,
+ int32_t run_duration_sum,
+ int32_t run_duration_max,
+ int32_t run_duration_sample,
+ int32_t queue_duration_sum,
+ int32_t queue_duration_max,
+ int32_t queue_duration_sample,
const DeathDataPhaseSnapshot* prev);
// Profiling phase at which completion this snapshot was taken.
@@ -324,19 +327,31 @@ class BASE_EXPORT DeathData {
// Update stats for a task destruction (death) that had a Run() time of
// |duration|, and has had a queueing delay of |queue_duration|.
- void RecordDeath(const int32 queue_duration,
- const int32 run_duration,
- const uint32 random_number);
+ void RecordDeath(const int32_t queue_duration,
+ const int32_t run_duration,
+ const uint32_t random_number);
// Metrics and past snapshots accessors, used only for serialization and in
// tests.
- int count() const { return count_; }
- int32 run_duration_sum() const { return run_duration_sum_; }
- int32 run_duration_max() const { return run_duration_max_; }
- int32 run_duration_sample() const { return run_duration_sample_; }
- int32 queue_duration_sum() const { return queue_duration_sum_; }
- int32 queue_duration_max() const { return queue_duration_max_; }
- int32 queue_duration_sample() const { return queue_duration_sample_; }
+ int count() const { return base::subtle::NoBarrier_Load(&count_); }
+ int32_t run_duration_sum() const {
+ return base::subtle::NoBarrier_Load(&run_duration_sum_);
+ }
+ int32_t run_duration_max() const {
+ return base::subtle::NoBarrier_Load(&run_duration_max_);
+ }
+ int32_t run_duration_sample() const {
+ return base::subtle::NoBarrier_Load(&run_duration_sample_);
+ }
+ int32_t queue_duration_sum() const {
+ return base::subtle::NoBarrier_Load(&queue_duration_sum_);
+ }
+ int32_t queue_duration_max() const {
+ return base::subtle::NoBarrier_Load(&queue_duration_max_);
+ }
+ int32_t queue_duration_sample() const {
+ return base::subtle::NoBarrier_Load(&queue_duration_sample_);
+ }
const DeathDataPhaseSnapshot* last_phase_snapshot() const {
return last_phase_snapshot_;
}
@@ -351,28 +366,28 @@ class BASE_EXPORT DeathData {
// frequently used. This might help a bit with cache lines.
// Number of runs seen (divisor for calculating averages).
// Can be incremented only on the death thread.
- int count_;
+ base::subtle::Atomic32 count_;
// Count used in determining probability of selecting exec/queue times from a
// recorded death as samples.
// Gets incremented only on the death thread, but can be set to 0 by
// OnProfilingPhaseCompleted() on the snapshot thread.
- int sample_probability_count_;
+ base::subtle::Atomic32 sample_probability_count_;
// Basic tallies, used to compute averages. Can be incremented only on the
// death thread.
- int32 run_duration_sum_;
- int32 queue_duration_sum_;
+ base::subtle::Atomic32 run_duration_sum_;
+ base::subtle::Atomic32 queue_duration_sum_;
// Max values, used by local visualization routines. These are often read,
// but rarely updated. The max values get assigned only on the death thread,
// but these fields can be set to 0 by OnProfilingPhaseCompleted() on the
// snapshot thread.
- int32 run_duration_max_;
- int32 queue_duration_max_;
+ base::subtle::Atomic32 run_duration_max_;
+ base::subtle::Atomic32 queue_duration_max_;
// Samples, used by crowd sourcing gatherers. These are almost never read,
// and rarely updated. They can be modified only on the death thread.
- int32 run_duration_sample_;
- int32 queue_duration_sample_;
+ base::subtle::Atomic32 run_duration_sample_;
+ base::subtle::Atomic32 queue_duration_sample_;
// Snapshot of this death data made at the last profiling phase completion, if
// any. DeathData owns the whole list starting with this pointer.
@@ -574,7 +589,7 @@ class BASE_EXPORT ThreadData {
// Find a place to record a death on this thread.
void TallyADeath(const Births& births,
- int32 queue_duration,
+ int32_t queue_duration,
const TaskStopwatch& stopwatch);
// Snapshots (under a lock) the profiled data for the tasks for this thread
@@ -661,7 +676,7 @@ class BASE_EXPORT ThreadData {
static base::LazyInstance<base::Lock>::Leaky list_lock_;
// We set status_ to SHUTDOWN when we shut down the tracking service.
- static Status status_;
+ static base::subtle::Atomic32 status_;
// Link to next instance (null terminated list). Used to globally track all
// registered instances (corresponds to all registered threads where we keep
@@ -707,7 +722,7 @@ class BASE_EXPORT ThreadData {
// representative sample in each DeathData instance. We can't start off with
// much randomness (because we can't call RandInt() on all our threads), so
// we stir in more and more as we go.
- uint32 random_number_;
+ uint32_t random_number_;
// Record of what the incarnation_counter_ was when this instance was created.
// If the incarnation_counter_ has changed, then we avoid pushing into the
@@ -747,7 +762,7 @@ class BASE_EXPORT TaskStopwatch {
// and stopping this stopwatch, minus the wallclock durations of any other
// instances that are immediately nested in this one, started and stopped on
// this thread during that period.
- int32 RunDurationMs() const;
+ int32_t RunDurationMs() const;
// Returns tracking info for the current thread.
ThreadData* GetThreadData() const;
@@ -757,14 +772,14 @@ class BASE_EXPORT TaskStopwatch {
TrackedTime start_time_;
// Wallclock duration of the task.
- int32 wallclock_duration_ms_;
+ int32_t wallclock_duration_ms_;
// Tracking info for the current thread.
ThreadData* current_thread_data_;
// Sum of wallclock durations of all stopwatches that were directly nested in
// this one.
- int32 excluded_duration_ms_;
+ int32_t excluded_duration_ms_;
// Stopwatch which was running on our thread when this stopwatch was started.
// That preexisting stopwatch must be adjusted to the exclude the wallclock
diff --git a/base/tracked_objects_unittest.cc b/base/tracked_objects_unittest.cc
index cdbf9ac7a6..69dd85e1a0 100644
--- a/base/tracked_objects_unittest.cc
+++ b/base/tracked_objects_unittest.cc
@@ -7,6 +7,7 @@
#include "base/tracked_objects.h"
#include <stddef.h>
+#include <stdint.h>
#include "base/memory/scoped_ptr.h"
#include "base/process/process_handle.h"
@@ -184,7 +185,7 @@ TEST_F(TrackedObjectsTest, TinyStartupShutdown) {
// execution.
// Create a child (using the same birth location).
// TrackingInfo will call TallyABirth() during construction.
- const int32 start_time = 1;
+ const int32_t start_time = 1;
base::TimeTicks kBogusBirthTime = base::TimeTicks() +
base::TimeDelta::FromMilliseconds(start_time);
base::TrackingInfo pending_task(location, kBogusBirthTime);
@@ -192,7 +193,7 @@ TEST_F(TrackedObjectsTest, TinyStartupShutdown) {
TaskStopwatch stopwatch;
stopwatch.Start();
// Finally conclude the outer run.
- const int32 time_elapsed = 1000;
+ const int32_t time_elapsed = 1000;
SetTestTime(start_time + time_elapsed);
stopwatch.Stop();
@@ -240,7 +241,7 @@ TEST_F(TrackedObjectsTest, DeathDataTestRecordDeath) {
ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
scoped_ptr<DeathData> data(new DeathData());
- ASSERT_NE(data, reinterpret_cast<DeathData*>(NULL));
+ ASSERT_NE(data, nullptr);
EXPECT_EQ(data->run_duration_sum(), 0);
EXPECT_EQ(data->run_duration_max(), 0);
EXPECT_EQ(data->run_duration_sample(), 0);
@@ -250,8 +251,8 @@ TEST_F(TrackedObjectsTest, DeathDataTestRecordDeath) {
EXPECT_EQ(data->count(), 0);
EXPECT_EQ(nullptr, data->last_phase_snapshot());
- int32 run_ms = 42;
- int32 queue_ms = 8;
+ int32_t run_ms = 42;
+ int32_t queue_ms = 8;
const int kUnrandomInt = 0; // Fake random int that ensure we sample data.
data->RecordDeath(queue_ms, run_ms, kUnrandomInt);
@@ -279,10 +280,10 @@ TEST_F(TrackedObjectsTest, DeathDataTest2Phases) {
ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
scoped_ptr<DeathData> data(new DeathData());
- ASSERT_NE(data, reinterpret_cast<DeathData*>(NULL));
+ ASSERT_NE(data, nullptr);
- int32 run_ms = 42;
- int32 queue_ms = 8;
+ int32_t run_ms = 42;
+ int32_t queue_ms = 8;
const int kUnrandomInt = 0; // Fake random int that ensure we sample data.
data->RecordDeath(queue_ms, run_ms, kUnrandomInt);
@@ -312,8 +313,8 @@ TEST_F(TrackedObjectsTest, DeathDataTest2Phases) {
data->last_phase_snapshot()->death_data.queue_duration_sample);
EXPECT_EQ(nullptr, data->last_phase_snapshot()->prev);
- int32 run_ms1 = 21;
- int32 queue_ms1 = 4;
+ int32_t run_ms1 = 21;
+ int32_t queue_ms1 = 4;
data->RecordDeath(queue_ms1, run_ms1, kUnrandomInt);
EXPECT_EQ(data->run_duration_sum(), run_ms + run_ms + run_ms1);
diff --git a/base/tuple.h b/base/tuple.h
index ef51d85fed..e5872cc4fa 100644
--- a/base/tuple.h
+++ b/base/tuple.h
@@ -28,7 +28,10 @@
#ifndef BASE_TUPLE_H_
#define BASE_TUPLE_H_
+#include <stddef.h>
+
#include "base/bind_helpers.h"
+#include "build/build_config.h"
namespace base {
@@ -150,7 +153,7 @@ template <size_t N, typename T>
struct TupleLeaf;
template <typename... Ts>
-struct Tuple : TupleBase<Ts...> {
+struct Tuple final : TupleBase<Ts...> {
Tuple() : TupleBase<Ts...>() {}
explicit Tuple(typename TupleTraits<Ts>::ParamType... args)
: TupleBase<Ts...>(args...) {}
@@ -158,7 +161,7 @@ struct Tuple : TupleBase<Ts...> {
// Avoids ambiguity between Tuple's two constructors.
template <>
-struct Tuple<> {};
+struct Tuple<> final {};
template <size_t... Ns, typename... Ts>
struct TupleBaseImpl<IndexSequence<Ns...>, Ts...> : TupleLeaf<Ns, Ts>... {
@@ -241,11 +244,6 @@ inline Tuple<Ts&...> MakeRefTuple(Ts&... arg) {
// Non-Static Dispatchers with no out params.
-template <typename ObjT, typename Method, typename A>
-inline void DispatchToMethod(ObjT* obj, Method method, const A& arg) {
- (obj->*method)(base::internal::UnwrapTraits<A>::Unwrap(arg));
-}
-
template <typename ObjT, typename Method, typename... Ts, size_t... Ns>
inline void DispatchToMethodImpl(ObjT* obj,
Method method,
@@ -263,11 +261,6 @@ inline void DispatchToMethod(ObjT* obj,
// Static Dispatchers with no out params.
-template <typename Function, typename A>
-inline void DispatchToMethod(Function function, const A& arg) {
- (*function)(base::internal::UnwrapTraits<A>::Unwrap(arg));
-}
-
template <typename Function, typename... Ts, size_t... Ns>
inline void DispatchToFunctionImpl(Function function,
const Tuple<Ts...>& arg,
@@ -284,29 +277,6 @@ inline void DispatchToFunction(Function function, const Tuple<Ts...>& arg) {
template <typename ObjT,
typename Method,
- typename In,
- typename... OutTs,
- size_t... OutNs>
-inline void DispatchToMethodImpl(ObjT* obj,
- Method method,
- const In& in,
- Tuple<OutTs...>* out,
- IndexSequence<OutNs...>) {
- (obj->*method)(base::internal::UnwrapTraits<In>::Unwrap(in),
- &get<OutNs>(*out)...);
-}
-
-template <typename ObjT, typename Method, typename In, typename... OutTs>
-inline void DispatchToMethod(ObjT* obj,
- Method method,
- const In& in,
- Tuple<OutTs...>* out) {
- DispatchToMethodImpl(obj, method, in, out,
- MakeIndexSequence<sizeof...(OutTs)>());
-}
-
-template <typename ObjT,
- typename Method,
typename... InTs,
typename... OutTs,
size_t... InNs,
diff --git a/base/values.cc b/base/values.cc
index c5e0ecc9f0..3f32b5e7eb 100644
--- a/base/values.cc
+++ b/base/values.cc
@@ -9,6 +9,7 @@
#include <algorithm>
#include <cmath>
#include <ostream>
+#include <utility>
#include "base/json/json_writer.h"
#include "base/logging.h"
@@ -32,7 +33,7 @@ scoped_ptr<ListValue> CopyListWithoutEmptyChildren(const ListValue& list) {
if (child_copy) {
if (!copy)
copy.reset(new ListValue);
- copy->Append(child_copy.Pass());
+ copy->Append(std::move(child_copy));
}
}
return copy;
@@ -46,7 +47,7 @@ scoped_ptr<DictionaryValue> CopyDictionaryWithoutEmptyChildren(
if (child_copy) {
if (!copy)
copy.reset(new DictionaryValue);
- copy->SetWithoutPathExpansion(it.key(), child_copy.Pass());
+ copy->SetWithoutPathExpansion(it.key(), std::move(child_copy));
}
}
return copy;
@@ -313,10 +314,7 @@ BinaryValue::BinaryValue()
}
BinaryValue::BinaryValue(scoped_ptr<char[]> buffer, size_t size)
- : Value(TYPE_BINARY),
- buffer_(buffer.Pass()),
- size_(size) {
-}
+ : Value(TYPE_BINARY), buffer_(std::move(buffer)), size_(size) {}
BinaryValue::~BinaryValue() {
}
@@ -327,7 +325,7 @@ BinaryValue* BinaryValue::CreateWithCopiedBuffer(const char* buffer,
char* buffer_copy = new char[size];
memcpy(buffer_copy, buffer, size);
scoped_ptr<char[]> scoped_buffer_copy(buffer_copy);
- return new BinaryValue(scoped_buffer_copy.Pass(), size);
+ return new BinaryValue(std::move(scoped_buffer_copy), size);
}
bool BinaryValue::GetAsBinary(const BinaryValue** out_value) const {
@@ -351,6 +349,16 @@ bool BinaryValue::Equals(const Value* other) const {
///////////////////// DictionaryValue ////////////////////
+// static
+scoped_ptr<DictionaryValue> DictionaryValue::From(scoped_ptr<Value> value) {
+ DictionaryValue* out;
+ if (value && value->GetAsDictionary(&out)) {
+ ignore_result(value.release());
+ return make_scoped_ptr(out);
+ }
+ return nullptr;
+}
+
DictionaryValue::DictionaryValue()
: Value(TYPE_DICTIONARY) {
}
@@ -409,7 +417,8 @@ void DictionaryValue::Set(const std::string& path, scoped_ptr<Value> in_value) {
current_path.erase(0, delimiter_position + 1);
}
- current_dictionary->SetWithoutPathExpansion(current_path, in_value.Pass());
+ current_dictionary->SetWithoutPathExpansion(current_path,
+ std::move(in_value));
}
void DictionaryValue::Set(const std::string& path, Value* in_value) {
@@ -482,27 +491,30 @@ void DictionaryValue::SetStringWithoutPathExpansion(
SetWithoutPathExpansion(path, new StringValue(in_value));
}
-bool DictionaryValue::Get(const std::string& path,
+bool DictionaryValue::Get(StringPiece path,
const Value** out_value) const {
DCHECK(IsStringUTF8(path));
- std::string current_path(path);
+ StringPiece current_path(path);
const DictionaryValue* current_dictionary = this;
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))
+ if (!current_dictionary->GetDictionaryWithoutPathExpansion(
+ current_path.substr(0, delimiter_position).as_string(),
+ &child_dictionary)) {
return false;
+ }
current_dictionary = child_dictionary;
- current_path.erase(0, delimiter_position + 1);
+ current_path = current_path.substr(delimiter_position + 1);
}
- return current_dictionary->GetWithoutPathExpansion(current_path, out_value);
+ return current_dictionary->GetWithoutPathExpansion(current_path.as_string(),
+ out_value);
}
-bool DictionaryValue::Get(const std::string& path, Value** out_value) {
+bool DictionaryValue::Get(StringPiece path, Value** out_value) {
return static_cast<const DictionaryValue&>(*this).Get(
path,
const_cast<const Value**>(out_value));
@@ -588,7 +600,7 @@ bool DictionaryValue::GetBinary(const std::string& path,
const_cast<const BinaryValue**>(out_value));
}
-bool DictionaryValue::GetDictionary(const std::string& path,
+bool DictionaryValue::GetDictionary(StringPiece path,
const DictionaryValue** out_value) const {
const Value* value;
bool result = Get(path, &value);
@@ -601,7 +613,7 @@ bool DictionaryValue::GetDictionary(const std::string& path,
return true;
}
-bool DictionaryValue::GetDictionary(const std::string& path,
+bool DictionaryValue::GetDictionary(StringPiece path,
DictionaryValue** out_value) {
return static_cast<const DictionaryValue&>(*this).GetDictionary(
path,
@@ -867,6 +879,16 @@ bool DictionaryValue::Equals(const Value* other) const {
///////////////////// ListValue ////////////////////
+// static
+scoped_ptr<ListValue> ListValue::From(scoped_ptr<Value> value) {
+ ListValue* out;
+ if (value && value->GetAsList(&out)) {
+ ignore_result(value.release());
+ return make_scoped_ptr(out);
+ }
+ return nullptr;
+}
+
ListValue::ListValue() : Value(TYPE_LIST) {
}
diff --git a/base/values.h b/base/values.h
index 7feef9da54..07e5b6c838 100644
--- a/base/values.h
+++ b/base/values.h
@@ -9,7 +9,7 @@
// 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
+// IN PARTICULAR this means that there is no support for int64_t 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.
@@ -18,6 +18,7 @@
#define BASE_VALUES_H_
#include <stddef.h>
+#include <stdint.h>
#include <iosfwd>
#include <map>
@@ -26,10 +27,11 @@
#include <vector>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
namespace base {
@@ -208,6 +210,9 @@ class BASE_EXPORT BinaryValue: public Value {
// are |std::string|s and should be UTF-8 encoded.
class BASE_EXPORT DictionaryValue : public Value {
public:
+ // Returns |value| if it is a dictionary, nullptr otherwise.
+ static scoped_ptr<DictionaryValue> From(scoped_ptr<Value> value);
+
DictionaryValue();
~DictionaryValue() override;
@@ -270,8 +275,8 @@ class BASE_EXPORT DictionaryValue : public Value {
// Otherwise, it will return false and |out_value| will be untouched.
// Note that the dictionary always owns the value that's returned.
// |out_value| is optional and will only be set if non-NULL.
- bool Get(const std::string& path, const Value** out_value) const;
- bool Get(const std::string& path, Value** out_value);
+ bool Get(StringPiece path, const Value** out_value) const;
+ bool Get(StringPiece 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
@@ -287,9 +292,9 @@ class BASE_EXPORT DictionaryValue : public Value {
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,
+ bool GetDictionary(StringPiece path,
const DictionaryValue** out_value) const;
- bool GetDictionary(const std::string& path, DictionaryValue** out_value);
+ bool GetDictionary(StringPiece path, DictionaryValue** out_value);
bool GetList(const std::string& path, const ListValue** out_value) const;
bool GetList(const std::string& path, ListValue** out_value);
@@ -386,6 +391,9 @@ class BASE_EXPORT ListValue : public Value {
typedef ValueVector::iterator iterator;
typedef ValueVector::const_iterator const_iterator;
+ // Returns |value| if it is a list, nullptr otherwise.
+ static scoped_ptr<ListValue> From(scoped_ptr<Value> value);
+
ListValue();
~ListValue() override;
@@ -524,7 +532,8 @@ class BASE_EXPORT ValueDeserializer {
// 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;
+ virtual scoped_ptr<Value> Deserialize(int* error_code,
+ std::string* error_str) = 0;
};
// Stream operator so Values can be used in assertion statements. In order that
diff --git a/base/values_unittest.cc b/base/values_unittest.cc
index 37ed7cecb7..66453e013b 100644
--- a/base/values_unittest.cc
+++ b/base/values_unittest.cc
@@ -2,7 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stddef.h>
+
#include <limits>
+#include <utility>
#include "base/memory/scoped_ptr.h"
#include "base/strings/string16.h"
@@ -34,13 +37,13 @@ TEST(ValuesTest, Basic) {
settings.GetList("global.toolbar.bookmarks", &toolbar_bookmarks));
scoped_ptr<ListValue> new_toolbar_bookmarks(new ListValue);
- settings.Set("global.toolbar.bookmarks", new_toolbar_bookmarks.Pass());
+ settings.Set("global.toolbar.bookmarks", std::move(new_toolbar_bookmarks));
ASSERT_TRUE(settings.GetList("global.toolbar.bookmarks", &toolbar_bookmarks));
scoped_ptr<DictionaryValue> new_bookmark(new DictionaryValue);
new_bookmark->SetString("name", "Froogle");
new_bookmark->SetString("url", "http://froogle.com");
- toolbar_bookmarks->Append(new_bookmark.Pass());
+ toolbar_bookmarks->Append(std::move(new_bookmark));
ListValue* bookmark_list;
ASSERT_TRUE(settings.GetList("global.toolbar.bookmarks", &bookmark_list));
@@ -114,7 +117,7 @@ TEST(ValuesTest, BinaryValue) {
// Test the common case of a non-empty buffer
scoped_ptr<char[]> buffer(new char[15]);
char* original_buffer = buffer.get();
- binary.reset(new BinaryValue(buffer.Pass(), 15));
+ binary.reset(new BinaryValue(std::move(buffer), 15));
ASSERT_TRUE(binary.get());
ASSERT_TRUE(binary->GetBuffer());
ASSERT_EQ(original_buffer, binary->GetBuffer());
@@ -250,7 +253,7 @@ TEST(ValuesTest, ListRemoval) {
ListValue list;
scoped_ptr<DeletionTestValue> value(new DeletionTestValue(&deletion_flag));
DeletionTestValue* original_value = value.get();
- list.Append(value.Pass());
+ list.Append(std::move(value));
EXPECT_FALSE(deletion_flag);
size_t index = 0;
list.Remove(*original_value, &index);
@@ -393,45 +396,45 @@ TEST(ValuesTest, DeepCopy) {
DictionaryValue original_dict;
scoped_ptr<Value> scoped_null = Value::CreateNullValue();
Value* original_null = scoped_null.get();
- original_dict.Set("null", scoped_null.Pass());
+ original_dict.Set("null", std::move(scoped_null));
scoped_ptr<FundamentalValue> scoped_bool(new FundamentalValue(true));
FundamentalValue* original_bool = scoped_bool.get();
- original_dict.Set("bool", scoped_bool.Pass());
+ original_dict.Set("bool", std::move(scoped_bool));
scoped_ptr<FundamentalValue> scoped_int(new FundamentalValue(42));
FundamentalValue* original_int = scoped_int.get();
- original_dict.Set("int", scoped_int.Pass());
+ original_dict.Set("int", std::move(scoped_int));
scoped_ptr<FundamentalValue> scoped_double(new FundamentalValue(3.14));
FundamentalValue* original_double = scoped_double.get();
- original_dict.Set("double", scoped_double.Pass());
+ original_dict.Set("double", std::move(scoped_double));
scoped_ptr<StringValue> scoped_string(new StringValue("hello"));
StringValue* original_string = scoped_string.get();
- original_dict.Set("string", scoped_string.Pass());
+ original_dict.Set("string", std::move(scoped_string));
scoped_ptr<StringValue> scoped_string16(
new StringValue(ASCIIToUTF16("hello16")));
StringValue* original_string16 = scoped_string16.get();
- original_dict.Set("string16", scoped_string16.Pass());
+ original_dict.Set("string16", std::move(scoped_string16));
scoped_ptr<char[]> original_buffer(new char[42]);
memset(original_buffer.get(), '!', 42);
scoped_ptr<BinaryValue> scoped_binary(
- new BinaryValue(original_buffer.Pass(), 42));
+ new BinaryValue(std::move(original_buffer), 42));
BinaryValue* original_binary = scoped_binary.get();
- original_dict.Set("binary", scoped_binary.Pass());
+ original_dict.Set("binary", std::move(scoped_binary));
scoped_ptr<ListValue> scoped_list(new ListValue());
Value* original_list = scoped_list.get();
scoped_ptr<FundamentalValue> scoped_list_element_0(new FundamentalValue(0));
Value* original_list_element_0 = scoped_list_element_0.get();
- scoped_list->Append(scoped_list_element_0.Pass());
+ scoped_list->Append(std::move(scoped_list_element_0));
scoped_ptr<FundamentalValue> scoped_list_element_1(new FundamentalValue(1));
Value* original_list_element_1 = scoped_list_element_1.get();
- scoped_list->Append(scoped_list_element_1.Pass());
- original_dict.Set("list", scoped_list.Pass());
+ scoped_list->Append(std::move(scoped_list_element_1));
+ original_dict.Set("list", std::move(scoped_list));
scoped_ptr<DictionaryValue> scoped_nested_dictionary(new DictionaryValue());
Value* original_nested_dictionary = scoped_nested_dictionary.get();
scoped_nested_dictionary->SetString("key", "value");
- original_dict.Set("dictionary", scoped_nested_dictionary.Pass());
+ original_dict.Set("dictionary", std::move(scoped_nested_dictionary));
scoped_ptr<DictionaryValue> copy_dict = original_dict.CreateDeepCopy();
ASSERT_TRUE(copy_dict.get());
@@ -568,9 +571,9 @@ TEST(ValuesTest, Equals) {
list->Append(make_scoped_ptr(new DictionaryValue));
scoped_ptr<Value> list_copy(list->CreateDeepCopy());
- dv.Set("f", list.Pass());
+ dv.Set("f", std::move(list));
EXPECT_FALSE(dv.Equals(copy.get()));
- copy->Set("f", list_copy.Pass());
+ copy->Set("f", std::move(list_copy));
EXPECT_TRUE(dv.Equals(copy.get()));
original_list->Append(make_scoped_ptr(new FundamentalValue(true)));
@@ -611,38 +614,38 @@ TEST(ValuesTest, DeepCopyCovariantReturnTypes) {
DictionaryValue original_dict;
scoped_ptr<Value> scoped_null(Value::CreateNullValue());
Value* original_null = scoped_null.get();
- original_dict.Set("null", scoped_null.Pass());
+ original_dict.Set("null", std::move(scoped_null));
scoped_ptr<FundamentalValue> scoped_bool(new FundamentalValue(true));
Value* original_bool = scoped_bool.get();
- original_dict.Set("bool", scoped_bool.Pass());
+ original_dict.Set("bool", std::move(scoped_bool));
scoped_ptr<FundamentalValue> scoped_int(new FundamentalValue(42));
Value* original_int = scoped_int.get();
- original_dict.Set("int", scoped_int.Pass());
+ original_dict.Set("int", std::move(scoped_int));
scoped_ptr<FundamentalValue> scoped_double(new FundamentalValue(3.14));
Value* original_double = scoped_double.get();
- original_dict.Set("double", scoped_double.Pass());
+ original_dict.Set("double", std::move(scoped_double));
scoped_ptr<StringValue> scoped_string(new StringValue("hello"));
Value* original_string = scoped_string.get();
- original_dict.Set("string", scoped_string.Pass());
+ original_dict.Set("string", std::move(scoped_string));
scoped_ptr<StringValue> scoped_string16(
new StringValue(ASCIIToUTF16("hello16")));
Value* original_string16 = scoped_string16.get();
- original_dict.Set("string16", scoped_string16.Pass());
+ original_dict.Set("string16", std::move(scoped_string16));
scoped_ptr<char[]> original_buffer(new char[42]);
memset(original_buffer.get(), '!', 42);
scoped_ptr<BinaryValue> scoped_binary(
- new BinaryValue(original_buffer.Pass(), 42));
+ new BinaryValue(std::move(original_buffer), 42));
Value* original_binary = scoped_binary.get();
- original_dict.Set("binary", scoped_binary.Pass());
+ original_dict.Set("binary", std::move(scoped_binary));
scoped_ptr<ListValue> scoped_list(new ListValue());
Value* original_list = scoped_list.get();
scoped_ptr<FundamentalValue> scoped_list_element_0(new FundamentalValue(0));
- scoped_list->Append(scoped_list_element_0.Pass());
+ scoped_list->Append(std::move(scoped_list_element_0));
scoped_ptr<FundamentalValue> scoped_list_element_1(new FundamentalValue(1));
- scoped_list->Append(scoped_list_element_1.Pass());
- original_dict.Set("list", scoped_list.Pass());
+ scoped_list->Append(std::move(scoped_list_element_1));
+ original_dict.Set("list", std::move(scoped_list));
scoped_ptr<Value> copy_dict = original_dict.CreateDeepCopy();
scoped_ptr<Value> copy_null = original_null->CreateDeepCopy();
@@ -697,7 +700,7 @@ TEST(ValuesTest, RemoveEmptyChildren) {
scoped_ptr<DictionaryValue> inner(new DictionaryValue);
inner->Set("empty_dict", make_scoped_ptr(new DictionaryValue));
inner->Set("empty_list", make_scoped_ptr(new ListValue));
- root->Set("dict_with_empty_children", inner.Pass());
+ root->Set("dict_with_empty_children", std::move(inner));
root = root->DeepCopyWithoutEmptyChildren();
EXPECT_EQ(2U, root->size());
}
@@ -705,7 +708,7 @@ TEST(ValuesTest, RemoveEmptyChildren) {
scoped_ptr<ListValue> inner(new ListValue);
inner->Append(make_scoped_ptr(new DictionaryValue));
inner->Append(make_scoped_ptr(new ListValue));
- root->Set("list_with_empty_children", inner.Pass());
+ root->Set("list_with_empty_children", std::move(inner));
root = root->DeepCopyWithoutEmptyChildren();
EXPECT_EQ(2U, root->size());
}
@@ -715,11 +718,11 @@ TEST(ValuesTest, RemoveEmptyChildren) {
scoped_ptr<ListValue> inner(new ListValue());
inner->Append(make_scoped_ptr(new DictionaryValue));
inner->Append(make_scoped_ptr(new ListValue));
- root->Set("list_with_empty_children", inner.Pass());
+ root->Set("list_with_empty_children", std::move(inner));
scoped_ptr<DictionaryValue> inner2(new DictionaryValue);
inner2->Set("empty_dict", make_scoped_ptr(new DictionaryValue));
inner2->Set("empty_list", make_scoped_ptr(new ListValue));
- root->Set("dict_with_empty_children", inner2.Pass());
+ root->Set("dict_with_empty_children", std::move(inner2));
root = root->DeepCopyWithoutEmptyChildren();
EXPECT_EQ(2U, root->size());
}
@@ -730,8 +733,8 @@ TEST(ValuesTest, RemoveEmptyChildren) {
scoped_ptr<ListValue> inner2(new ListValue);
inner2->Append(make_scoped_ptr(new StringValue("hello")));
inner->Append(make_scoped_ptr(new DictionaryValue));
- inner->Append(inner2.Pass());
- root->Set("list_with_empty_children", inner.Pass());
+ inner->Append(std::move(inner2));
+ root->Set("list_with_empty_children", std::move(inner));
root = root->DeepCopyWithoutEmptyChildren();
EXPECT_EQ(3U, root->size());
@@ -750,7 +753,7 @@ TEST(ValuesTest, MergeDictionary) {
scoped_ptr<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.Pass());
+ base->Set("sub_dict_key", std::move(base_sub_dict));
scoped_ptr<DictionaryValue> merge(new DictionaryValue);
merge->SetString("merge_key", "merge_key_value_merge");
@@ -758,7 +761,7 @@ TEST(ValuesTest, MergeDictionary) {
scoped_ptr<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.Pass());
+ merge->Set("sub_dict_key", std::move(merge_sub_dict));
base->MergeDictionary(merge.get());
@@ -799,7 +802,7 @@ TEST(ValuesTest, MergeDictionaryDeepCopy) {
EXPECT_EQ("value", value);
scoped_ptr<DictionaryValue> base(new DictionaryValue);
- base->Set("dict", child.Pass());
+ base->Set("dict", std::move(child));
EXPECT_EQ(1U, base->size());
DictionaryValue* ptr;
diff --git a/base/vlog.cc b/base/vlog.cc
index 519ceff10c..c00e63185a 100644
--- a/base/vlog.cc
+++ b/base/vlog.cc
@@ -4,12 +4,13 @@
#include "base/vlog.h"
-#include <cstddef>
+#include <stddef.h>
+
#include <ostream>
#include <utility>
-#include "base/basictypes.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
diff --git a/base/vlog.h b/base/vlog.h
index a32ed14c7d..2950904c55 100644
--- a/base/vlog.h
+++ b/base/vlog.h
@@ -9,7 +9,7 @@
#include <vector>
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/strings/string_piece.h"
namespace logging {
diff --git a/base/vlog_unittest.cc b/base/vlog_unittest.cc
index b505d4cbf5..3c3f49cb13 100644
--- a/base/vlog_unittest.cc
+++ b/base/vlog_unittest.cc
@@ -4,7 +4,6 @@
#include "base/vlog.h"
-#include "base/basictypes.h"
#include "base/logging.h"
#include "base/time/time.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/base/win/OWNERS b/base/win/OWNERS
index 8624efe736..78473b9e74 100644
--- a/base/win/OWNERS
+++ b/base/win/OWNERS
@@ -1,3 +1,4 @@
cpu@chromium.org
grt@chromium.org
-rvargas@chromium.org
+jschuh@chromium.org
+scottmg@chromium.org
diff --git a/base/win/event_trace_consumer.h b/base/win/event_trace_consumer.h
index fd44894993..9f97e0df65 100644
--- a/base/win/event_trace_consumer.h
+++ b/base/win/event_trace_consumer.h
@@ -9,8 +9,10 @@
#include <windows.h>
#include <wmistr.h>
#include <evntrace.h>
+#include <stddef.h>
#include <vector>
-#include "base/basictypes.h"
+
+#include "base/macros.h"
namespace base {
namespace win {
diff --git a/base/win/scoped_co_mem.h b/base/win/scoped_co_mem.h
index fc85114828..a3737dd571 100644
--- a/base/win/scoped_co_mem.h
+++ b/base/win/scoped_co_mem.h
@@ -7,8 +7,8 @@
#include <objbase.h>
-#include "base/basictypes.h"
#include "base/logging.h"
+#include "base/macros.h"
namespace base {
namespace win {
diff --git a/base/win/scoped_com_initializer.h b/base/win/scoped_com_initializer.h
index 92228baa50..8efff856f0 100644
--- a/base/win/scoped_com_initializer.h
+++ b/base/win/scoped_com_initializer.h
@@ -7,8 +7,8 @@
#include <objbase.h>
-#include "base/basictypes.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "build/build_config.h"
namespace base {
diff --git a/base/win/scoped_comptr.h b/base/win/scoped_comptr.h
index 373c0c3ba5..5ce60e2b68 100644
--- a/base/win/scoped_comptr.h
+++ b/base/win/scoped_comptr.h
@@ -43,8 +43,9 @@ class ScopedComPtr : public scoped_refptr<Interface> {
~ScopedComPtr() {
// We don't want the smart pointer class to be bigger than the pointer
// it wraps.
- COMPILE_ASSERT(sizeof(ScopedComPtr<Interface, interface_id>) ==
- sizeof(Interface*), ScopedComPtrSize);
+ static_assert(
+ sizeof(ScopedComPtr<Interface, interface_id>) == sizeof(Interface*),
+ "ScopedComPtrSize");
}
// Explicit Release() of the held object. Useful for reuse of the
@@ -52,24 +53,24 @@ class ScopedComPtr : public scoped_refptr<Interface> {
// 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;
+ if (this->ptr_ != NULL) {
+ this->ptr_->Release();
+ this->ptr_ = NULL;
}
}
// Sets the internal pointer to NULL and returns the held object without
// releasing the reference.
Interface* Detach() {
- Interface* p = ptr_;
- ptr_ = NULL;
+ Interface* p = this->ptr_;
+ this->ptr_ = NULL;
return p;
}
// Accepts an interface pointer that has already been addref-ed.
void Attach(Interface* p) {
- DCHECK(!ptr_);
- ptr_ = p;
+ DCHECK(!this->ptr_);
+ this->ptr_ = p;
}
// Retrieves the pointer address.
@@ -77,8 +78,8 @@ class ScopedComPtr : public scoped_refptr<Interface> {
// 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_;
+ DCHECK(!this->ptr_) << "Object leak. Pointer must be NULL";
+ return &this->ptr_;
}
// A convenience for whenever a void pointer is needed as an out argument.
@@ -89,18 +90,18 @@ class ScopedComPtr : public scoped_refptr<Interface> {
template <class Query>
HRESULT QueryInterface(Query** p) {
DCHECK(p != NULL);
- DCHECK(ptr_ != NULL);
+ DCHECK(this->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);
+ return this->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);
+ DCHECK(this->ptr_ != NULL);
+ return this->ptr_->QueryInterface(iid, obj);
}
// Queries |other| for the interface this object wraps and returns the
@@ -113,18 +114,18 @@ class ScopedComPtr : public scoped_refptr<Interface> {
// Convenience wrapper around CoCreateInstance
HRESULT CreateInstance(const CLSID& clsid, IUnknown* outer = NULL,
DWORD context = CLSCTX_ALL) {
- DCHECK(!ptr_);
+ DCHECK(!this->ptr_);
HRESULT hr = ::CoCreateInstance(clsid, outer, context, *interface_id,
- reinterpret_cast<void**>(&ptr_));
+ reinterpret_cast<void**>(&this->ptr_));
return hr;
}
// Checks if the identity of |other| and this object is the same.
bool IsSameObject(IUnknown* other) {
- if (!other && !ptr_)
+ if (!other && !this->ptr_)
return true;
- if (!other || !ptr_)
+ if (!other || !this->ptr_)
return false;
ScopedComPtr<IUnknown> my_identity;
@@ -147,8 +148,8 @@ class ScopedComPtr : public scoped_refptr<Interface> {
// 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<BlockIUnknownMethods*>(ptr_);
+ DCHECK(this->ptr_ != NULL);
+ return reinterpret_cast<BlockIUnknownMethods*>(this->ptr_);
}
// Pull in operator=() from the parent class.
diff --git a/base/win/scoped_gdi_object.h b/base/win/scoped_gdi_object.h
index 57b013e2fb..9d8465b25b 100644
--- a/base/win/scoped_gdi_object.h
+++ b/base/win/scoped_gdi_object.h
@@ -7,64 +7,32 @@
#include <windows.h>
-#include "base/basictypes.h"
-#include "base/logging.h"
+#include "base/scoped_generic.h"
namespace base {
namespace win {
-// Like ScopedHandle but for GDI objects.
-template<class T>
-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;
- }
+namespace internal {
- operator T() { return object_; }
-
- private:
- void Close() {
- if (object_)
- DeleteObject(object_);
- }
-
- T object_;
- DISALLOW_COPY_AND_ASSIGN(ScopedGDIObject);
+template <class T>
+struct ScopedGDIObjectTraits {
+ static T InvalidValue() { return nullptr; }
+ static void Free(T object) { DeleteObject(object); }
};
// An explicit specialization for HICON because we have to call DestroyIcon()
// instead of DeleteObject() for HICON.
-template<>
-void inline ScopedGDIObject<HICON>::Close() {
- if (object_)
- DestroyIcon(object_);
+template <>
+void inline ScopedGDIObjectTraits<HICON>::Free(HICON icon) {
+ DestroyIcon(icon);
}
+} // namespace internal
+
+// Like ScopedHandle but for GDI objects.
+template <class T>
+using ScopedGDIObject = ScopedGeneric<T, internal::ScopedGDIObjectTraits<T>>;
+
// Typedefs for some common use cases.
typedef ScopedGDIObject<HBITMAP> ScopedBitmap;
typedef ScopedGDIObject<HRGN> ScopedRegion;
diff --git a/base/win/scoped_hdc.h b/base/win/scoped_hdc.h
index 2452067dfb..fa686dd050 100644
--- a/base/win/scoped_hdc.h
+++ b/base/win/scoped_hdc.h
@@ -7,8 +7,8 @@
#include <windows.h>
-#include "base/basictypes.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/win/scoped_handle.h"
namespace base {
diff --git a/base/win/scoped_hglobal.h b/base/win/scoped_hglobal.h
index 185ccbd5f0..abe9a5a3dd 100644
--- a/base/win/scoped_hglobal.h
+++ b/base/win/scoped_hglobal.h
@@ -6,8 +6,9 @@
#define BASE_WIN_SCOPED_HGLOBAL_H_
#include <windows.h>
+#include <stddef.h>
-#include "base/basictypes.h"
+#include "base/macros.h"
namespace base {
namespace win {
diff --git a/base/win/scoped_propvariant.h b/base/win/scoped_propvariant.h
index 62cc6a6d15..aa9afec1c1 100644
--- a/base/win/scoped_propvariant.h
+++ b/base/win/scoped_propvariant.h
@@ -7,8 +7,8 @@
#include <propidl.h>
-#include "base/basictypes.h"
#include "base/logging.h"
+#include "base/macros.h"
namespace base {
namespace win {
diff --git a/base/win/scoped_select_object.h b/base/win/scoped_select_object.h
index 347de798e2..59b21c1335 100644
--- a/base/win/scoped_select_object.h
+++ b/base/win/scoped_select_object.h
@@ -7,8 +7,8 @@
#include <windows.h>
-#include "base/basictypes.h"
#include "base/logging.h"
+#include "base/macros.h"
namespace base {
namespace win {
diff --git a/components/timers/alarm_timer_chromeos.cc b/components/timers/alarm_timer_chromeos.cc
index 60b7353d22..ae14870c56 100644
--- a/components/timers/alarm_timer_chromeos.cc
+++ b/components/timers/alarm_timer_chromeos.cc
@@ -4,7 +4,9 @@
#include "components/timers/alarm_timer_chromeos.h"
+#include <stdint.h>
#include <sys/timerfd.h>
+#include <utility>
#include "base/bind.h"
#include "base/bind_helpers.h"
@@ -16,6 +18,7 @@
#include "base/pending_task.h"
#include "base/thread_task_runner_handle.h"
#include "base/threading/thread.h"
+#include "base/trace_event/trace_event.h"
namespace timers {
namespace {
@@ -352,6 +355,9 @@ void AlarmTimer::Init() {
}
void AlarmTimer::Stop() {
+ if (!base::Timer::is_running())
+ return;
+
if (!can_wake_from_suspend_) {
base::Timer::Stop();
return;
@@ -422,7 +428,7 @@ void AlarmTimer::OnTimerFired() {
// Take ownership of the pending user task, which is going to be cleared by
// the Stop() or Reset() functions below.
- scoped_ptr<base::PendingTask> pending_user_task(pending_task_.Pass());
+ scoped_ptr<base::PendingTask> pending_user_task(std::move(pending_task_));
// Re-schedule or stop the timer as requested.
if (base::Timer::is_repeating())
@@ -430,9 +436,11 @@ void AlarmTimer::OnTimerFired() {
else
Stop();
+ TRACE_TASK_EXECUTION("AlarmTimer::OnTimerFired", *pending_user_task);
+
// Now run the user task.
- base::MessageLoop::current()->task_annotator()->RunTask(
- "AlarmTimer::Reset", "AlarmTimer::OnTimerFired", *pending_user_task);
+ base::MessageLoop::current()->task_annotator()->RunTask("AlarmTimer::Reset",
+ *pending_user_task);
}
OneShotAlarmTimer::OneShotAlarmTimer() : AlarmTimer(false, false) {
diff --git a/crypto/BUILD.gn b/crypto/BUILD.gn
index f84c4d455d..8d24e609e1 100644
--- a/crypto/BUILD.gn
+++ b/crypto/BUILD.gn
@@ -19,8 +19,9 @@ component("crypto") {
"cssm_init.cc",
"cssm_init.h",
"curve25519-donna.c",
- "curve25519.cc",
"curve25519.h",
+ "curve25519_nss.cc",
+ "curve25519_openssl.cc",
"ec_private_key.h",
"ec_private_key_nss.cc",
"ec_private_key_openssl.cc",
@@ -136,6 +137,8 @@ component("crypto") {
if (use_openssl) {
# Remove NSS files when using OpenSSL
sources -= [
+ "curve25519-donna.c",
+ "curve25519_nss.cc",
"ec_private_key_nss.cc",
"ec_signature_creator_nss.cc",
"encryptor_nss.cc",
@@ -157,6 +160,7 @@ component("crypto") {
sources -= [
"aead_openssl.cc",
"aead_openssl.h",
+ "curve25519_openssl.cc",
"ec_private_key_openssl.cc",
"ec_signature_creator_openssl.cc",
"encryptor_openssl.cc",
@@ -186,6 +190,10 @@ component("crypto") {
}
defines = [ "CRYPTO_IMPLEMENTATION" ]
+
+ if (is_nacl) {
+ deps += [ "//native_client_sdk/src/libraries/nacl_io" ]
+ }
}
# TODO(GYP): TODO(dpranke), fix the compile errors for this stuff
@@ -220,9 +228,18 @@ if (false && is_win) {
}
}
+# TODO(GYP): Delete this after we've converted everything to GN.
+# The _run targets exist only for compatibility w/ GYP.
+group("crypto_unittests_run") {
+ testonly = true
+ deps = [
+ ":crypto_unittests",
+ ]
+}
+
test("crypto_unittests") {
sources = [
- # Tests.
+ "aead_openssl_unittest.cc",
"curve25519_unittest.cc",
"ec_private_key_unittest.cc",
"ec_signature_creator_unittest.cc",
@@ -316,11 +333,11 @@ config("platform_config") {
# on the current SSL library should just depend on this.
group("platform") {
if (use_openssl) {
- deps = [
+ public_deps = [
"//third_party/boringssl",
]
} else {
- deps = [
+ public_deps = [
"//net/third_party/nss/ssl:libssl",
]
}
@@ -345,7 +362,7 @@ group("platform") {
public_configs += [ "//third_party/nss:system_nss_no_ssl_config" ]
} else {
# Non-Linux platforms use the hermetic NSS from the tree.
- deps += [
+ public_deps += [
"//third_party/nss:nspr",
"//third_party/nss:nss",
]
diff --git a/crypto/OWNERS b/crypto/OWNERS
index bde32a088b..42d0d3b58b 100644
--- a/crypto/OWNERS
+++ b/crypto/OWNERS
@@ -1,5 +1,3 @@
agl@chromium.org
davidben@chromium.org
rsleevi@chromium.org
-rvargas@chromium.org
-wtc@chromium.org
diff --git a/crypto/apple_keychain.h b/crypto/apple_keychain.h
index 840ccee8c2..1ea2473547 100644
--- a/crypto/apple_keychain.h
+++ b/crypto/apple_keychain.h
@@ -7,7 +7,8 @@
#include <Security/Security.h>
-#include "base/basictypes.h"
+#include "base/macros.h"
+#include "build/build_config.h"
#include "crypto/crypto_export.h"
#if defined (OS_IOS)
diff --git a/crypto/crypto.gyp b/crypto/crypto.gyp
index e6bff0b098..2590c4fbdb 100644
--- a/crypto/crypto.gyp
+++ b/crypto/crypto.gyp
@@ -94,7 +94,6 @@
[ 'OS == "win"', {
'msvs_disabled_warnings': [
4267, # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 4018,
],
}],
[ 'use_openssl==1', {
@@ -104,6 +103,8 @@
# TODO(joth): Use a glob to match exclude patterns once the
# OpenSSL file set is complete.
'sources!': [
+ 'curve25519-donna.c',
+ 'curve25519_nss.cc',
'ec_private_key_nss.cc',
'ec_signature_creator_nss.cc',
'encryptor_nss.cc',
@@ -127,6 +128,7 @@
'sources!': [
'aead_openssl.cc',
'aead_openssl.h',
+ 'curve25519_openssl.cc',
'ec_private_key_openssl.cc',
'ec_signature_creator_openssl.cc',
'encryptor_openssl.cc',
@@ -255,9 +257,6 @@
'CRYPTO_IMPLEMENTATION',
'<@(nacl_win64_defines)',
],
- 'msvs_disabled_warnings': [
- 4018,
- ],
'configurations': {
'Common_Base': {
'msvs_target_platform': 'x64',
diff --git a/crypto/crypto.gypi b/crypto/crypto.gypi
index 73b3332260..e5cc4f44d3 100644
--- a/crypto/crypto.gypi
+++ b/crypto/crypto.gypi
@@ -37,9 +37,10 @@
'crypto_export.h',
'cssm_init.cc',
'cssm_init.h',
- 'curve25519.cc',
- 'curve25519.h',
'curve25519-donna.c',
+ 'curve25519.h',
+ 'curve25519_nss.cc',
+ 'curve25519_openssl.cc',
'ghash.cc',
'ghash.h',
'ec_private_key.h',
diff --git a/crypto/crypto_export.h b/crypto/crypto_export.h
index 983afe6d09..605af94e29 100644
--- a/crypto/crypto_export.h
+++ b/crypto/crypto_export.h
@@ -6,33 +6,27 @@
#define CRYPTO_CRYPTO_EXPORT_H_
// Defines CRYPTO_EXPORT so that functionality implemented by the crypto module
-// can be exported to consumers, and CRYPTO_EXPORT_PRIVATE that allows unit
-// tests to access features not intended to be used directly by real consumers.
+// can be exported to consumers.
#if defined(COMPONENT_BUILD)
#if defined(WIN32)
#if defined(CRYPTO_IMPLEMENTATION)
#define CRYPTO_EXPORT __declspec(dllexport)
-#define CRYPTO_EXPORT_PRIVATE __declspec(dllexport)
#else
#define CRYPTO_EXPORT __declspec(dllimport)
-#define CRYPTO_EXPORT_PRIVATE __declspec(dllimport)
#endif // defined(CRYPTO_IMPLEMENTATION)
#else // defined(WIN32)
#if defined(CRYPTO_IMPLEMENTATION)
#define CRYPTO_EXPORT __attribute__((visibility("default")))
-#define CRYPTO_EXPORT_PRIVATE __attribute__((visibility("default")))
#else
#define CRYPTO_EXPORT
-#define CRYPTO_EXPORT_PRIVATE
#endif
#endif
#else // defined(COMPONENT_BUILD)
#define CRYPTO_EXPORT
-#define CRYPTO_EXPORT_PRIVATE
#endif
#endif // CRYPTO_CRYPTO_EXPORT_H_
diff --git a/crypto/crypto_unittests.isolate b/crypto/crypto_unittests.isolate
index e09095c142..de13aa23a7 100644
--- a/crypto/crypto_unittests.isolate
+++ b/crypto/crypto_unittests.isolate
@@ -18,9 +18,7 @@
'variables': {
'files': [
'../testing/test_env.py',
- '<(PRODUCT_DIR)/crypto_unittests<(EXECUTABLE_SUFFIX)',
],
- 'read_only': 1,
},
}],
['OS=="mac" and asan==1 and fastbuild==0', {
diff --git a/crypto/ec_private_key.h b/crypto/ec_private_key.h
index 87af838904..9a8a02acfb 100644
--- a/crypto/ec_private_key.h
+++ b/crypto/ec_private_key.h
@@ -5,10 +5,13 @@
#ifndef CRYPTO_EC_PRIVATE_KEY_H_
#define CRYPTO_EC_PRIVATE_KEY_H_
+#include <stddef.h>
+#include <stdint.h>
+
#include <string>
#include <vector>
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "build/build_config.h"
#include "crypto/crypto_export.h"
@@ -34,9 +37,6 @@ class CRYPTO_EXPORT ECPrivateKey {
public:
~ECPrivateKey();
- // Returns whether the system supports elliptic curve cryptography.
- static bool IsSupported();
-
// Creates a new random instance. Can return NULL if initialization fails.
// The created key will use the NIST P-256 curve.
// TODO(mattm): Add a curve parameter.
@@ -48,8 +48,8 @@ class CRYPTO_EXPORT ECPrivateKey {
// Returns NULL if initialization fails.
static ECPrivateKey* CreateFromEncryptedPrivateKeyInfo(
const std::string& password,
- const std::vector<uint8>& encrypted_private_key_info,
- const std::vector<uint8>& subject_public_key_info);
+ const std::vector<uint8_t>& encrypted_private_key_info,
+ const std::vector<uint8_t>& subject_public_key_info);
#if !defined(USE_OPENSSL)
// Imports the key pair into |slot| and returns in |public_key| and |key|.
@@ -59,7 +59,7 @@ class CRYPTO_EXPORT ECPrivateKey {
static bool ImportFromEncryptedPrivateKeyInfo(
PK11SlotInfo* slot,
const std::string& password,
- const uint8* encrypted_private_key_info,
+ const uint8_t* encrypted_private_key_info,
size_t encrypted_private_key_info_len,
CERTSubjectPublicKeyInfo* decoded_spki,
bool permanent,
@@ -85,18 +85,18 @@ class CRYPTO_EXPORT ECPrivateKey {
// of 1000 iterations, on modern systems a larger value may be preferrable.
bool ExportEncryptedPrivateKey(const std::string& password,
int iterations,
- std::vector<uint8>* output);
+ std::vector<uint8_t>* output);
// Exports the public key to an X.509 SubjectPublicKeyInfo block.
- bool ExportPublicKey(std::vector<uint8>* output);
+ bool ExportPublicKey(std::vector<uint8_t>* output);
// Exports the public key as an EC point in the uncompressed point format.
bool ExportRawPublicKey(std::string* output);
// Exports private key data for testing. The format of data stored into output
// doesn't matter other than that it is consistent for the same key.
- bool ExportValue(std::vector<uint8>* output);
- bool ExportECParams(std::vector<uint8>* output);
+ bool ExportValue(std::vector<uint8_t>* output);
+ bool ExportECParams(std::vector<uint8_t>* output);
private:
// Constructor is private. Use one of the Create*() methods above instead.
diff --git a/crypto/ec_signature_creator_impl.h b/crypto/ec_signature_creator_impl.h
index 91a60a8996..21614f8201 100644
--- a/crypto/ec_signature_creator_impl.h
+++ b/crypto/ec_signature_creator_impl.h
@@ -5,7 +5,10 @@
#ifndef CRYPTO_EC_SIGNATURE_CREATOR_IMPL_H_
#define CRYPTO_EC_SIGNATURE_CREATOR_IMPL_H_
+#include <stdint.h>
+
#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "crypto/ec_signature_creator.h"
namespace crypto {
@@ -15,16 +18,15 @@ class ECSignatureCreatorImpl : public ECSignatureCreator {
explicit ECSignatureCreatorImpl(ECPrivateKey* key);
~ECSignatureCreatorImpl() override;
- bool Sign(const uint8* data,
+ bool Sign(const uint8_t* data,
int data_len,
- std::vector<uint8>* signature) override;
+ std::vector<uint8_t>* signature) override;
- bool DecodeSignature(const std::vector<uint8>& der_sig,
- std::vector<uint8>* out_raw_sig) override;
+ bool DecodeSignature(const std::vector<uint8_t>& der_sig,
+ std::vector<uint8_t>* out_raw_sig) override;
private:
ECPrivateKey* key_;
- size_t signature_len_;
DISALLOW_COPY_AND_ASSIGN(ECSignatureCreatorImpl);
};
diff --git a/crypto/nss_util_internal.h b/crypto/nss_util_internal.h
index f321343d95..0982a6e8c7 100644
--- a/crypto/nss_util_internal.h
+++ b/crypto/nss_util_internal.h
@@ -9,6 +9,7 @@
#include "base/callback.h"
#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "crypto/crypto_export.h"
#include "crypto/scoped_nss_types.h"
@@ -24,9 +25,8 @@ namespace crypto {
// Opens an NSS software database in folder |path|, with the (potentially)
// user-visible description |description|. Returns the slot for the opened
// database, or NULL if the database could not be opened.
-CRYPTO_EXPORT_PRIVATE ScopedPK11Slot
- OpenSoftwareNSSDB(const base::FilePath& path,
- const std::string& description);
+CRYPTO_EXPORT ScopedPK11Slot OpenSoftwareNSSDB(const base::FilePath& path,
+ const std::string& description);
#if !defined(OS_CHROMEOS)
// Returns a reference to the default NSS key slot for storing persistent data.
@@ -59,7 +59,7 @@ CRYPTO_EXPORT ScopedPK11Slot GetSystemNSSKeySlot(
// does not have to be called if the test system slot is set.
// This must must not be called consecutively with a |slot| != NULL. If |slot|
// is NULL, the test system slot is unset.
-CRYPTO_EXPORT_PRIVATE void SetSystemKeySlotForTesting(ScopedPK11Slot slot);
+CRYPTO_EXPORT void SetSystemKeySlotForTesting(ScopedPK11Slot slot);
// Prepare per-user NSS slot mapping. It is safe to call this function multiple
// times. Returns true if the user was added, or false if it already existed.
@@ -104,7 +104,7 @@ CRYPTO_EXPORT ScopedPK11Slot GetPrivateSlotForChromeOSUser(
// Closes the NSS DB for |username_hash| that was previously opened by the
// *Initialize*ForChromeOSUser functions.
-CRYPTO_EXPORT_PRIVATE void CloseChromeOSUserForTesting(
+CRYPTO_EXPORT void CloseChromeOSUserForTesting(
const std::string& username_hash);
#endif // defined(OS_CHROMEOS)
diff --git a/crypto/scoped_capi_types.h b/crypto/scoped_capi_types.h
index ac92e394b9..74e5765859 100644
--- a/crypto/scoped_capi_types.h
+++ b/crypto/scoped_capi_types.h
@@ -10,6 +10,7 @@
#include <algorithm>
#include "base/logging.h"
+#include "base/macros.h"
#include "crypto/wincrypt_shim.h"
namespace crypto {
diff --git a/crypto/scoped_nss_types.h b/crypto/scoped_nss_types.h
index fdfb83c154..8e96e8d4e2 100644
--- a/crypto/scoped_nss_types.h
+++ b/crypto/scoped_nss_types.h
@@ -16,7 +16,6 @@ namespace crypto {
template <typename Type, void (*Destroyer)(Type*)>
struct NSSDestroyer {
- typedef void AllowSelfReset;
void operator()(Type* ptr) const {
Destroyer(ptr);
}
@@ -24,7 +23,6 @@ struct NSSDestroyer {
template <typename Type, void (*Destroyer)(Type*, PRBool), PRBool freeit>
struct NSSDestroyer1 {
- typedef void AllowSelfReset;
void operator()(Type* ptr) const {
Destroyer(ptr, freeit);
}
diff --git a/crypto/scoped_openssl_types.h b/crypto/scoped_openssl_types.h
index b392a072d4..9bc5d74309 100644
--- a/crypto/scoped_openssl_types.h
+++ b/crypto/scoped_openssl_types.h
@@ -11,7 +11,9 @@
#include <openssl/ec.h>
#include <openssl/ecdsa.h>
#include <openssl/evp.h>
+#include <openssl/mem.h>
#include <openssl/rsa.h>
+#include <stdint.h>
#include "base/memory/scoped_ptr.h"
@@ -22,7 +24,6 @@ namespace crypto {
// base::internal::RunnableAdapter<>, but that's far too heavy weight.
template <typename Type, void (*Destroyer)(Type*)>
struct OpenSSLDestroyer {
- using AllowSelfReset = void;
void operator()(Type* ptr) const { Destroyer(ptr); }
};
diff --git a/crypto/secure_hash.h b/crypto/secure_hash.h
index 23349b0be0..491a299a31 100644
--- a/crypto/secure_hash.h
+++ b/crypto/secure_hash.h
@@ -5,7 +5,9 @@
#ifndef CRYPTO_SECURE_HASH_H_
#define CRYPTO_SECURE_HASH_H_
-#include "base/basictypes.h"
+#include <stddef.h>
+
+#include "base/macros.h"
#include "crypto/crypto_export.h"
namespace base {
diff --git a/crypto/signature_creator.h b/crypto/signature_creator.h
index ab9d2c1a21..abd1546164 100644
--- a/crypto/signature_creator.h
+++ b/crypto/signature_creator.h
@@ -5,10 +5,12 @@
#ifndef CRYPTO_SIGNATURE_CREATOR_H_
#define CRYPTO_SIGNATURE_CREATOR_H_
+#include <stdint.h>
+
#include <vector>
+#include "base/macros.h"
#include "build/build_config.h"
-#include "base/basictypes.h"
#include "crypto/crypto_export.h"
#if defined(USE_OPENSSL)
@@ -45,15 +47,15 @@ class CRYPTO_EXPORT SignatureCreator {
// specified in PKCS #1 v1.5.
static bool Sign(RSAPrivateKey* key,
HashAlgorithm hash_alg,
- const uint8* data,
+ const uint8_t* data,
int data_len,
- std::vector<uint8>* signature);
+ std::vector<uint8_t>* signature);
// Update the signature with more data.
- bool Update(const uint8* data_part, int data_part_len);
+ bool Update(const uint8_t* data_part, int data_part_len);
// Finalize the signature.
- bool Final(std::vector<uint8>* signature);
+ bool Final(std::vector<uint8_t>* signature);
private:
// Private constructor. Use the Create() method instead.
diff --git a/crypto/signature_verifier.h b/crypto/signature_verifier.h
index fbf87d4cc6..b26a0dfb4a 100644
--- a/crypto/signature_verifier.h
+++ b/crypto/signature_verifier.h
@@ -5,10 +5,11 @@
#ifndef CRYPTO_SIGNATURE_VERIFIER_H_
#define CRYPTO_SIGNATURE_VERIFIER_H_
+#include <stdint.h>
+
#include <vector>
#include "build/build_config.h"
-#include "base/basictypes.h"
#include "crypto/crypto_export.h"
#if defined(USE_OPENSSL)
@@ -58,11 +59,11 @@ class CRYPTO_EXPORT SignatureVerifier {
// SubjectPublicKeyInfo ::= SEQUENCE {
// algorithm AlgorithmIdentifier,
// subjectPublicKey BIT STRING }
- bool VerifyInit(const uint8* signature_algorithm,
+ bool VerifyInit(const uint8_t* signature_algorithm,
int signature_algorithm_len,
- const uint8* signature,
+ const uint8_t* signature,
int signature_len,
- const uint8* public_key_info,
+ const uint8_t* public_key_info,
int public_key_info_len);
// Initiates a RSA-PSS signature verification operation. This should be
@@ -84,13 +85,13 @@ class CRYPTO_EXPORT SignatureVerifier {
bool VerifyInitRSAPSS(HashAlgorithm hash_alg,
HashAlgorithm mask_hash_alg,
int salt_len,
- const uint8* signature,
+ const uint8_t* signature,
int signature_len,
- const uint8* public_key_info,
+ const uint8_t* public_key_info,
int public_key_info_len);
// Feeds a piece of the data to the signature verifier.
- void VerifyUpdate(const uint8* data_part, int data_part_len);
+ void VerifyUpdate(const uint8_t* data_part, int data_part_len);
// Concludes a signature verification operation. Returns true if the
// signature is valid. Returns false if the signature is invalid or an
@@ -98,31 +99,31 @@ class CRYPTO_EXPORT SignatureVerifier {
bool VerifyFinal();
// Note: we can provide a one-shot interface if there is interest:
- // bool Verify(const uint8* data,
+ // bool Verify(const uint8_t* data,
// int data_len,
- // const uint8* signature_algorithm,
+ // const uint8_t* signature_algorithm,
// int signature_algorithm_len,
- // const uint8* signature,
+ // const uint8_t* signature,
// int signature_len,
- // const uint8* public_key_info,
+ // const uint8_t* public_key_info,
// int public_key_info_len);
private:
#if defined(USE_OPENSSL)
bool CommonInit(const EVP_MD* digest,
- const uint8* signature,
+ const uint8_t* signature,
int signature_len,
- const uint8* public_key_info,
+ const uint8_t* public_key_info,
int public_key_info_len,
EVP_PKEY_CTX** pkey_ctx);
#else
- static SECKEYPublicKey* DecodePublicKeyInfo(const uint8* public_key_info,
+ static SECKEYPublicKey* DecodePublicKeyInfo(const uint8_t* public_key_info,
int public_key_info_len);
#endif
void Reset();
- std::vector<uint8> signature_;
+ std::vector<uint8_t> signature_;
#if defined(USE_OPENSSL)
struct VerifyContext;
diff --git a/crypto/symmetric_key.h b/crypto/symmetric_key.h
index 996c5923b1..14f74aeb74 100644
--- a/crypto/symmetric_key.h
+++ b/crypto/symmetric_key.h
@@ -5,9 +5,12 @@
#ifndef CRYPTO_SYMMETRIC_KEY_H_
#define CRYPTO_SYMMETRIC_KEY_H_
+#include <stddef.h>
+
#include <string>
-#include "base/basictypes.h"
+#include "base/macros.h"
+#include "build/build_config.h"
#include "crypto/crypto_export.h"
#if defined(NACL_WIN64)
diff --git a/dbus/BUILD.gn b/dbus/BUILD.gn
index a133e724b6..dbeee0c1dd 100644
--- a/dbus/BUILD.gn
+++ b/dbus/BUILD.gn
@@ -90,7 +90,6 @@ test("dbus_unittests") {
"object_manager_unittest.cc",
"object_proxy_unittest.cc",
"property_unittest.cc",
- "run_all_unittests.cc",
"signal_sender_verification_unittest.cc",
"string_util_unittest.cc",
"test_service.cc",
@@ -103,6 +102,7 @@ test("dbus_unittests") {
":dbus",
":test_proto",
":test_support",
+ "//base/test:run_all_unittests",
"//base/test:test_support",
"//testing/gmock",
"//testing/gtest",
@@ -124,6 +124,7 @@ executable("dbus_test_server") {
":dbus",
"//base",
"//base/test:test_support",
+ "//build/config/sanitizers:deps",
]
configs += [ "//build/config/linux:dbus" ]
diff --git a/dbus/bus.cc b/dbus/bus.cc
index a9e14edef0..8781eaea83 100644
--- a/dbus/bus.cc
+++ b/dbus/bus.cc
@@ -4,6 +4,8 @@
#include "dbus/bus.h"
+#include <stddef.h>
+
#include "base/bind.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
@@ -665,7 +667,7 @@ void Bus::SendWithReply(DBusMessage* request,
CHECK(success) << "Unable to allocate memory";
}
-void Bus::Send(DBusMessage* request, uint32* serial) {
+void Bus::Send(DBusMessage* request, uint32_t* serial) {
DCHECK(connection_);
AssertOnDBusThread();
diff --git a/dbus/bus.h b/dbus/bus.h
index 27d149c479..e5e0b1c6a9 100644
--- a/dbus/bus.h
+++ b/dbus/bus.h
@@ -6,6 +6,7 @@
#define DBUS_BUS_H_
#include <dbus/dbus.h>
+#include <stdint.h>
#include <map>
#include <set>
@@ -14,6 +15,7 @@
#include <vector>
#include "base/callback.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/platform_thread.h"
@@ -462,7 +464,7 @@ class CHROME_DBUS_EXPORT Bus : public base::RefCountedThreadSafe<Bus> {
// be stored in |serial|.
//
// BLOCKING CALL.
- virtual void Send(DBusMessage* request, uint32* serial);
+ virtual void Send(DBusMessage* request, uint32_t* serial);
// Adds the message filter function. |filter_function| will be called
// when incoming messages are received.
diff --git a/dbus/dbus.gyp b/dbus/dbus.gyp
index daac2e26a3..264383ee4b 100644
--- a/dbus/dbus.gyp
+++ b/dbus/dbus.gyp
@@ -89,6 +89,7 @@
'target_name': 'dbus_unittests',
'type': 'executable',
'dependencies': [
+ '../base/base.gyp:run_all_unittests',
'../base/base.gyp:test_support_base',
'../build/linux/system.gyp:dbus',
'../testing/gmock.gyp:gmock',
@@ -107,7 +108,6 @@
'object_manager_unittest.cc',
'object_proxy_unittest.cc',
'property_unittest.cc',
- 'run_all_unittests.cc',
'signal_sender_verification_unittest.cc',
'string_util_unittest.cc',
'test_service.cc',
diff --git a/dbus/dbus_statistics.cc b/dbus/dbus_statistics.cc
index 9abec65e3d..e6eb5a2f5b 100644
--- a/dbus/dbus_statistics.cc
+++ b/dbus/dbus_statistics.cc
@@ -7,6 +7,7 @@
#include <set>
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
diff --git a/dbus/exported_object.cc b/dbus/exported_object.cc
index 8f782c232b..889792a5ab 100644
--- a/dbus/exported_object.cc
+++ b/dbus/exported_object.cc
@@ -4,6 +4,9 @@
#include "dbus/exported_object.h"
+#include <stdint.h>
+#include <utility>
+
#include "base/bind.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
@@ -148,7 +151,7 @@ void ExportedObject::OnExported(OnExportedCallback on_exported_callback,
void ExportedObject::SendSignalInternal(base::TimeTicks start_time,
DBusMessage* signal_message) {
- uint32 serial = 0;
+ uint32_t serial = 0;
bus_->Send(signal_message, &serial);
dbus_message_unref(signal_message);
// Record time spent to send the the signal. This is not accurate as the
@@ -263,7 +266,7 @@ void ExportedObject::SendResponse(base::TimeTicks start_time,
base::Passed(&response),
start_time));
} else {
- OnMethodCompleted(method_call.Pass(), response.Pass(), start_time);
+ OnMethodCompleted(std::move(method_call), std::move(response), start_time);
}
}
diff --git a/dbus/file_descriptor.cc b/dbus/file_descriptor.cc
index c740f28062..b690881749 100644
--- a/dbus/file_descriptor.cc
+++ b/dbus/file_descriptor.cc
@@ -21,9 +21,8 @@ void CHROME_DBUS_EXPORT FileDescriptor::Deleter::operator()(
FROM_HERE, base::Bind(&base::DeletePointer<FileDescriptor>, fd), false);
}
-FileDescriptor::FileDescriptor(RValue other)
- : value_(-1), owner_(false), valid_(false) {
- Swap(other.object);
+FileDescriptor::FileDescriptor(FileDescriptor&& other) : FileDescriptor() {
+ Swap(&other);
}
FileDescriptor::~FileDescriptor() {
@@ -31,8 +30,8 @@ FileDescriptor::~FileDescriptor() {
base::File auto_closer(value_);
}
-FileDescriptor& FileDescriptor::operator=(RValue other) {
- Swap(other.object);
+FileDescriptor& FileDescriptor::operator=(FileDescriptor&& other) {
+ Swap(&other);
return *this;
}
diff --git a/dbus/file_descriptor.h b/dbus/file_descriptor.h
index 8a4109789e..b4f95cb593 100644
--- a/dbus/file_descriptor.h
+++ b/dbus/file_descriptor.h
@@ -5,7 +5,6 @@
#ifndef DBUS_FILE_DESCRIPTOR_H_
#define DBUS_FILE_DESCRIPTOR_H_
-#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
#include "base/move.h"
#include "dbus/dbus_export.h"
@@ -34,7 +33,7 @@ namespace dbus {
// also allows the caller to do this work on the File thread to conform
// with i/o restrictions.
class CHROME_DBUS_EXPORT FileDescriptor {
- MOVE_ONLY_TYPE_FOR_CPP_03(FileDescriptor, RValue);
+ MOVE_ONLY_TYPE_FOR_CPP_03(FileDescriptor);
public:
// This provides a simple way to pass around file descriptors since they must
@@ -49,13 +48,11 @@ class CHROME_DBUS_EXPORT FileDescriptor {
explicit FileDescriptor(int value) : value_(value), owner_(false),
valid_(false) {}
- // Move constructor for C++03 move emulation of this type.
- FileDescriptor(RValue other);
+ FileDescriptor(FileDescriptor&& other);
virtual ~FileDescriptor();
- // Move operator= for C++03 move emulation of this type.
- FileDescriptor& operator=(RValue other);
+ FileDescriptor& operator=(FileDescriptor&& other);
// Retrieves value as an int without affecting ownership.
int value() const;
diff --git a/dbus/message.cc b/dbus/message.cc
index 3b021e5019..8a58dbaa3b 100644
--- a/dbus/message.cc
+++ b/dbus/message.cc
@@ -6,9 +6,9 @@
#include <string>
-#include "base/basictypes.h"
#include "base/format_macros.h"
#include "base/logging.h"
+#include "base/numerics/safe_conversions.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
@@ -35,11 +35,10 @@ void AppendStringHeader(const std::string& header_name,
// Appends the header name and the value to |output|, if the value is
// nonzero.
void AppendUint32Header(const std::string& header_name,
- uint32 header_value,
+ uint32_t header_value,
std::string* output) {
if (header_value != 0) {
- *output += (header_name + ": " + base::StringPrintf("%u", header_value) +
- "\n");
+ *output += (header_name + ": " + base::UintToString(header_value) + "\n");
}
}
@@ -99,10 +98,10 @@ std::string Message::ToStringInternal(const std::string& indent,
const DataType type = reader->GetDataType();
switch (type) {
case BYTE: {
- uint8 value = 0;
+ uint8_t value = 0;
if (!reader->PopByte(&value))
return kBrokenMessage;
- output += indent + "byte " + base::IntToString(value) + "\n";
+ output += indent + "byte " + base::UintToString(value) + "\n";
break;
}
case BOOL: {
@@ -113,54 +112,52 @@ std::string Message::ToStringInternal(const std::string& indent,
break;
}
case INT16: {
- int16 value = 0;
+ int16_t value = 0;
if (!reader->PopInt16(&value))
return kBrokenMessage;
- output += indent + "int16 " + base::IntToString(value) + "\n";
+ output += indent + "int16_t " + base::IntToString(value) + "\n";
break;
}
case UINT16: {
- uint16 value = 0;
+ uint16_t value = 0;
if (!reader->PopUint16(&value))
return kBrokenMessage;
- output += indent + "uint16 " + base::IntToString(value) + "\n";
+ output += indent + "uint16_t " + base::UintToString(value) + "\n";
break;
}
case INT32: {
- int32 value = 0;
+ int32_t value = 0;
if (!reader->PopInt32(&value))
return kBrokenMessage;
- output += indent + "int32 " + base::IntToString(value) + "\n";
+ output += indent + "int32_t " + base::IntToString(value) + "\n";
break;
}
case UINT32: {
- uint32 value = 0;
+ uint32_t value = 0;
if (!reader->PopUint32(&value))
return kBrokenMessage;
- output += indent + "uint32 " + base::StringPrintf("%u", value) + "\n";
+ output += indent + "uint32_t " + base::UintToString(value) + "\n";
break;
}
case INT64: {
- int64 value = 0;
+ int64_t value = 0;
if (!reader->PopInt64(&value))
return kBrokenMessage;
- output += (indent + "int64 " +
- base::StringPrintf("%" PRId64, value) + "\n");
+ output += (indent + "int64_t " + base::Int64ToString(value) + "\n");
break;
}
case UINT64: {
- uint64 value = 0;
+ uint64_t value = 0;
if (!reader->PopUint64(&value))
return kBrokenMessage;
- output += (indent + "uint64 " +
- base::StringPrintf("%" PRIu64, value) + "\n");
+ output += (indent + "uint64_t " + base::Uint64ToString(value) + "\n");
break;
}
case DOUBLE: {
double value = 0;
if (!reader->PopDouble(&value))
return kBrokenMessage;
- output += indent + "double " + base::StringPrintf("%f", value) + "\n";
+ output += indent + "double " + base::DoubleToString(value) + "\n";
break;
}
case STRING: {
@@ -296,11 +293,11 @@ bool Message::SetSender(const std::string& sender) {
return dbus_message_set_sender(raw_message_, sender.c_str());
}
-void Message::SetSerial(uint32 serial) {
+void Message::SetSerial(uint32_t serial) {
dbus_message_set_serial(raw_message_, serial);
}
-void Message::SetReplySerial(uint32 reply_serial) {
+void Message::SetReplySerial(uint32_t reply_serial) {
dbus_message_set_reply_serial(raw_message_, reply_serial);
}
@@ -339,11 +336,11 @@ std::string Message::GetSignature() {
return signature ? signature : "";
}
-uint32 Message::GetSerial() {
+uint32_t Message::GetSerial() {
return dbus_message_get_serial(raw_message_);
}
-uint32 Message::GetReplySerial() {
+uint32_t Message::GetReplySerial() {
return dbus_message_get_reply_serial(raw_message_);
}
@@ -407,19 +404,19 @@ scoped_ptr<Response> Response::FromRawMessage(DBusMessage* raw_message) {
scoped_ptr<Response> response(new Response);
response->Init(raw_message);
- return response.Pass();
+ return response;
}
scoped_ptr<Response> Response::FromMethodCall(MethodCall* method_call) {
scoped_ptr<Response> response(new Response);
response->Init(dbus_message_new_method_return(method_call->raw_message()));
- return response.Pass();
+ return response;
}
scoped_ptr<Response> Response::CreateEmpty() {
scoped_ptr<Response> response(new Response);
response->Init(dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN));
- return response.Pass();
+ return response;
}
//
@@ -435,7 +432,7 @@ scoped_ptr<ErrorResponse> ErrorResponse::FromRawMessage(
scoped_ptr<ErrorResponse> response(new ErrorResponse);
response->Init(raw_message);
- return response.Pass();
+ return response;
}
scoped_ptr<ErrorResponse> ErrorResponse::FromMethodCall(
@@ -446,7 +443,7 @@ scoped_ptr<ErrorResponse> ErrorResponse::FromMethodCall(
response->Init(dbus_message_new_error(method_call->raw_message(),
error_name.c_str(),
error_message.c_str()));
- return response.Pass();
+ return response;
}
//
@@ -464,7 +461,7 @@ MessageWriter::MessageWriter(Message* message)
MessageWriter::~MessageWriter() {
}
-void MessageWriter::AppendByte(uint8 value) {
+void MessageWriter::AppendByte(uint8_t value) {
AppendBasic(DBUS_TYPE_BYTE, &value);
}
@@ -478,27 +475,27 @@ void MessageWriter::AppendBool(bool value) {
AppendBasic(DBUS_TYPE_BOOLEAN, &dbus_value);
}
-void MessageWriter::AppendInt16(int16 value) {
+void MessageWriter::AppendInt16(int16_t value) {
AppendBasic(DBUS_TYPE_INT16, &value);
}
-void MessageWriter::AppendUint16(uint16 value) {
+void MessageWriter::AppendUint16(uint16_t value) {
AppendBasic(DBUS_TYPE_UINT16, &value);
}
-void MessageWriter::AppendInt32(int32 value) {
+void MessageWriter::AppendInt32(int32_t value) {
AppendBasic(DBUS_TYPE_INT32, &value);
}
-void MessageWriter::AppendUint32(uint32 value) {
+void MessageWriter::AppendUint32(uint32_t value) {
AppendBasic(DBUS_TYPE_UINT32, &value);
}
-void MessageWriter::AppendInt64(int64 value) {
+void MessageWriter::AppendInt64(int64_t value) {
AppendBasic(DBUS_TYPE_INT64, &value);
}
-void MessageWriter::AppendUint64(uint64 value) {
+void MessageWriter::AppendUint64(uint64_t value) {
AppendBasic(DBUS_TYPE_UINT64, &value);
}
@@ -589,7 +586,7 @@ void MessageWriter::CloseContainer(MessageWriter* writer) {
container_is_open_ = false;
}
-void MessageWriter::AppendArrayOfBytes(const uint8* values, size_t length) {
+void MessageWriter::AppendArrayOfBytes(const uint8_t* values, size_t length) {
DCHECK(!container_is_open_);
MessageWriter array_writer(message_);
OpenArray("y", &array_writer);
@@ -631,12 +628,12 @@ bool MessageWriter::AppendProtoAsArrayOfBytes(
LOG(ERROR) << "Unable to serialize supplied protocol buffer";
return false;
}
- AppendArrayOfBytes(reinterpret_cast<const uint8*>(serialized_proto.data()),
+ AppendArrayOfBytes(reinterpret_cast<const uint8_t*>(serialized_proto.data()),
serialized_proto.size());
return true;
}
-void MessageWriter::AppendVariantOfByte(uint8 value) {
+void MessageWriter::AppendVariantOfByte(uint8_t value) {
AppendVariantOfBasic(DBUS_TYPE_BYTE, &value);
}
@@ -646,27 +643,27 @@ void MessageWriter::AppendVariantOfBool(bool value) {
AppendVariantOfBasic(DBUS_TYPE_BOOLEAN, &dbus_value);
}
-void MessageWriter::AppendVariantOfInt16(int16 value) {
+void MessageWriter::AppendVariantOfInt16(int16_t value) {
AppendVariantOfBasic(DBUS_TYPE_INT16, &value);
}
-void MessageWriter::AppendVariantOfUint16(uint16 value) {
+void MessageWriter::AppendVariantOfUint16(uint16_t value) {
AppendVariantOfBasic(DBUS_TYPE_UINT16, &value);
}
-void MessageWriter::AppendVariantOfInt32(int32 value) {
+void MessageWriter::AppendVariantOfInt32(int32_t value) {
AppendVariantOfBasic(DBUS_TYPE_INT32, &value);
}
-void MessageWriter::AppendVariantOfUint32(uint32 value) {
+void MessageWriter::AppendVariantOfUint32(uint32_t value) {
AppendVariantOfBasic(DBUS_TYPE_UINT32, &value);
}
-void MessageWriter::AppendVariantOfInt64(int64 value) {
+void MessageWriter::AppendVariantOfInt64(int64_t value) {
AppendVariantOfBasic(DBUS_TYPE_INT64, &value);
}
-void MessageWriter::AppendVariantOfUint64(uint64 value) {
+void MessageWriter::AppendVariantOfUint64(uint64_t value) {
AppendVariantOfBasic(DBUS_TYPE_UINT64, &value);
}
@@ -696,7 +693,8 @@ void MessageWriter::AppendBasic(int dbus_type, const void* value) {
}
void MessageWriter::AppendVariantOfBasic(int dbus_type, const void* value) {
- const std::string signature = base::StringPrintf("%c", dbus_type);
+ const std::string signature(1u, // length
+ base::checked_cast<char>(dbus_type));
MessageWriter variant_writer(message_);
OpenVariant(signature, &variant_writer);
variant_writer.AppendBasic(dbus_type, value);
@@ -734,7 +732,7 @@ bool MessageReader::HasMoreData() {
return dbus_type != DBUS_TYPE_INVALID;
}
-bool MessageReader::PopByte(uint8* value) {
+bool MessageReader::PopByte(uint8_t* value) {
return PopBasic(DBUS_TYPE_BYTE, value);
}
@@ -748,27 +746,27 @@ bool MessageReader::PopBool(bool* value) {
return success;
}
-bool MessageReader::PopInt16(int16* value) {
+bool MessageReader::PopInt16(int16_t* value) {
return PopBasic(DBUS_TYPE_INT16, value);
}
-bool MessageReader::PopUint16(uint16* value) {
+bool MessageReader::PopUint16(uint16_t* value) {
return PopBasic(DBUS_TYPE_UINT16, value);
}
-bool MessageReader::PopInt32(int32* value) {
+bool MessageReader::PopInt32(int32_t* value) {
return PopBasic(DBUS_TYPE_INT32, value);
}
-bool MessageReader::PopUint32(uint32* value) {
+bool MessageReader::PopUint32(uint32_t* value) {
return PopBasic(DBUS_TYPE_UINT32, value);
}
-bool MessageReader::PopInt64(int64* value) {
+bool MessageReader::PopInt64(int64_t* value) {
return PopBasic(DBUS_TYPE_INT64, value);
}
-bool MessageReader::PopUint64(uint64* value) {
+bool MessageReader::PopUint64(uint64_t* value) {
return PopBasic(DBUS_TYPE_UINT64, value);
}
@@ -808,7 +806,7 @@ bool MessageReader::PopVariant(MessageReader* sub_reader) {
return PopContainer(DBUS_TYPE_VARIANT, sub_reader);
}
-bool MessageReader::PopArrayOfBytes(const uint8** bytes, size_t* length) {
+bool MessageReader::PopArrayOfBytes(const uint8_t** bytes, size_t* length) {
MessageReader array_reader(message_);
if (!PopArray(&array_reader))
return false;
@@ -863,8 +861,8 @@ bool MessageReader::PopArrayOfBytesAsProto(
DCHECK(protobuf != NULL);
const char* serialized_buf = NULL;
size_t buf_size = 0;
- if (!PopArrayOfBytes(
- reinterpret_cast<const uint8**>(&serialized_buf), &buf_size)) {
+ if (!PopArrayOfBytes(reinterpret_cast<const uint8_t**>(&serialized_buf),
+ &buf_size)) {
LOG(ERROR) << "Error reading array of bytes";
return false;
}
@@ -875,7 +873,7 @@ bool MessageReader::PopArrayOfBytesAsProto(
return true;
}
-bool MessageReader::PopVariantOfByte(uint8* value) {
+bool MessageReader::PopVariantOfByte(uint8_t* value) {
return PopVariantOfBasic(DBUS_TYPE_BYTE, value);
}
@@ -887,27 +885,27 @@ bool MessageReader::PopVariantOfBool(bool* value) {
return success;
}
-bool MessageReader::PopVariantOfInt16(int16* value) {
+bool MessageReader::PopVariantOfInt16(int16_t* value) {
return PopVariantOfBasic(DBUS_TYPE_INT16, value);
}
-bool MessageReader::PopVariantOfUint16(uint16* value) {
+bool MessageReader::PopVariantOfUint16(uint16_t* value) {
return PopVariantOfBasic(DBUS_TYPE_UINT16, value);
}
-bool MessageReader::PopVariantOfInt32(int32* value) {
+bool MessageReader::PopVariantOfInt32(int32_t* value) {
return PopVariantOfBasic(DBUS_TYPE_INT32, value);
}
-bool MessageReader::PopVariantOfUint32(uint32* value) {
+bool MessageReader::PopVariantOfUint32(uint32_t* value) {
return PopVariantOfBasic(DBUS_TYPE_UINT32, value);
}
-bool MessageReader::PopVariantOfInt64(int64* value) {
+bool MessageReader::PopVariantOfInt64(int64_t* value) {
return PopVariantOfBasic(DBUS_TYPE_INT64, value);
}
-bool MessageReader::PopVariantOfUint64(uint64* value) {
+bool MessageReader::PopVariantOfUint64(uint64_t* value) {
return PopVariantOfBasic(DBUS_TYPE_UINT64, value);
}
diff --git a/dbus/message.h b/dbus/message.h
index 780e6c5b46..7dffe0e0f6 100644
--- a/dbus/message.h
+++ b/dbus/message.h
@@ -5,11 +5,13 @@
#ifndef DBUS_MESSAGE_H_
#define DBUS_MESSAGE_H_
+#include <dbus/dbus.h>
+#include <stddef.h>
+#include <stdint.h>
#include <string>
#include <vector>
-#include <dbus/dbus.h>
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "dbus/dbus_export.h"
#include "dbus/file_descriptor.h"
@@ -99,8 +101,8 @@ class CHROME_DBUS_EXPORT Message {
bool SetMember(const std::string& member);
bool SetErrorName(const std::string& error_name);
bool SetSender(const std::string& sender);
- void SetSerial(uint32 serial);
- void SetReplySerial(uint32 reply_serial);
+ void SetSerial(uint32_t serial);
+ void SetReplySerial(uint32_t reply_serial);
// SetSignature() does not exist as we cannot do it.
// Gets the destination, the path, the interface, the member, etc.
@@ -113,8 +115,8 @@ class CHROME_DBUS_EXPORT Message {
std::string GetSender();
std::string GetSignature();
// Gets the serial and reply serial numbers. Returns 0 if not set.
- uint32 GetSerial();
- uint32 GetReplySerial();
+ uint32_t GetSerial();
+ uint32_t GetReplySerial();
// Returns the string representation of this message. Useful for
// debugging. The output is truncated as needed (ex. strings are truncated
@@ -270,14 +272,14 @@ class CHROME_DBUS_EXPORT MessageWriter {
~MessageWriter();
// Appends a byte to the message.
- void AppendByte(uint8 value);
+ void AppendByte(uint8_t value);
void AppendBool(bool value);
- void AppendInt16(int16 value);
- void AppendUint16(uint16 value);
- void AppendInt32(int32 value);
- void AppendUint32(uint32 value);
- void AppendInt64(int64 value);
- void AppendUint64(uint64 value);
+ void AppendInt16(int16_t value);
+ void AppendUint16(uint16_t value);
+ void AppendInt32(int32_t value);
+ void AppendUint32(uint32_t value);
+ void AppendInt64(int64_t value);
+ void AppendUint64(uint64_t value);
void AppendDouble(double value);
void AppendString(const std::string& value);
void AppendObjectPath(const ObjectPath& value);
@@ -308,7 +310,7 @@ class CHROME_DBUS_EXPORT MessageWriter {
// Appends the array of bytes. Arrays of bytes are often used for
// exchanging binary blobs hence it's worth having a specialized
// function.
- void AppendArrayOfBytes(const uint8* values, size_t length);
+ void AppendArrayOfBytes(const uint8_t* values, size_t length);
// Appends the array of strings. Arrays of strings are often used for
// exchanging lists of names hence it's worth having a specialized
@@ -332,14 +334,14 @@ class CHROME_DBUS_EXPORT MessageWriter {
// widely used in D-Bus services so it's worth having a specialized
// function. For instance, The third parameter of
// "org.freedesktop.DBus.Properties.Set" is a variant.
- void AppendVariantOfByte(uint8 value);
+ void AppendVariantOfByte(uint8_t value);
void AppendVariantOfBool(bool value);
- void AppendVariantOfInt16(int16 value);
- void AppendVariantOfUint16(uint16 value);
- void AppendVariantOfInt32(int32 value);
- void AppendVariantOfUint32(uint32 value);
- void AppendVariantOfInt64(int64 value);
- void AppendVariantOfUint64(uint64 value);
+ void AppendVariantOfInt16(int16_t value);
+ void AppendVariantOfUint16(uint16_t value);
+ void AppendVariantOfInt32(int32_t value);
+ void AppendVariantOfUint32(uint32_t value);
+ void AppendVariantOfInt64(int64_t value);
+ void AppendVariantOfUint64(uint64_t value);
void AppendVariantOfDouble(double value);
void AppendVariantOfString(const std::string& value);
void AppendVariantOfObjectPath(const ObjectPath& value);
@@ -380,14 +382,14 @@ class CHROME_DBUS_EXPORT MessageReader {
// Gets the byte at the current iterator position.
// Returns true and advances the iterator on success.
// Returns false if the data type is not a byte.
- bool PopByte(uint8* value);
+ bool PopByte(uint8_t* value);
bool PopBool(bool* value);
- bool PopInt16(int16* value);
- bool PopUint16(uint16* value);
- bool PopInt32(int32* value);
- bool PopUint32(uint32* value);
- bool PopInt64(int64* value);
- bool PopUint64(uint64* value);
+ bool PopInt16(int16_t* value);
+ bool PopUint16(uint16_t* value);
+ bool PopInt32(int32_t* value);
+ bool PopUint32(uint32_t* value);
+ bool PopInt64(int64_t* value);
+ bool PopUint64(uint64_t* value);
bool PopDouble(double* value);
bool PopString(std::string* value);
bool PopObjectPath(ObjectPath* value);
@@ -411,7 +413,7 @@ class CHROME_DBUS_EXPORT MessageReader {
// Ownership of the memory pointed to by |bytes| remains with the
// MessageReader; |bytes| must be copied if the contents will be referenced
// after the MessageReader is destroyed.
- bool PopArrayOfBytes(const uint8** bytes, size_t* length);
+ bool PopArrayOfBytes(const uint8_t** bytes, size_t* length);
// Gets the array of strings at the current iterator position. |strings| is
// cleared before being modified. Returns true and advances the iterator on
@@ -446,14 +448,14 @@ class CHROME_DBUS_EXPORT MessageReader {
// Variants are widely used in D-Bus services so it's worth having a
// specialized function. For instance, The return value type of
// "org.freedesktop.DBus.Properties.Get" is a variant.
- bool PopVariantOfByte(uint8* value);
+ bool PopVariantOfByte(uint8_t* value);
bool PopVariantOfBool(bool* value);
- bool PopVariantOfInt16(int16* value);
- bool PopVariantOfUint16(uint16* value);
- bool PopVariantOfInt32(int32* value);
- bool PopVariantOfUint32(uint32* value);
- bool PopVariantOfInt64(int64* value);
- bool PopVariantOfUint64(uint64* value);
+ bool PopVariantOfInt16(int16_t* value);
+ bool PopVariantOfUint16(uint16_t* value);
+ bool PopVariantOfInt32(int32_t* value);
+ bool PopVariantOfUint32(uint32_t* value);
+ bool PopVariantOfInt64(int64_t* value);
+ bool PopVariantOfUint64(uint64_t* value);
bool PopVariantOfDouble(double* value);
bool PopVariantOfString(std::string* value);
bool PopVariantOfObjectPath(ObjectPath* value);
diff --git a/dbus/mock_bus.h b/dbus/mock_bus.h
index 60000672e1..40b090b156 100644
--- a/dbus/mock_bus.h
+++ b/dbus/mock_bus.h
@@ -5,6 +5,8 @@
#ifndef DBUS_MOCK_BUS_H_
#define DBUS_MOCK_BUS_H_
+#include <stdint.h>
+
#include "dbus/bus.h"
#include "dbus/object_path.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -45,8 +47,7 @@ class MockBus : public Bus {
MOCK_METHOD3(SendWithReply, void(DBusMessage* request,
DBusPendingCall** pending_call,
int timeout_ms));
- MOCK_METHOD2(Send, void(DBusMessage* request,
- uint32* serial));
+ MOCK_METHOD2(Send, void(DBusMessage* request, uint32_t* serial));
MOCK_METHOD2(AddFilter, void(DBusHandleMessageFunction handle_message,
void* user_data));
MOCK_METHOD2(RemoveFilter, void(DBusHandleMessageFunction handle_message,
diff --git a/dbus/object_manager.cc b/dbus/object_manager.cc
index cc99f6290d..34b881ce0f 100644
--- a/dbus/object_manager.cc
+++ b/dbus/object_manager.cc
@@ -4,6 +4,8 @@
#include "dbus/object_manager.h"
+#include <stddef.h>
+
#include "base/bind.h"
#include "base/location.h"
#include "base/logging.h"
@@ -252,6 +254,9 @@ DBusHandlerResult ObjectManager::HandleMessage(DBusConnection* /* connection */,
DCHECK(bus_);
bus_->AssertOnDBusThread();
+ // Handle the message only if it is a signal.
+ // Note that the match rule in SetupMatchRuleAndFilter() is configured to
+ // only accept signals, but we check here just in case.
if (dbus_message_get_type(raw_message) != DBUS_MESSAGE_TYPE_SIGNAL)
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
@@ -266,7 +271,9 @@ DBusHandlerResult ObjectManager::HandleMessage(DBusConnection* /* connection */,
statistics::AddReceivedSignal(service_name_, interface, member);
- // Only handle the PropertiesChanged signal.
+ // Handle the signal only if it is PropertiesChanged.
+ // Note that the match rule in SetupMatchRuleAndFilter() is configured to
+ // only accept PropertiesChanged signals, but we check here just in case.
const std::string absolute_signal_name =
GetAbsoluteMemberName(interface, member);
const std::string properties_changed_signal_name =
@@ -276,13 +283,15 @@ DBusHandlerResult ObjectManager::HandleMessage(DBusConnection* /* connection */,
VLOG(1) << "Signal received: " << signal->ToString();
- // Make sure that the signal originated from the correct sender.
+ // Handle the signal only if it is from the service that the ObjectManager
+ // instance is interested in.
+ // Note that the match rule in SetupMatchRuleAndFilter() is configured to
+ // only accept messages from the service name of our interest. However, the
+ // service='...' filter does not work as intended. See crbug.com/507206#14
+ // and #15 for details, hence it's necessary to check the sender here.
std::string sender = signal->GetSender();
- if (service_name_owner_ != sender) {
- LOG(ERROR) << "Rejecting a message from a wrong sender.";
- UMA_HISTOGRAM_COUNTS("DBus.RejectedSignalCount", 1);
+ if (service_name_owner_ != sender)
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
- }
const ObjectPath path = signal->GetPath();
diff --git a/dbus/object_manager.h b/dbus/object_manager.h
index 456e183525..25834c54fe 100644
--- a/dbus/object_manager.h
+++ b/dbus/object_manager.h
@@ -5,8 +5,11 @@
#ifndef DBUS_OBJECT_MANAGER_H_
#define DBUS_OBJECT_MANAGER_H_
+#include <stdint.h>
+
#include <map>
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "dbus/object_path.h"
@@ -36,7 +39,7 @@
// public:
// struct Properties : public dbus::PropertySet {
// dbus::Property<std::string> name;
-// dbus::Property<uint16> version;
+// dbus::Property<uint16_t> version;
// dbus::Property<dbus::ObjectPath> parent;
// dbus::Property<std::vector<std::string> > children;
//
diff --git a/dbus/object_proxy.cc b/dbus/object_proxy.cc
index b0ba9b70c5..9fb3ee41a3 100644
--- a/dbus/object_proxy.cc
+++ b/dbus/object_proxy.cc
@@ -2,7 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "dbus/bus.h"
+#include "dbus/object_proxy.h"
+
+#include <stddef.h>
+#include <utility>
#include "base/bind.h"
#include "base/logging.h"
@@ -13,10 +16,10 @@
#include "base/task_runner_util.h"
#include "base/threading/thread.h"
#include "base/threading/thread_restrictions.h"
+#include "dbus/bus.h"
#include "dbus/dbus_statistics.h"
#include "dbus/message.h"
#include "dbus/object_path.h"
-#include "dbus/object_proxy.h"
#include "dbus/scoped_dbus_error.h"
#include "dbus/util.h"
@@ -474,7 +477,7 @@ DBusHandlerResult ObjectProxy::HandleMessage(
if (path.value() == kDBusSystemObjectPath &&
signal->GetMember() == kNameOwnerChangedMember) {
// Handle NameOwnerChanged separately
- return HandleNameOwnerChanged(signal.Pass());
+ return HandleNameOwnerChanged(std::move(signal));
}
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
diff --git a/dbus/object_proxy.h b/dbus/object_proxy.h
index c0211b1db6..edb97a5be7 100644
--- a/dbus/object_proxy.h
+++ b/dbus/object_proxy.h
@@ -13,6 +13,7 @@
#include <vector>
#include "base/callback.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/strings/string_piece.h"
#include "base/time/time.h"
@@ -146,8 +147,7 @@ class CHROME_DBUS_EXPORT ObjectProxy
ResponseCallback callback,
ErrorCallback error_callback);
- // Requests to connect to the signal from the remote object, replacing
- // any previous |signal_callback| connected to that signal.
+ // Requests to connect to the signal from the remote object.
//
// |signal_callback| will be called in the origin thread, when the
// signal is received from the remote object. As it's called in the
@@ -157,6 +157,11 @@ class CHROME_DBUS_EXPORT ObjectProxy
// |on_connected_callback| is called when the object proxy is connected
// to the signal, or failed to be connected, in the origin thread.
//
+ // If a SignalCallback has already been registered for the given
+ // |interface_name| and |signal_name|, |signal_callback| will be
+ // added to the list of callbacks for |interface_name| and
+ // |signal_name|.
+ //
// Must be called in the origin thread.
virtual void ConnectToSignal(const std::string& interface_name,
const std::string& signal_name,
diff --git a/dbus/property.cc b/dbus/property.cc
index bec8faebaf..156d0c7f55 100644
--- a/dbus/property.cc
+++ b/dbus/property.cc
@@ -4,7 +4,8 @@
#include "dbus/property.h"
-#include "base/basictypes.h"
+#include <stddef.h>
+
#include "base/bind.h"
#include "base/logging.h"
@@ -302,16 +303,16 @@ void PropertySet::NotifyPropertyChanged(const std::string& name) {
//
template <>
-Property<uint8>::Property() : value_(0) {
-}
+Property<uint8_t>::Property()
+ : value_(0) {}
template <>
-bool Property<uint8>::PopValueFromReader(MessageReader* reader) {
+bool Property<uint8_t>::PopValueFromReader(MessageReader* reader) {
return reader->PopVariantOfByte(&value_);
}
template <>
-void Property<uint8>::AppendSetValueToWriter(MessageWriter* writer) {
+void Property<uint8_t>::AppendSetValueToWriter(MessageWriter* writer) {
writer->AppendVariantOfByte(set_value_);
}
@@ -334,110 +335,110 @@ void Property<bool>::AppendSetValueToWriter(MessageWriter* writer) {
}
//
-// Property<int16> specialization.
+// Property<int16_t> specialization.
//
template <>
-Property<int16>::Property() : value_(0) {
-}
+Property<int16_t>::Property()
+ : value_(0) {}
template <>
-bool Property<int16>::PopValueFromReader(MessageReader* reader) {
+bool Property<int16_t>::PopValueFromReader(MessageReader* reader) {
return reader->PopVariantOfInt16(&value_);
}
template <>
-void Property<int16>::AppendSetValueToWriter(MessageWriter* writer) {
+void Property<int16_t>::AppendSetValueToWriter(MessageWriter* writer) {
writer->AppendVariantOfInt16(set_value_);
}
//
-// Property<uint16> specialization.
+// Property<uint16_t> specialization.
//
template <>
-Property<uint16>::Property() : value_(0) {
-}
+Property<uint16_t>::Property()
+ : value_(0) {}
template <>
-bool Property<uint16>::PopValueFromReader(MessageReader* reader) {
+bool Property<uint16_t>::PopValueFromReader(MessageReader* reader) {
return reader->PopVariantOfUint16(&value_);
}
template <>
-void Property<uint16>::AppendSetValueToWriter(MessageWriter* writer) {
+void Property<uint16_t>::AppendSetValueToWriter(MessageWriter* writer) {
writer->AppendVariantOfUint16(set_value_);
}
//
-// Property<int32> specialization.
+// Property<int32_t> specialization.
//
template <>
-Property<int32>::Property() : value_(0) {
-}
+Property<int32_t>::Property()
+ : value_(0) {}
template <>
-bool Property<int32>::PopValueFromReader(MessageReader* reader) {
+bool Property<int32_t>::PopValueFromReader(MessageReader* reader) {
return reader->PopVariantOfInt32(&value_);
}
template <>
-void Property<int32>::AppendSetValueToWriter(MessageWriter* writer) {
+void Property<int32_t>::AppendSetValueToWriter(MessageWriter* writer) {
writer->AppendVariantOfInt32(set_value_);
}
//
-// Property<uint32> specialization.
+// Property<uint32_t> specialization.
//
template <>
-Property<uint32>::Property() : value_(0) {
-}
+Property<uint32_t>::Property()
+ : value_(0) {}
template <>
-bool Property<uint32>::PopValueFromReader(MessageReader* reader) {
+bool Property<uint32_t>::PopValueFromReader(MessageReader* reader) {
return reader->PopVariantOfUint32(&value_);
}
template <>
-void Property<uint32>::AppendSetValueToWriter(MessageWriter* writer) {
+void Property<uint32_t>::AppendSetValueToWriter(MessageWriter* writer) {
writer->AppendVariantOfUint32(set_value_);
}
//
-// Property<int64> specialization.
+// Property<int64_t> specialization.
//
template <>
-Property<int64>::Property() : value_(0), set_value_(0) {
-}
+Property<int64_t>::Property()
+ : value_(0), set_value_(0) {}
template <>
-bool Property<int64>::PopValueFromReader(MessageReader* reader) {
+bool Property<int64_t>::PopValueFromReader(MessageReader* reader) {
return reader->PopVariantOfInt64(&value_);
}
template <>
-void Property<int64>::AppendSetValueToWriter(MessageWriter* writer) {
+void Property<int64_t>::AppendSetValueToWriter(MessageWriter* writer) {
writer->AppendVariantOfInt64(set_value_);
}
//
-// Property<uint64> specialization.
+// Property<uint64_t> specialization.
//
template <>
-Property<uint64>::Property() : value_(0) {
-}
+Property<uint64_t>::Property()
+ : value_(0) {}
template <>
-bool Property<uint64>::PopValueFromReader(MessageReader* reader) {
+bool Property<uint64_t>::PopValueFromReader(MessageReader* reader) {
return reader->PopVariantOfUint64(&value_);
}
template <>
-void Property<uint64>::AppendSetValueToWriter(MessageWriter* writer) {
+void Property<uint64_t>::AppendSetValueToWriter(MessageWriter* writer) {
writer->AppendVariantOfUint64(set_value_);
}
@@ -536,17 +537,17 @@ void Property<std::vector<ObjectPath> >::AppendSetValueToWriter(
}
//
-// Property<std::vector<uint8> > specialization.
+// Property<std::vector<uint8_t> > specialization.
//
template <>
-bool Property<std::vector<uint8> >::PopValueFromReader(MessageReader* reader) {
+bool Property<std::vector<uint8_t>>::PopValueFromReader(MessageReader* reader) {
MessageReader variant_reader(NULL);
if (!reader->PopVariant(&variant_reader))
return false;
value_.clear();
- const uint8* bytes = NULL;
+ const uint8_t* bytes = NULL;
size_t length = 0;
if (!variant_reader.PopArrayOfBytes(&bytes, &length))
return false;
@@ -555,7 +556,7 @@ bool Property<std::vector<uint8> >::PopValueFromReader(MessageReader* reader) {
}
template <>
-void Property<std::vector<uint8> >::AppendSetValueToWriter(
+void Property<std::vector<uint8_t>>::AppendSetValueToWriter(
MessageWriter* writer) {
MessageWriter variant_writer(NULL);
writer->OpenVariant("ay", &variant_writer);
@@ -629,7 +630,7 @@ bool Property<std::vector<std::pair<std::vector<uint8_t>, uint16_t>>>::
return false;
std::pair<std::vector<uint8_t>, uint16_t> entry;
- const uint8* bytes = NULL;
+ const uint8_t* bytes = NULL;
size_t length = 0;
if (!struct_reader.PopArrayOfBytes(&bytes, &length))
return false;
@@ -660,20 +661,20 @@ void Property<std::vector<std::pair<std::vector<uint8_t>, uint16_t>>>::
writer->CloseContainer(&variant_writer);
}
-template class Property<uint8>;
+template class Property<uint8_t>;
template class Property<bool>;
-template class Property<int16>;
-template class Property<uint16>;
-template class Property<int32>;
-template class Property<uint32>;
-template class Property<int64>;
-template class Property<uint64>;
+template class Property<int16_t>;
+template class Property<uint16_t>;
+template class Property<int32_t>;
+template class Property<uint32_t>;
+template class Property<int64_t>;
+template class Property<uint64_t>;
template class Property<double>;
template class Property<std::string>;
template class Property<ObjectPath>;
template class Property<std::vector<std::string> >;
template class Property<std::vector<ObjectPath> >;
-template class Property<std::vector<uint8> >;
+template class Property<std::vector<uint8_t>>;
template class Property<std::map<std::string, std::string>>;
template class Property<std::vector<std::pair<std::vector<uint8_t>, uint16_t>>>;
diff --git a/dbus/property.h b/dbus/property.h
index e2c09d6b9f..efbad226a6 100644
--- a/dbus/property.h
+++ b/dbus/property.h
@@ -5,14 +5,16 @@
#ifndef DBUS_PROPERTY_H_
#define DBUS_PROPERTY_H_
+#include <stdint.h>
+
#include <map>
#include <string>
#include <utility>
#include <vector>
-#include "base/basictypes.h"
#include "base/bind.h"
#include "base/callback.h"
+#include "base/macros.h"
#include "dbus/dbus_export.h"
#include "dbus/message.h"
#include "dbus/object_proxy.h"
@@ -36,7 +38,7 @@
// public:
// struct Properties : public dbus::PropertySet {
// dbus::Property<std::string> name;
-// dbus::Property<uint16> version;
+// dbus::Property<uint16_t> version;
// dbus::Property<dbus::ObjectPath> parent;
// dbus::Property<std::vector<std::string> > children;
//
@@ -447,101 +449,168 @@ class CHROME_DBUS_EXPORT Property : public PropertyBase {
T set_value_;
};
-template <> Property<uint8>::Property();
-template <> bool Property<uint8>::PopValueFromReader(MessageReader* reader);
-template <> void Property<uint8>::AppendSetValueToWriter(MessageWriter* writer);
-extern template class Property<uint8>;
-
-template <> Property<bool>::Property();
-template <> bool Property<bool>::PopValueFromReader(MessageReader* reader);
-template <> void Property<bool>::AppendSetValueToWriter(MessageWriter* writer);
-extern template class Property<bool>;
-
-template <> Property<int16>::Property();
-template <> bool Property<int16>::PopValueFromReader(MessageReader* reader);
-template <> void Property<int16>::AppendSetValueToWriter(MessageWriter* writer);
-extern template class Property<int16>;
-
-template <> Property<uint16>::Property();
-template <> bool Property<uint16>::PopValueFromReader(MessageReader* reader);
-template <> void Property<uint16>::AppendSetValueToWriter(
- MessageWriter* writer);
-extern template class Property<uint16>;
-
-template <> Property<int32>::Property();
-template <> bool Property<int32>::PopValueFromReader(MessageReader* reader);
-template <> void Property<int32>::AppendSetValueToWriter(MessageWriter* writer);
-extern template class Property<int32>;
-
-template <> Property<uint32>::Property();
-template <> bool Property<uint32>::PopValueFromReader(MessageReader* reader);
-template <> void Property<uint32>::AppendSetValueToWriter(
- MessageWriter* writer);
-extern template class Property<uint32>;
-
-template <> Property<int64>::Property();
-template <> bool Property<int64>::PopValueFromReader(MessageReader* reader);
-template <> void Property<int64>::AppendSetValueToWriter(MessageWriter* writer);
-extern template class Property<int64>;
-
-template <> Property<uint64>::Property();
-template <> bool Property<uint64>::PopValueFromReader(MessageReader* reader);
-template <> void Property<uint64>::AppendSetValueToWriter(
- MessageWriter* writer);
-extern template class Property<uint64>;
-
-template <> Property<double>::Property();
-template <> bool Property<double>::PopValueFromReader(MessageReader* reader);
-template <> void Property<double>::AppendSetValueToWriter(
- MessageWriter* writer);
-extern template class Property<double>;
-
-template <> bool Property<std::string>::PopValueFromReader(
- MessageReader* reader);
-template <> void Property<std::string>::AppendSetValueToWriter(
- MessageWriter* writer);
-extern template class Property<std::string>;
-
-template <> bool Property<ObjectPath>::PopValueFromReader(
- MessageReader* reader);
-template <> void Property<ObjectPath>::AppendSetValueToWriter(
- MessageWriter* writer);
-extern template class Property<ObjectPath>;
-
-template <> bool Property<std::vector<std::string> >::PopValueFromReader(
- MessageReader* reader);
-template <> void Property<std::vector<std::string> >::AppendSetValueToWriter(
- MessageWriter* writer);
-extern template class Property<std::vector<std::string> >;
-
-template <> bool Property<std::vector<ObjectPath> >::PopValueFromReader(
- MessageReader* reader);
-template <> void Property<std::vector<ObjectPath> >::AppendSetValueToWriter(
- MessageWriter* writer);
-extern template class Property<std::vector<ObjectPath> >;
-
-template <> bool Property<std::vector<uint8> >::PopValueFromReader(
- MessageReader* reader);
-template <> void Property<std::vector<uint8> >::AppendSetValueToWriter(
- MessageWriter* writer);
-extern template class Property<std::vector<uint8> >;
-
-template <>
-bool Property<std::map<std::string, std::string>>::PopValueFromReader(
+// Clang and GCC don't agree on how attributes should work for explicitly
+// instantiated templates. GCC ignores attributes on explicit instantiations
+// (and emits a warning) while Clang requires the visiblity attribute on the
+// explicit instantiations for them to be visible to other compilation units.
+// Hopefully clang and GCC agree one day, and this can be cleaned up:
+// https://llvm.org/bugs/show_bug.cgi?id=24815
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wattributes"
+
+template <>
+CHROME_DBUS_EXPORT Property<uint8_t>::Property();
+template <>
+CHROME_DBUS_EXPORT bool Property<uint8_t>::PopValueFromReader(
MessageReader* reader);
template <>
-void Property<std::map<std::string, std::string>>::AppendSetValueToWriter(
+CHROME_DBUS_EXPORT void Property<uint8_t>::AppendSetValueToWriter(
MessageWriter* writer);
-extern template class Property<std::map<std::string, std::string>>;
+extern template class CHROME_DBUS_EXPORT Property<uint8_t>;
template <>
-bool Property<std::vector<std::pair<std::vector<uint8_t>, uint16_t>>>::
+CHROME_DBUS_EXPORT Property<bool>::Property();
+template <>
+CHROME_DBUS_EXPORT bool Property<bool>::PopValueFromReader(
+ MessageReader* reader);
+template <>
+CHROME_DBUS_EXPORT void Property<bool>::AppendSetValueToWriter(
+ MessageWriter* writer);
+extern template class CHROME_DBUS_EXPORT Property<bool>;
+
+template <>
+CHROME_DBUS_EXPORT Property<int16_t>::Property();
+template <>
+CHROME_DBUS_EXPORT bool Property<int16_t>::PopValueFromReader(
+ MessageReader* reader);
+template <>
+CHROME_DBUS_EXPORT void Property<int16_t>::AppendSetValueToWriter(
+ MessageWriter* writer);
+extern template class CHROME_DBUS_EXPORT Property<int16_t>;
+
+template <>
+CHROME_DBUS_EXPORT Property<uint16_t>::Property();
+template <>
+CHROME_DBUS_EXPORT bool Property<uint16_t>::PopValueFromReader(
+ MessageReader* reader);
+template <>
+CHROME_DBUS_EXPORT void Property<uint16_t>::AppendSetValueToWriter(
+ MessageWriter* writer);
+extern template class CHROME_DBUS_EXPORT Property<uint16_t>;
+
+template <>
+CHROME_DBUS_EXPORT Property<int32_t>::Property();
+template <>
+CHROME_DBUS_EXPORT bool Property<int32_t>::PopValueFromReader(
+ MessageReader* reader);
+template <>
+CHROME_DBUS_EXPORT void Property<int32_t>::AppendSetValueToWriter(
+ MessageWriter* writer);
+extern template class CHROME_DBUS_EXPORT Property<int32_t>;
+
+template <>
+CHROME_DBUS_EXPORT Property<uint32_t>::Property();
+template <>
+CHROME_DBUS_EXPORT bool Property<uint32_t>::PopValueFromReader(
+ MessageReader* reader);
+template <>
+CHROME_DBUS_EXPORT void Property<uint32_t>::AppendSetValueToWriter(
+ MessageWriter* writer);
+extern template class CHROME_DBUS_EXPORT Property<uint32_t>;
+
+template <>
+CHROME_DBUS_EXPORT Property<int64_t>::Property();
+template <>
+CHROME_DBUS_EXPORT bool Property<int64_t>::PopValueFromReader(
+ MessageReader* reader);
+template <>
+CHROME_DBUS_EXPORT void Property<int64_t>::AppendSetValueToWriter(
+ MessageWriter* writer);
+extern template class CHROME_DBUS_EXPORT Property<int64_t>;
+
+template <>
+CHROME_DBUS_EXPORT Property<uint64_t>::Property();
+template <>
+CHROME_DBUS_EXPORT bool Property<uint64_t>::PopValueFromReader(
+ MessageReader* reader);
+template <>
+CHROME_DBUS_EXPORT void Property<uint64_t>::AppendSetValueToWriter(
+ MessageWriter* writer);
+extern template class CHROME_DBUS_EXPORT Property<uint64_t>;
+
+template <>
+CHROME_DBUS_EXPORT Property<double>::Property();
+template <>
+CHROME_DBUS_EXPORT bool Property<double>::PopValueFromReader(
+ MessageReader* reader);
+template <>
+CHROME_DBUS_EXPORT void Property<double>::AppendSetValueToWriter(
+ MessageWriter* writer);
+extern template class CHROME_DBUS_EXPORT Property<double>;
+
+template <>
+CHROME_DBUS_EXPORT bool Property<std::string>::PopValueFromReader(
+ MessageReader* reader);
+template <>
+CHROME_DBUS_EXPORT void Property<std::string>::AppendSetValueToWriter(
+ MessageWriter* writer);
+extern template class CHROME_DBUS_EXPORT Property<std::string>;
+
+template <>
+CHROME_DBUS_EXPORT bool Property<ObjectPath>::PopValueFromReader(
+ MessageReader* reader);
+template <>
+CHROME_DBUS_EXPORT void Property<ObjectPath>::AppendSetValueToWriter(
+ MessageWriter* writer);
+extern template class CHROME_DBUS_EXPORT Property<ObjectPath>;
+
+template <>
+CHROME_DBUS_EXPORT bool Property<std::vector<std::string>>::PopValueFromReader(
+ MessageReader* reader);
+template <>
+CHROME_DBUS_EXPORT void Property<
+ std::vector<std::string>>::AppendSetValueToWriter(MessageWriter* writer);
+extern template class CHROME_DBUS_EXPORT Property<std::vector<std::string>>;
+
+template <>
+CHROME_DBUS_EXPORT bool Property<std::vector<ObjectPath>>::PopValueFromReader(
+ MessageReader* reader);
+template <>
+CHROME_DBUS_EXPORT void Property<
+ std::vector<ObjectPath>>::AppendSetValueToWriter(MessageWriter* writer);
+extern template class CHROME_DBUS_EXPORT Property<std::vector<ObjectPath>>;
+
+template <>
+CHROME_DBUS_EXPORT bool Property<std::vector<uint8_t>>::PopValueFromReader(
+ MessageReader* reader);
+template <>
+CHROME_DBUS_EXPORT void Property<std::vector<uint8_t>>::AppendSetValueToWriter(
+ MessageWriter* writer);
+extern template class CHROME_DBUS_EXPORT Property<std::vector<uint8_t>>;
+
+template <>
+CHROME_DBUS_EXPORT bool
+Property<std::map<std::string, std::string>>::PopValueFromReader(
+ MessageReader* reader);
+template <>
+CHROME_DBUS_EXPORT void
+Property<std::map<std::string, std::string>>::AppendSetValueToWriter(
+ MessageWriter* writer);
+extern template class CHROME_DBUS_EXPORT
+ Property<std::map<std::string, std::string>>;
+
+template <>
+CHROME_DBUS_EXPORT bool
+Property<std::vector<std::pair<std::vector<uint8_t>, uint16_t>>>::
PopValueFromReader(MessageReader* reader);
template <>
-void Property<std::vector<std::pair<std::vector<uint8_t>, uint16_t>>>::
+CHROME_DBUS_EXPORT void
+Property<std::vector<std::pair<std::vector<uint8_t>, uint16_t>>>::
AppendSetValueToWriter(MessageWriter* writer);
-extern template class Property<
- std::vector<std::pair<std::vector<uint8_t>, uint16_t>>>;
+extern template class CHROME_DBUS_EXPORT
+ Property<std::vector<std::pair<std::vector<uint8_t>, uint16_t>>>;
+
+#pragma GCC diagnostic pop
} // namespace dbus
diff --git a/dbus/string_util.cc b/dbus/string_util.cc
index 0b07786030..7f71015c48 100644
--- a/dbus/string_util.cc
+++ b/dbus/string_util.cc
@@ -4,17 +4,16 @@
#include "dbus/string_util.h"
+#include <stddef.h>
+
#include "base/strings/string_util.h"
namespace dbus {
+// This implementation is based upon D-Bus Specification Version 0.19.
bool IsValidObjectPath(const std::string& value) {
- // This implementation is based upon D-Bus Specification Version 0.19.
-
- const bool kCaseSensitive = true;
-
// A valid object path begins with '/'.
- if (!base::StartsWithASCII(value, "/", kCaseSensitive))
+ if (!base::StartsWith(value, "/", base::CompareCase::SENSITIVE))
return false;
// Elements are pieces delimited by '/'. For instance, "org", "chromium",
@@ -39,7 +38,8 @@ bool IsValidObjectPath(const std::string& value) {
}
// A trailing '/' character is not allowed unless the path is the root path.
- if (value.size() > 1 && base::EndsWith(value, "/", kCaseSensitive))
+ if (value.size() > 1 &&
+ base::EndsWith(value, "/", base::CompareCase::SENSITIVE))
return false;
return true;
diff --git a/dbus/test_proto.proto b/dbus/test_proto.proto
index 0a1d06f7ff..1ec128bf60 100644
--- a/dbus/test_proto.proto
+++ b/dbus/test_proto.proto
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+syntax = "proto2";
+
option optimize_for = LITE_RUNTIME;
// This is a simple dummy protocol buffer that is used for testing handling of
@@ -10,4 +12,4 @@ option optimize_for = LITE_RUNTIME;
message TestProto {
optional string text = 1;
optional int32 number = 2;
-} \ No newline at end of file
+}
diff --git a/dbus/values_util.cc b/dbus/values_util.cc
index c162878ee0..e932312e69 100644
--- a/dbus/values_util.cc
+++ b/dbus/values_util.cc
@@ -94,7 +94,7 @@ base::Value* PopDataAsValue(MessageReader* reader) {
// Do nothing.
break;
case Message::BYTE: {
- uint8 value = 0;
+ uint8_t value = 0;
if (reader->PopByte(&value))
result = new base::FundamentalValue(value);
break;
@@ -106,31 +106,31 @@ base::Value* PopDataAsValue(MessageReader* reader) {
break;
}
case Message::INT16: {
- int16 value = 0;
+ int16_t value = 0;
if (reader->PopInt16(&value))
result = new base::FundamentalValue(value);
break;
}
case Message::UINT16: {
- uint16 value = 0;
+ uint16_t value = 0;
if (reader->PopUint16(&value))
result = new base::FundamentalValue(value);
break;
}
case Message::INT32: {
- int32 value = 0;
+ int32_t value = 0;
if (reader->PopInt32(&value))
result = new base::FundamentalValue(value);
break;
}
case Message::UINT32: {
- uint32 value = 0;
+ uint32_t value = 0;
if (reader->PopUint32(&value))
result = new base::FundamentalValue(static_cast<double>(value));
break;
}
case Message::INT64: {
- int64 value = 0;
+ int64_t value = 0;
if (reader->PopInt64(&value)) {
DLOG_IF(WARNING, !IsExactlyRepresentableByDouble(value)) <<
value << " is not exactly representable by double";
@@ -139,7 +139,7 @@ base::Value* PopDataAsValue(MessageReader* reader) {
break;
}
case Message::UINT64: {
- uint64 value = 0;
+ uint64_t value = 0;
if (reader->PopUint64(&value)) {
DLOG_IF(WARNING, !IsExactlyRepresentableByDouble(value)) <<
value << " is not exactly representable by double";
diff --git a/dbus/values_util.h b/dbus/values_util.h
index 9ece9b9be5..b6f4ff3b10 100644
--- a/dbus/values_util.h
+++ b/dbus/values_util.h
@@ -5,6 +5,8 @@
#ifndef DBUS_VALUES_UTIL_H_
#define DBUS_VALUES_UTIL_H_
+#include <stdint.h>
+
#include "dbus/dbus_export.h"
namespace base {
@@ -18,8 +20,8 @@ class MessageWriter;
// Pops a value from |reader| as a base::Value.
// Returns NULL if an error occurs.
-// Note: Integer values larger than int32 (including uint32) are converted to
-// double. Non-string diciontary keys are converted to strings.
+// Note: Integer values larger than int32_t (including uint32_t) are converted
+// to double. Non-string dictionary keys are converted to strings.
CHROME_DBUS_EXPORT base::Value* PopDataAsValue(MessageReader* reader);
// Appends a basic type value to |writer|. Basic types are BOOLEAN, INTEGER,
diff --git a/sandbox/BUILD.gn b/sandbox/BUILD.gn
index 15fb62092f..6825a1d3b5 100644
--- a/sandbox/BUILD.gn
+++ b/sandbox/BUILD.gn
@@ -5,18 +5,18 @@
# Meta-target that forwards to the proper platform one.
group("sandbox") {
if (is_win) {
- deps = [
+ public_deps = [
"//sandbox/win:sandbox",
]
} else if (is_mac) {
# TODO(GYP): Make sandbox compile w/ 10.6 SDK.
if (false) {
- deps = [
+ public_deps = [
"//sandbox/mac:sandbox",
]
}
} else if (is_linux || is_android) {
- deps = [
+ public_deps = [
"//sandbox/linux:sandbox",
]
}
diff --git a/sandbox/linux/BUILD.gn b/sandbox/linux/BUILD.gn
index a1a77204f5..341d3639e7 100644
--- a/sandbox/linux/BUILD.gn
+++ b/sandbox/linux/BUILD.gn
@@ -3,8 +3,13 @@
# found in the LICENSE file.
import("//build/config/features.gni")
+import("//build/config/nacl/config.gni")
import("//testing/test.gni")
+if (is_android) {
+ import("//build/config/android/rules.gni")
+}
+
declare_args() {
compile_suid_client = is_linux
@@ -14,21 +19,29 @@ declare_args() {
use_base_test_suite = is_linux
}
+if (is_nacl_nonsfi) {
+ config("nacl_nonsfi_warnings") {
+ # There are number of platform specific functions in
+ # seccomp-bpf syscall helpers, which are not being used.
+ cflags = [ "-Wno-unused-function" ]
+ }
+}
+
# We have two principal targets: sandbox and sandbox_linux_unittests
# All other targets are listed as dependencies.
# There is one notable exception: for historical reasons, chrome_sandbox is
# the setuid sandbox and is its own target.
group("sandbox") {
- deps = [
+ public_deps = [
":sandbox_services",
]
- if (compile_suid_client) {
- deps += [ ":suid_sandbox_client" ]
+ if (compile_suid_client || is_nacl_nonsfi) {
+ public_deps += [ ":suid_sandbox_client" ]
}
- if (use_seccomp_bpf) {
- deps += [
+ if (use_seccomp_bpf || is_nacl_nonsfi) {
+ public_deps += [
":seccomp_bpf",
":seccomp_bpf_helpers",
]
@@ -42,8 +55,6 @@ source_set("sandbox_linux_test_utils") {
"tests/sandbox_test_runner.h",
"tests/sandbox_test_runner_function_pointer.cc",
"tests/sandbox_test_runner_function_pointer.h",
- "tests/test_utils.cc",
- "tests/test_utils.h",
"tests/unit_tests.cc",
"tests/unit_tests.h",
]
@@ -52,7 +63,14 @@ source_set("sandbox_linux_test_utils") {
"//testing/gtest",
]
- if (use_seccomp_bpf) {
+ if (!is_nacl_nonsfi) {
+ sources += [
+ "tests/test_utils.cc",
+ "tests/test_utils.h",
+ ]
+ }
+
+ if (use_seccomp_bpf || is_nacl_nonsfi) {
sources += [
"seccomp-bpf/bpf_tester_compatibility_delegate.h",
"seccomp-bpf/bpf_tests.h",
@@ -68,7 +86,7 @@ source_set("sandbox_linux_test_utils") {
}
}
-# Sources shared by sandbox_linux_unittests and sandbox_linux_jni_unittests.
+# Sources for sandbox_linux_unittests.
source_set("sandbox_linux_unittests_sources") {
testonly = true
@@ -101,11 +119,6 @@ source_set("sandbox_linux_unittests_sources") {
defines = [ "SANDBOX_USES_BASE_TEST_SUITE" ]
}
- if (is_linux) {
- # Don't use this on Android.
- libs = [ "rt" ]
- }
-
if (compile_suid_client) {
sources += [
"suid/client/setuid_sandbox_client_unittest.cc",
@@ -117,17 +130,24 @@ source_set("sandbox_linux_unittests_sources") {
"bpf_dsl/bpf_dsl_unittest.cc",
"bpf_dsl/codegen_unittest.cc",
"bpf_dsl/cons_unittest.cc",
+ "bpf_dsl/dump_bpf.cc",
+ "bpf_dsl/dump_bpf.h",
"bpf_dsl/syscall_set_unittest.cc",
+ "bpf_dsl/test_trap_registry.cc",
+ "bpf_dsl/test_trap_registry.h",
+ "bpf_dsl/test_trap_registry_unittest.cc",
+ "bpf_dsl/verifier.cc",
+ "bpf_dsl/verifier.h",
"integration_tests/bpf_dsl_seccomp_unittest.cc",
"integration_tests/seccomp_broker_process_unittest.cc",
"seccomp-bpf-helpers/baseline_policy_unittest.cc",
"seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc",
"seccomp-bpf/bpf_tests_unittest.cc",
- "seccomp-bpf/errorcode_unittest.cc",
"seccomp-bpf/sandbox_bpf_unittest.cc",
"seccomp-bpf/syscall_unittest.cc",
"seccomp-bpf/trap_unittest.cc",
]
+ deps += [ ":bpf_dsl_golden" ]
}
if (compile_credentials) {
sources += [
@@ -146,23 +166,50 @@ source_set("sandbox_linux_unittests_sources") {
}
}
-# The main sandboxing test target.
-test("sandbox_linux_unittests") {
+action("bpf_dsl_golden") {
+ script = "bpf_dsl/golden/generate.py"
+ inputs = [
+ "bpf_dsl/golden/i386/ArgSizePolicy.txt",
+ "bpf_dsl/golden/i386/BasicPolicy.txt",
+ "bpf_dsl/golden/i386/ElseIfPolicy.txt",
+ "bpf_dsl/golden/i386/MaskingPolicy.txt",
+ "bpf_dsl/golden/i386/MoreBooleanLogicPolicy.txt",
+ "bpf_dsl/golden/i386/NegativeConstantsPolicy.txt",
+ "bpf_dsl/golden/i386/SwitchPolicy.txt",
+ "bpf_dsl/golden/x86-64/ArgSizePolicy.txt",
+ "bpf_dsl/golden/x86-64/BasicPolicy.txt",
+ "bpf_dsl/golden/x86-64/BooleanLogicPolicy.txt",
+ "bpf_dsl/golden/x86-64/ElseIfPolicy.txt",
+ "bpf_dsl/golden/x86-64/MaskingPolicy.txt",
+ "bpf_dsl/golden/x86-64/MoreBooleanLogicPolicy.txt",
+ "bpf_dsl/golden/x86-64/NegativeConstantsPolicy.txt",
+ "bpf_dsl/golden/x86-64/SwitchPolicy.txt",
+ ]
+ outputs = [
+ "$target_gen_dir/bpf_dsl/golden/golden_files.h",
+ ]
+ args =
+ rebase_path(outputs, root_build_dir) + rebase_path(inputs, root_build_dir)
+}
+
+# TODO(GYP): Delete this after we've converted everything to GN.
+# The _run targets exist only for compatibility w/ GYP.
+group("sandbox_linux_unittests_run") {
+ testonly = true
deps = [
- ":sandbox_linux_unittests_sources",
+ ":sandbox_linux_unittests",
]
}
-# This target is the shared library used by Android APK (i.e.
-# JNI-friendly) tests.
-shared_library("sandbox_linux_jni_unittests") {
+# The main sandboxing test target. "sandbox_linux_unittests" cannot use the
+# test() template because the test is run as an executable not as an APK on
+# Android.
+executable("sandbox_linux_unittests") {
testonly = true
deps = [
":sandbox_linux_unittests_sources",
+ "//build/config/sanitizers:deps",
]
- if (is_android) {
- deps += [ "//testing/android/native_test:native_test_native_code" ]
- }
}
component("seccomp_bpf") {
@@ -174,8 +221,7 @@ component("seccomp_bpf") {
"bpf_dsl/codegen.cc",
"bpf_dsl/codegen.h",
"bpf_dsl/cons.h",
- "bpf_dsl/dump_bpf.cc",
- "bpf_dsl/dump_bpf.h",
+ "bpf_dsl/errorcode.h",
"bpf_dsl/linux_syscall_ranges.h",
"bpf_dsl/policy.cc",
"bpf_dsl/policy.h",
@@ -185,12 +231,8 @@ component("seccomp_bpf") {
"bpf_dsl/syscall_set.cc",
"bpf_dsl/syscall_set.h",
"bpf_dsl/trap_registry.h",
- "bpf_dsl/verifier.cc",
- "bpf_dsl/verifier.h",
"seccomp-bpf/die.cc",
"seccomp-bpf/die.h",
- "seccomp-bpf/errorcode.cc",
- "seccomp-bpf/errorcode.h",
"seccomp-bpf/sandbox_bpf.cc",
"seccomp-bpf/sandbox_bpf.h",
"seccomp-bpf/syscall.cc",
@@ -205,6 +247,19 @@ component("seccomp_bpf") {
":sandbox_services_headers",
"//base",
]
+
+ if (is_nacl_nonsfi) {
+ cflags = [ "-fgnu-inline-asm" ]
+ sources -= [
+ "bpf_dsl/bpf_dsl_forward.h",
+ "bpf_dsl/bpf_dsl_impl.h",
+ "bpf_dsl/cons.h",
+ "bpf_dsl/errorcode.h",
+ "bpf_dsl/linux_syscall_ranges.h",
+ "bpf_dsl/seccomp_macros.h",
+ "bpf_dsl/trap_registry.h",
+ ]
+ }
}
component("seccomp_bpf_helpers") {
@@ -221,10 +276,20 @@ component("seccomp_bpf_helpers") {
defines = [ "SANDBOX_IMPLEMENTATION" ]
deps = [
- "//base",
":sandbox_services",
":seccomp_bpf",
+ "//base",
]
+
+ if (is_nacl_nonsfi) {
+ sources -= [
+ "seccomp-bpf-helpers/baseline_policy.cc",
+ "seccomp-bpf-helpers/baseline_policy.h",
+ "seccomp-bpf-helpers/syscall_sets.cc",
+ "seccomp-bpf-helpers/syscall_sets.h",
+ ]
+ configs += [ ":nacl_nonsfi_warnings" ]
+ }
}
if (is_linux) {
@@ -246,6 +311,10 @@ if (is_linux) {
# TODO fix this and re-enable this warning.
"-Wno-sign-compare",
]
+
+ deps = [
+ "//build/config/sanitizers:deps",
+ ]
}
}
@@ -286,7 +355,7 @@ component("sandbox_services") {
"//base",
]
- if (compile_credentials) {
+ if (compile_credentials || is_nacl_nonsfi) {
sources += [
"services/credentials.cc",
"services/credentials.h",
@@ -298,6 +367,32 @@ component("sandbox_services") {
deps += [ ":sandbox_services_headers" ]
}
+
+ if (is_nacl_nonsfi) {
+ cflags = [ "-fgnu-inline-asm" ]
+
+ sources -= [
+ "services/init_process_reaper.cc",
+ "services/init_process_reaper.h",
+ "services/scoped_process.cc",
+ "services/scoped_process.h",
+ "services/yama.cc",
+ "services/yama.h",
+ "syscall_broker/broker_channel.cc",
+ "syscall_broker/broker_channel.h",
+ "syscall_broker/broker_client.cc",
+ "syscall_broker/broker_client.h",
+ "syscall_broker/broker_common.h",
+ "syscall_broker/broker_file_permission.cc",
+ "syscall_broker/broker_file_permission.h",
+ "syscall_broker/broker_host.cc",
+ "syscall_broker/broker_host.h",
+ "syscall_broker/broker_policy.cc",
+ "syscall_broker/broker_policy.h",
+ "syscall_broker/broker_process.cc",
+ "syscall_broker/broker_process.h",
+ ]
+ }
}
source_set("sandbox_services_headers") {
@@ -318,18 +413,7 @@ source_set("sandbox_services_headers") {
]
}
-# We make this its own target so that it does not interfere with our tests.
-source_set("libc_urandom_override") {
- sources = [
- "services/libc_urandom_override.cc",
- "services/libc_urandom_override.h",
- ]
- deps = [
- "//base",
- ]
-}
-
-if (compile_suid_client) {
+if (compile_suid_client || is_nacl_nonsfi) {
component("suid_sandbox_client") {
sources = [
"suid/client/setuid_sandbox_client.cc",
@@ -345,38 +429,36 @@ if (compile_suid_client) {
":sandbox_services",
"//base",
]
+
+ if (is_nacl_nonsfi) {
+ sources -= [
+ "suid/client/setuid_sandbox_host.cc",
+ "suid/client/setuid_sandbox_host.h",
+ "suid/common/sandbox.h",
+ "suid/common/suid_unsafe_environment_variables.h",
+ ]
+ }
}
}
if (is_android) {
- # TODO(GYP) enable this. Needs an android_strip wrapper python script.
- #action("sandbox_linux_unittests_stripped") {
- # script = "android_stip.py"
- #
- # in_file = "$root_out_dir/sandbox_linux_unittests"
- #
- # out_file = "$root_out_dir/sandbox_linux_unittests_stripped"
- # outputs = [ out_file ]
- #
- # args = [
- # rebase_path(in_file, root_build_dir),
- # "-o", rebase_path(out_file, root_build_dir),
- # ]
- #
- # deps = [
- # ":sandbox_linux_unittests",
- # ]
- #}
- # TODO(GYP) convert this.
- # {
- # 'target_name': 'sandbox_linux_jni_unittests_apk',
- # 'type': 'none',
- # 'variables': {
- # 'test_suite_name': 'sandbox_linux_jni_unittests',
- # },
- # 'dependencies': [
- # 'sandbox_linux_jni_unittests',
- # ],
- # 'includes': [ '../../build/apk_test.gypi' ],
- # }
+ create_native_executable_dist("sandbox_linux_unittests_deps") {
+ testonly = true
+ dist_dir = "$root_out_dir/sandbox_linux_unittests_deps"
+ binary = "$root_out_dir/sandbox_linux_unittests"
+ deps = [
+ ":sandbox_linux_unittests",
+ ]
+
+ if (is_component_build) {
+ deps += [ "//build/android:cpplib_stripped" ]
+ }
+ }
+
+ test_runner_script("sandbox_linux_unittests__test_runner_script") {
+ test_name = "sandbox_linux_unittests"
+ test_type = "gtest"
+ test_suite = "sandbox_linux_unittests"
+ isolate_file = "//sandbox/sandbox_linux_unittests_android.isolate"
+ }
}
diff --git a/sandbox/linux/OWNERS b/sandbox/linux/OWNERS
index f39e96736d..99ef1bd961 100644
--- a/sandbox/linux/OWNERS
+++ b/sandbox/linux/OWNERS
@@ -1,3 +1,4 @@
jln@chromium.org
jorgelo@chromium.org
mdempsky@chromium.org
+rickyz@chromium.org
diff --git a/sandbox/linux/bpf_dsl/DEPS b/sandbox/linux/bpf_dsl/DEPS
index be37a129c2..70d9b18aa1 100644
--- a/sandbox/linux/bpf_dsl/DEPS
+++ b/sandbox/linux/bpf_dsl/DEPS
@@ -1,5 +1,3 @@
include_rules = [
- # TODO(mdempsky): Eliminate cyclic dependency on seccomp-bpf.
- "+sandbox/linux/seccomp-bpf",
"+sandbox/linux/system_headers",
]
diff --git a/sandbox/linux/bpf_dsl/bpf_dsl_impl.h b/sandbox/linux/bpf_dsl/bpf_dsl_impl.h
index 2ffaf79c2f..0064f8a7a2 100644
--- a/sandbox/linux/bpf_dsl/bpf_dsl_impl.h
+++ b/sandbox/linux/bpf_dsl/bpf_dsl_impl.h
@@ -7,12 +7,12 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "sandbox/linux/bpf_dsl/codegen.h"
#include "sandbox/sandbox_export.h"
namespace sandbox {
-class ErrorCode;
-
namespace bpf_dsl {
+class ErrorCode;
class PolicyCompiler;
namespace internal {
@@ -20,12 +20,12 @@ namespace internal {
// Internal interface implemented by BoolExpr implementations.
class BoolExprImpl : public base::RefCounted<BoolExprImpl> {
public:
- // Compile uses |pc| to construct an ErrorCode that conditionally continues
- // to either |true_ec| or |false_ec|, depending on whether the represented
+ // Compile uses |pc| to emit a CodeGen::Node that conditionally continues
+ // to either |then_node| or |false_node|, depending on whether the represented
// boolean expression is true or false.
- virtual ErrorCode Compile(PolicyCompiler* pc,
- ErrorCode true_ec,
- ErrorCode false_ec) const = 0;
+ virtual CodeGen::Node Compile(PolicyCompiler* pc,
+ CodeGen::Node then_node,
+ CodeGen::Node else_node) const = 0;
protected:
BoolExprImpl() {}
@@ -39,9 +39,9 @@ class BoolExprImpl : public base::RefCounted<BoolExprImpl> {
// Internal interface implemented by ResultExpr implementations.
class ResultExprImpl : public base::RefCounted<ResultExprImpl> {
public:
- // Compile uses |pc| to construct an ErrorCode analogous to the represented
- // result expression.
- virtual ErrorCode Compile(PolicyCompiler* pc) const = 0;
+ // Compile uses |pc| to emit a CodeGen::Node that executes the
+ // represented result expression.
+ virtual CodeGen::Node Compile(PolicyCompiler* pc) const = 0;
// HasUnsafeTraps returns whether the result expression is or recursively
// contains an unsafe trap expression.
diff --git a/sandbox/linux/bpf_dsl/cons.h b/sandbox/linux/bpf_dsl/cons.h
index fa47c140ff..be050f7781 100644
--- a/sandbox/linux/bpf_dsl/cons.h
+++ b/sandbox/linux/bpf_dsl/cons.h
@@ -5,6 +5,7 @@
#ifndef SANDBOX_LINUX_BPF_DSL_CONS_H_
#define SANDBOX_LINUX_BPF_DSL_CONS_H_
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "sandbox/sandbox_export.h"
diff --git a/sandbox/linux/bpf_dsl/seccomp_macros.h b/sandbox/linux/bpf_dsl/seccomp_macros.h
index ca28c1d7cd..af70f21cd7 100644
--- a/sandbox/linux/bpf_dsl/seccomp_macros.h
+++ b/sandbox/linux/bpf_dsl/seccomp_macros.h
@@ -5,12 +5,11 @@
#ifndef SANDBOX_LINUX_BPF_DSL_SECCOMP_MACROS_H_
#define SANDBOX_LINUX_BPF_DSL_SECCOMP_MACROS_H_
-#include <sys/cdefs.h>
+#include <sys/types.h> // For __BIONIC__.
// Old Bionic versions do not have sys/user.h. The if can be removed once we no
// longer need to support these old Bionic versions.
// All x86_64 builds use a new enough bionic to have sys/user.h.
#if !defined(__BIONIC__) || defined(__x86_64__)
-#include <sys/types.h> // Fix for gcc 4.7, make sure __uint16_t is defined.
#if !defined(__native_client_nonsfi__)
#include <sys/user.h>
#endif
diff --git a/sandbox/linux/sandbox_linux.gypi b/sandbox/linux/sandbox_linux.gypi
index a7bd259d8a..f5b3e0fae8 100644
--- a/sandbox/linux/sandbox_linux.gypi
+++ b/sandbox/linux/sandbox_linux.gypi
@@ -107,22 +107,17 @@
'sandbox_linux_test_sources.gypi',
],
'type': 'executable',
- },
- {
- # This target is the shared library used by Android APK (i.e.
- # JNI-friendly) tests.
- 'target_name': 'sandbox_linux_jni_unittests',
- 'includes': [
- 'sandbox_linux_test_sources.gypi',
- ],
- 'type': 'shared_library',
'conditions': [
[ 'OS == "android"', {
- 'dependencies': [
- '../testing/android/native_test.gyp:native_test_native_code',
+ 'variables': {
+ 'test_type': 'gtest',
+ 'test_suite_name': '<(_target_name)',
+ },
+ 'includes': [
+ '../../build/android/test_runner.gypi',
],
- }],
- ],
+ }]
+ ]
},
{
'target_name': 'seccomp_bpf',
@@ -135,8 +130,7 @@
'bpf_dsl/codegen.cc',
'bpf_dsl/codegen.h',
'bpf_dsl/cons.h',
- 'bpf_dsl/dump_bpf.cc',
- 'bpf_dsl/dump_bpf.h',
+ 'bpf_dsl/errorcode.h',
'bpf_dsl/linux_syscall_ranges.h',
'bpf_dsl/policy.cc',
'bpf_dsl/policy.h',
@@ -147,12 +141,8 @@
'bpf_dsl/syscall_set.cc',
'bpf_dsl/syscall_set.h',
'bpf_dsl/trap_registry.h',
- 'bpf_dsl/verifier.cc',
- 'bpf_dsl/verifier.h',
'seccomp-bpf/die.cc',
'seccomp-bpf/die.h',
- 'seccomp-bpf/errorcode.cc',
- 'seccomp-bpf/errorcode.h',
'seccomp-bpf/sandbox_bpf.cc',
'seccomp-bpf/sandbox_bpf.h',
'seccomp-bpf/syscall.cc',
@@ -171,7 +161,7 @@
'includes': [
# Disable LTO due to compiler bug
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57703
- '../../build/android/disable_lto.gypi',
+ '../../build/android/disable_gcc_lto.gypi',
],
'include_dirs': [
'../..',
@@ -309,22 +299,6 @@
],
},
{
- # We make this its own target so that it does not interfere
- # with our tests.
- 'target_name': 'libc_urandom_override',
- 'type': 'static_library',
- 'sources': [
- 'services/libc_urandom_override.cc',
- 'services/libc_urandom_override.h',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- ],
- 'include_dirs': [
- '..',
- ],
- },
- {
'target_name': 'suid_sandbox_client',
'type': '<(component)',
'sources': [
@@ -346,6 +320,57 @@
'..',
],
},
+ {
+ 'target_name': 'bpf_dsl_golden',
+ 'type': 'none',
+ 'actions': [
+ {
+ 'action_name': 'generate',
+ 'inputs': [
+ 'bpf_dsl/golden/generate.py',
+ 'bpf_dsl/golden/i386/ArgSizePolicy.txt',
+ 'bpf_dsl/golden/i386/BasicPolicy.txt',
+ 'bpf_dsl/golden/i386/ElseIfPolicy.txt',
+ 'bpf_dsl/golden/i386/MaskingPolicy.txt',
+ 'bpf_dsl/golden/i386/MoreBooleanLogicPolicy.txt',
+ 'bpf_dsl/golden/i386/NegativeConstantsPolicy.txt',
+ 'bpf_dsl/golden/i386/SwitchPolicy.txt',
+ 'bpf_dsl/golden/x86-64/ArgSizePolicy.txt',
+ 'bpf_dsl/golden/x86-64/BasicPolicy.txt',
+ 'bpf_dsl/golden/x86-64/BooleanLogicPolicy.txt',
+ 'bpf_dsl/golden/x86-64/ElseIfPolicy.txt',
+ 'bpf_dsl/golden/x86-64/MaskingPolicy.txt',
+ 'bpf_dsl/golden/x86-64/MoreBooleanLogicPolicy.txt',
+ 'bpf_dsl/golden/x86-64/NegativeConstantsPolicy.txt',
+ 'bpf_dsl/golden/x86-64/SwitchPolicy.txt',
+ ],
+ 'outputs': [
+ '<(SHARED_INTERMEDIATE_DIR)/sandbox/linux/bpf_dsl/golden/golden_files.h',
+ ],
+ 'action': [
+ 'python',
+ 'linux/bpf_dsl/golden/generate.py',
+ '<(SHARED_INTERMEDIATE_DIR)/sandbox/linux/bpf_dsl/golden/golden_files.h',
+ 'linux/bpf_dsl/golden/i386/ArgSizePolicy.txt',
+ 'linux/bpf_dsl/golden/i386/BasicPolicy.txt',
+ 'linux/bpf_dsl/golden/i386/ElseIfPolicy.txt',
+ 'linux/bpf_dsl/golden/i386/MaskingPolicy.txt',
+ 'linux/bpf_dsl/golden/i386/MoreBooleanLogicPolicy.txt',
+ 'linux/bpf_dsl/golden/i386/NegativeConstantsPolicy.txt',
+ 'linux/bpf_dsl/golden/i386/SwitchPolicy.txt',
+ 'linux/bpf_dsl/golden/x86-64/ArgSizePolicy.txt',
+ 'linux/bpf_dsl/golden/x86-64/BasicPolicy.txt',
+ 'linux/bpf_dsl/golden/x86-64/BooleanLogicPolicy.txt',
+ 'linux/bpf_dsl/golden/x86-64/ElseIfPolicy.txt',
+ 'linux/bpf_dsl/golden/x86-64/MaskingPolicy.txt',
+ 'linux/bpf_dsl/golden/x86-64/MoreBooleanLogicPolicy.txt',
+ 'linux/bpf_dsl/golden/x86-64/NegativeConstantsPolicy.txt',
+ 'linux/bpf_dsl/golden/x86-64/SwitchPolicy.txt',
+ ],
+ 'message': 'Generating header from golden files ...',
+ },
+ ],
+ },
],
'conditions': [
[ 'OS=="android"', {
@@ -381,19 +406,26 @@
}],
}],
[ 'OS=="android"', {
- 'targets': [
- {
- 'target_name': 'sandbox_linux_jni_unittests_apk',
- 'type': 'none',
- 'variables': {
- 'test_suite_name': 'sandbox_linux_jni_unittests',
+ 'conditions': [
+ ['test_isolation_mode != "noop"', {
+ 'targets': [
+ {
+ 'target_name': 'sandbox_linux_unittests_android_run',
+ 'type': 'none',
+ 'dependencies': [
+ 'sandbox_linux_unittests',
+ ],
+ 'includes': [
+ '../../build/isolate.gypi',
+ ],
+ 'sources': [
+ '../sandbox_linux_unittests_android.isolate',
+ ],
+ },
+ ],
},
- 'dependencies': [
- 'sandbox_linux_jni_unittests',
- ],
- 'includes': [ '../../build/apk_test.gypi' ],
- }
],
+ ],
}],
['test_isolation_mode != "noop"', {
'targets': [
diff --git a/sandbox/linux/sandbox_linux_nacl_nonsfi.gyp b/sandbox/linux/sandbox_linux_nacl_nonsfi.gyp
index 87ad06ccdc..50e637c360 100644
--- a/sandbox/linux/sandbox_linux_nacl_nonsfi.gyp
+++ b/sandbox/linux/sandbox_linux_nacl_nonsfi.gyp
@@ -23,21 +23,20 @@
'build_irt': 0,
'build_pnacl_newlib': 0,
'build_nonsfi_helper': 1,
-
+ 'compile_flags': [
+ '-fgnu-inline-asm',
+ ],
'sources': [
# This is the subset of linux build target, needed for
# nacl_helper_nonsfi's sandbox implementation.
'bpf_dsl/bpf_dsl.cc',
'bpf_dsl/codegen.cc',
- 'bpf_dsl/dump_bpf.cc',
'bpf_dsl/policy.cc',
'bpf_dsl/policy_compiler.cc',
'bpf_dsl/syscall_set.cc',
- 'bpf_dsl/verifier.cc',
'seccomp-bpf-helpers/sigsys_handlers.cc',
'seccomp-bpf-helpers/syscall_parameters_restrictions.cc',
'seccomp-bpf/die.cc',
- 'seccomp-bpf/errorcode.cc',
'seccomp-bpf/sandbox_bpf.cc',
'seccomp-bpf/syscall.cc',
'seccomp-bpf/trap.cc',
diff --git a/sandbox/linux/sandbox_linux_test_sources.gypi b/sandbox/linux/sandbox_linux_test_sources.gypi
index 82d7532056..612814e1d4 100644
--- a/sandbox/linux/sandbox_linux_test_sources.gypi
+++ b/sandbox/linux/sandbox_linux_test_sources.gypi
@@ -43,17 +43,26 @@
'bpf_dsl/bpf_dsl_unittest.cc',
'bpf_dsl/codegen_unittest.cc',
'bpf_dsl/cons_unittest.cc',
+ 'bpf_dsl/dump_bpf.cc',
+ 'bpf_dsl/dump_bpf.h',
'bpf_dsl/syscall_set_unittest.cc',
+ 'bpf_dsl/test_trap_registry.cc',
+ 'bpf_dsl/test_trap_registry.h',
+ 'bpf_dsl/test_trap_registry_unittest.cc',
+ 'bpf_dsl/verifier.cc',
+ 'bpf_dsl/verifier.h',
'integration_tests/bpf_dsl_seccomp_unittest.cc',
'integration_tests/seccomp_broker_process_unittest.cc',
'seccomp-bpf-helpers/baseline_policy_unittest.cc',
'seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc',
'seccomp-bpf/bpf_tests_unittest.cc',
- 'seccomp-bpf/errorcode_unittest.cc',
'seccomp-bpf/sandbox_bpf_unittest.cc',
'seccomp-bpf/syscall_unittest.cc',
'seccomp-bpf/trap_unittest.cc',
],
+ 'dependencies': [
+ 'bpf_dsl_golden',
+ ],
}],
[ 'compile_credentials==1', {
'sources': [
diff --git a/sandbox/linux/seccomp-bpf/bpf_tester_compatibility_delegate.h b/sandbox/linux/seccomp-bpf/bpf_tester_compatibility_delegate.h
index 7736c1506f..00d415c3fc 100644
--- a/sandbox/linux/seccomp-bpf/bpf_tester_compatibility_delegate.h
+++ b/sandbox/linux/seccomp-bpf/bpf_tester_compatibility_delegate.h
@@ -5,6 +5,7 @@
#ifndef SANDBOX_LINUX_SECCOMP_BPF_BPF_TESTER_COMPATIBILITY_DELEGATE_H_
#define SANDBOX_LINUX_SECCOMP_BPF_BPF_TESTER_COMPATIBILITY_DELEGATE_H_
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "sandbox/linux/seccomp-bpf/sandbox_bpf_test_runner.h"
diff --git a/sandbox/linux/suid/common/sandbox.h b/sandbox/linux/suid/common/sandbox.h
index 99eb7b5120..52ef10cdc0 100644
--- a/sandbox/linux/suid/common/sandbox.h
+++ b/sandbox/linux/suid/common/sandbox.h
@@ -17,7 +17,7 @@ static const char kAdjustOOMScoreSwitch[] = "--adjust-oom-score";
static const char kSandboxDescriptorEnvironmentVarName[] = "SBX_D";
static const char kSandboxHelperPidEnvironmentVarName[] = "SBX_HELPER_PID";
-static const long kSUIDSandboxApiNumber = 1;
+static const int kSUIDSandboxApiNumber = 1;
static const char kSandboxEnvironmentApiRequest[] = "SBX_CHROME_API_RQ";
static const char kSandboxEnvironmentApiProvides[] = "SBX_CHROME_API_PRV";
diff --git a/sandbox/linux/suid/common/suid_unsafe_environment_variables.h b/sandbox/linux/suid/common/suid_unsafe_environment_variables.h
index 33ba4b6ab7..e955e0c9c4 100644
--- a/sandbox/linux/suid/common/suid_unsafe_environment_variables.h
+++ b/sandbox/linux/suid/common/suid_unsafe_environment_variables.h
@@ -13,14 +13,15 @@
// sysdeps/unix/sysv/linux/i386/dl-librecon.h
// sysdeps/generic/unsecvars.h
-#ifndef SANDBOX_LINUX_SUID_SUID_UNSAFE_ENVIRONMENT_VARIABLES_H_
-#define SANDBOX_LINUX_SUID_SUID_UNSAFE_ENVIRONMENT_VARIABLES_H_
+#ifndef SANDBOX_LINUX_SUID_COMMON_SUID_UNSAFE_ENVIRONMENT_VARIABLES_H_
+#define SANDBOX_LINUX_SUID_COMMON_SUID_UNSAFE_ENVIRONMENT_VARIABLES_H_
+#include <stddef.h>
#include <stdint.h>
#include <stdlib.h> // malloc
#include <string.h> // memcpy
-static const char* kSUIDUnsafeEnvironmentVariables[] = {
+static const char* const kSUIDUnsafeEnvironmentVariables[] = {
"LD_AOUT_LIBRARY_PATH",
"LD_AOUT_PRELOAD",
"GCONV_PATH",
@@ -70,4 +71,4 @@ static inline char* SandboxSavedEnvironmentVariable(const char* envvar) {
return saved_envvar;
}
-#endif // SANDBOX_LINUX_SUID_SUID_UNSAFE_ENVIRONMENT_VARIABLES_H_
+#endif // SANDBOX_LINUX_SUID_COMMON_SUID_UNSAFE_ENVIRONMENT_VARIABLES_H_
diff --git a/sandbox/linux/suid/process_util.h b/sandbox/linux/suid/process_util.h
index 9fb9a8791a..10071d3e00 100644
--- a/sandbox/linux/suid/process_util.h
+++ b/sandbox/linux/suid/process_util.h
@@ -9,6 +9,7 @@
#define SANDBOX_LINUX_SUID_PROCESS_UTIL_H_
#include <stdbool.h>
+#include <stdint.h>
#include <sys/types.h>
// This adjusts /proc/process/oom_score_adj so the Linux OOM killer
diff --git a/sandbox/linux/suid/process_util_linux.c b/sandbox/linux/suid/process_util_linux.c
index 8d9a53c3a4..40949bd6ac 100644
--- a/sandbox/linux/suid/process_util_linux.c
+++ b/sandbox/linux/suid/process_util_linux.c
@@ -15,6 +15,7 @@
#include <fcntl.h>
#include <inttypes.h>
#include <limits.h>
+#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
diff --git a/sandbox/linux/suid/sandbox.c b/sandbox/linux/suid/sandbox.c
index 3049ae5211..b655d1c79c 100644
--- a/sandbox/linux/suid/sandbox.c
+++ b/sandbox/linux/suid/sandbox.c
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// http://code.google.com/p/chromium/wiki/LinuxSUIDSandbox
+// https://chromium.googlesource.com/chromium/src/+/master/docs/linux_suid_sandbox.md
#include "sandbox/linux/suid/common/sandbox.h"
@@ -15,6 +15,7 @@
#include <signal.h>
#include <stdarg.h>
#include <stdbool.h>
+#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -378,26 +379,29 @@ static bool SetupChildEnvironment() {
bool CheckAndExportApiVersion() {
// Check the environment to see if a specific API version was requested.
// assume version 0 if none.
- long api_number = -1;
+ int api_number = -1;
char* api_string = getenv(kSandboxEnvironmentApiRequest);
if (!api_string) {
api_number = 0;
} else {
errno = 0;
char* endptr = NULL;
- api_number = strtol(api_string, &endptr, 10);
- if (!endptr || *endptr || errno != 0)
+ long long_api_number = strtol(api_string, &endptr, 10);
+ if (!endptr || *endptr || errno != 0 || long_api_number < INT_MIN ||
+ long_api_number > INT_MAX) {
return false;
+ }
+ api_number = long_api_number;
}
// Warn only for now.
if (api_number != kSUIDSandboxApiNumber) {
fprintf(
stderr,
- "The setuid sandbox provides API version %ld, "
- "but you need %ld\n"
+ "The setuid sandbox provides API version %d, "
+ "but you need %d\n"
"Please read "
- "https://code.google.com/p/chromium/wiki/LinuxSUIDSandboxDevelopment."
+ "https://chromium.googlesource.com/chromium/src/+/master/docs/linux_suid_sandbox_development.md."
"\n\n",
kSUIDSandboxApiNumber,
api_number);
@@ -406,8 +410,7 @@ bool CheckAndExportApiVersion() {
// Export our version so that the sandboxed process can verify it did not
// use an old sandbox.
char version_string[64];
- snprintf(
- version_string, sizeof(version_string), "%ld", kSUIDSandboxApiNumber);
+ snprintf(version_string, sizeof(version_string), "%d", kSUIDSandboxApiNumber);
if (setenv(kSandboxEnvironmentApiProvides, version_string, 1)) {
perror("setenv");
return false;
@@ -428,7 +431,7 @@ int main(int argc, char** argv) {
// Allow someone to query our API version
if (argc == 2 && 0 == strcmp(argv[1], kSuidSandboxGetApiSwitch)) {
- printf("%ld\n", kSUIDSandboxApiNumber);
+ printf("%d\n", kSUIDSandboxApiNumber);
return 0;
}
diff --git a/sandbox/linux/system_headers/arm64_linux_ucontext.h b/sandbox/linux/system_headers/arm64_linux_ucontext.h
index 46e0407599..48303ba8dc 100644
--- a/sandbox/linux/system_headers/arm64_linux_ucontext.h
+++ b/sandbox/linux/system_headers/arm64_linux_ucontext.h
@@ -8,6 +8,7 @@
#if !defined(__BIONIC_HAVE_UCONTEXT_T)
#include <asm/sigcontext.h>
#include <signal.h>
+#include <stdint.h>
// We also need greg_t for the sandbox, include it in this header as well.
typedef uint64_t greg_t;
diff --git a/sandbox/linux/system_headers/arm_linux_ucontext.h b/sandbox/linux/system_headers/arm_linux_ucontext.h
index 0eb723a236..35208fa2a5 100644
--- a/sandbox/linux/system_headers/arm_linux_ucontext.h
+++ b/sandbox/linux/system_headers/arm_linux_ucontext.h
@@ -5,6 +5,8 @@
#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_ARM_LINUX_UCONTEXT_H_
#define SANDBOX_LINUX_SYSTEM_HEADERS_ARM_LINUX_UCONTEXT_H_
+#include <stddef.h>
+
#if !defined(__BIONIC_HAVE_UCONTEXT_T)
#if !defined(__native_client_nonsfi__)
#include <asm/sigcontext.h>
diff --git a/sandbox/linux/system_headers/i386_linux_ucontext.h b/sandbox/linux/system_headers/i386_linux_ucontext.h
index 61d9f7a9b8..f4380339d9 100644
--- a/sandbox/linux/system_headers/i386_linux_ucontext.h
+++ b/sandbox/linux/system_headers/i386_linux_ucontext.h
@@ -5,6 +5,9 @@
#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_ANDROID_I386_UCONTEXT_H_
#define SANDBOX_LINUX_SYSTEM_HEADERS_ANDROID_I386_UCONTEXT_H_
+#include <stddef.h>
+#include <stdint.h>
+
// We do something compatible with glibc. Hopefully, at some point Android will
// provide that for us, and __BIONIC_HAVE_UCONTEXT_T should be defined.
// This is mostly copied from breakpad (common/android/include/sys/ucontext.h),
diff --git a/sandbox/linux/system_headers/linux_signal.h b/sandbox/linux/system_headers/linux_signal.h
index 5db7fc5ea1..fb9a47b8d1 100644
--- a/sandbox/linux/system_headers/linux_signal.h
+++ b/sandbox/linux/system_headers/linux_signal.h
@@ -5,9 +5,63 @@
#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_SIGNAL_H_
#define SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_SIGNAL_H_
+#include <stdint.h>
+
// NOTE: On some toolchains, signal related ABI is incompatible with Linux's
// (not undefined, but defined different values and in different memory
// layouts). So, fill the gap here.
+#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || \
+ defined(__aarch64__)
+
+#define LINUX_SIGHUP 1
+#define LINUX_SIGINT 2
+#define LINUX_SIGQUIT 3
+#define LINUX_SIGABRT 6
+#define LINUX_SIGBUS 7
+#define LINUX_SIGUSR1 10
+#define LINUX_SIGSEGV 11
+#define LINUX_SIGUSR2 12
+#define LINUX_SIGPIPE 13
+#define LINUX_SIGTERM 15
+#define LINUX_SIGCHLD 17
+#define LINUX_SIGSYS 31
+
+#define LINUX_SIG_BLOCK 0
+#define LINUX_SIG_UNBLOCK 1
+
+#define LINUX_SA_SIGINFO 4
+#define LINUX_SA_NODEFER 0x40000000
+#define LINUX_SA_RESTART 0x10000000
+
+#define LINUX_SIG_DFL 0
+
+#elif defined(__mips__)
+
+#define LINUX_SIGHUP 1
+#define LINUX_SIGINT 2
+#define LINUX_SIGQUIT 3
+#define LINUX_SIGABRT 6
+#define LINUX_SIGBUS 10
+#define LINUX_SIGSEGV 11
+#define LINUX_SIGSYS 12
+#define LINUX_SIGPIPE 13
+#define LINUX_SIGTERM 15
+#define LINUX_SIGUSR1 16
+#define LINUX_SIGUSR2 17
+#define LINUX_SIGCHLD 18
+
+#define LINUX_SIG_BLOCK 1
+#define LINUX_SIG_UNBLOCK 2
+
+#define LINUX_SA_SIGINFO 0x00000008
+#define LINUX_SA_NODEFER 0x40000000
+#define LINUX_SA_RESTART 0x10000000
+
+#define LINUX_SIG_DFL 0
+
+#else
+#error "Unsupported platform"
+#endif
#if defined(__native_client_nonsfi__)
#if !defined(__i386__) && !defined(__arm__)
@@ -16,20 +70,6 @@
#include <signal.h>
-#define LINUX_SIGBUS 7 // 10 in PNaCl toolchain.
-#define LINUX_SIGSEGV 11 // 11 in PNaCl toolchain. Defined for consistency.
-#define LINUX_SIGCHLD 17 // 20 in PNaCl toolchain.
-#define LINUX_SIGSYS 31 // 12 in PNaCl toolchain.
-
-#define LINUX_SIG_BLOCK 0 // 1 in PNaCl toolchain.
-#define LINUX_SIG_UNBLOCK 1 // 2 in PNaCl toolchain.
-
-#define LINUX_SA_SIGINFO 4 // 2 in PNaCl toolchain.
-#define LINUX_SA_NODEFER 0x40000000 // Undefined in PNaCl toolchain.
-#define LINUX_SA_RESTART 0x10000000 // Undefined in PNaCl toolchain.
-
-#define LINUX_SIG_DFL 0 // In PNaCl toolchain, unneeded cast is applied.
-
struct LinuxSigInfo {
int si_signo;
int si_errno;
@@ -44,22 +84,27 @@ struct LinuxSigInfo {
#else // !defined(__native_client_nonsfi__)
-// Just alias the toolchain's value.
#include <signal.h>
-#define LINUX_SIGBUS SIGBUS
-#define LINUX_SIGSEGV SIGSEGV
-#define LINUX_SIGCHLD SIGCHLD
-#define LINUX_SIGSYS SIGSYS
-
-#define LINUX_SIG_BLOCK SIG_BLOCK
-#define LINUX_SIG_UNBLOCK SIG_UNBLOCK
-
-#define LINUX_SA_SIGINFO SA_SIGINFO
-#define LINUX_SA_NODEFER SA_NODEFER
-#define LINUX_SA_RESTART SA_RESTART
-
-#define LINUX_SIG_DFL SIG_DFL
+static_assert(LINUX_SIGHUP == SIGHUP, "LINUX_SIGHUP == SIGHUP");
+static_assert(LINUX_SIGINT == SIGINT, "LINUX_SIGINT == SIGINT");
+static_assert(LINUX_SIGQUIT == SIGQUIT, "LINUX_SIGQUIT == SIGQUIT");
+static_assert(LINUX_SIGABRT == SIGABRT, "LINUX_SIGABRT == SIGABRT");
+static_assert(LINUX_SIGBUS == SIGBUS, "LINUX_SIGBUS == SIGBUS");
+static_assert(LINUX_SIGUSR1 == SIGUSR1, "LINUX_SIGUSR1 == SIGUSR1");
+static_assert(LINUX_SIGSEGV == SIGSEGV, "LINUX_SIGSEGV == SIGSEGV");
+static_assert(LINUX_SIGUSR2 == SIGUSR2, "LINUX_SIGUSR2 == SIGUSR2");
+static_assert(LINUX_SIGPIPE == SIGPIPE, "LINUX_SIGPIPE == SIGPIPE");
+static_assert(LINUX_SIGTERM == SIGTERM, "LINUX_SIGTERM == SIGTERM");
+static_assert(LINUX_SIGCHLD == SIGCHLD, "LINUX_SIGCHLD == SIGCHLD");
+static_assert(LINUX_SIGSYS == SIGSYS, "LINUX_SIGSYS == SIGSYS");
+static_assert(LINUX_SIG_BLOCK == SIG_BLOCK, "LINUX_SIG_BLOCK == SIG_BLOCK");
+static_assert(LINUX_SIG_UNBLOCK == SIG_UNBLOCK,
+ "LINUX_SIG_UNBLOCK == SIG_UNBLOCK");
+static_assert(LINUX_SA_SIGINFO == SA_SIGINFO, "LINUX_SA_SIGINFO == SA_SIGINFO");
+static_assert(LINUX_SA_NODEFER == SA_NODEFER, "LINUX_SA_NODEFER == SA_NODEFER");
+static_assert(LINUX_SA_RESTART == SA_RESTART, "LINUX_SA_RESTART == SA_RESTART");
+static_assert(LINUX_SIG_DFL == SIG_DFL, "LINUX_SIG_DFL == SIG_DFL");
typedef siginfo_t LinuxSigInfo;
@@ -70,4 +115,32 @@ typedef siginfo_t LinuxSigInfo;
#endif // !defined(__native_client_nonsfi__)
+// struct sigset_t is different size in PNaCl from the Linux's.
+#if defined(__mips__)
+#if !defined(_NSIG_WORDS)
+#define _NSIG_WORDS 4
+#endif
+struct LinuxSigSet {
+ unsigned long sig[_NSIG_WORDS];
+};
+#else
+typedef uint64_t LinuxSigSet;
+#endif
+
+// struct sigaction is different in PNaCl from the Linux's.
+#if defined(__mips__)
+struct LinuxSigAction {
+ unsigned int sa_flags;
+ void (*kernel_handler)(int);
+ LinuxSigSet sa_mask;
+};
+#else
+struct LinuxSigAction {
+ void (*kernel_handler)(int);
+ uint32_t sa_flags;
+ void (*sa_restorer)(void);
+ LinuxSigSet sa_mask;
+};
+#endif
+
#endif // SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_SIGNAL_H_
diff --git a/sandbox/linux/system_headers/mips_linux_ucontext.h b/sandbox/linux/system_headers/mips_linux_ucontext.h
index 27b3763522..774bf312ea 100644
--- a/sandbox/linux/system_headers/mips_linux_ucontext.h
+++ b/sandbox/linux/system_headers/mips_linux_ucontext.h
@@ -5,6 +5,8 @@
#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_MIPS_LINUX_UCONTEXT_H_
#define SANDBOX_LINUX_SYSTEM_HEADERS_MIPS_LINUX_UCONTEXT_H_
+#include <stdint.h>
+
// This is mostly copied from breakpad (common/android/include/sys/ucontext.h),
// except we do use sigset_t for uc_sigmask instead of a custom type.
#if !defined(__BIONIC_HAVE_UCONTEXT_T)
diff --git a/sandbox/linux/system_headers/x86_64_linux_ucontext.h b/sandbox/linux/system_headers/x86_64_linux_ucontext.h
index 57b8919a9c..1f1abe642f 100644
--- a/sandbox/linux/system_headers/x86_64_linux_ucontext.h
+++ b/sandbox/linux/system_headers/x86_64_linux_ucontext.h
@@ -5,6 +5,8 @@
#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_X86_64_LINUX_UCONTEXT_H_
#define SANDBOX_LINUX_SYSTEM_HEADERS_X86_64_LINUX_UCONTEXT_H_
+#include <stdint.h>
+
// We do something compatible with glibc. Hopefully, at some point Android will
// provide that for us, and __BIONIC_HAVE_UCONTEXT_T should be defined.
// Spec:
diff --git a/sandbox/mac/BUILD.gn b/sandbox/mac/BUILD.gn
index 13960bfaef..cdaf527a56 100644
--- a/sandbox/mac/BUILD.gn
+++ b/sandbox/mac/BUILD.gn
@@ -57,6 +57,8 @@ component("sandbox") {
"os_compatibility.h",
"policy.cc",
"policy.h",
+ "pre_exec_delegate.cc",
+ "pre_exec_delegate.h",
"xpc.cc",
"xpc.h",
"xpc_message_server.cc",
diff --git a/sandbox/mac/message_server.h b/sandbox/mac/message_server.h
index 1cd40b0a3d..6ee119bd5e 100644
--- a/sandbox/mac/message_server.h
+++ b/sandbox/mac/message_server.h
@@ -44,6 +44,11 @@ class MessageServer {
// returns false, no other methods may be called on this class.
virtual bool Initialize() = 0;
+ // Blocks the calling thread while the server shuts down. This prevents
+ // the server from receiving new messages. After this method is called,
+ // no other methods may be called on this class.
+ virtual void Shutdown() = 0;
+
// Given a received request message, returns the PID of the sending process.
virtual pid_t GetMessageSenderPID(IPCMessage request) = 0;
diff --git a/sandbox/mac/sandbox_mac.gypi b/sandbox/mac/sandbox_mac.gypi
index d5013f832e..91ad20bac7 100644
--- a/sandbox/mac/sandbox_mac.gypi
+++ b/sandbox/mac/sandbox_mac.gypi
@@ -19,6 +19,8 @@
'os_compatibility.h',
'policy.cc',
'policy.h',
+ 'pre_exec_delegate.cc',
+ 'pre_exec_delegate.h',
'xpc.cc',
'xpc.h',
'xpc_message_server.cc',
@@ -111,4 +113,19 @@
},
},
],
+ 'conditions': [
+ ['test_isolation_mode != "noop"', {
+ 'targets': [
+ {
+ 'target_name': 'sandbox_mac_unittests_run',
+ 'type': 'none',
+ 'dependencies': [
+ 'sandbox_mac_unittests',
+ ],
+ 'includes': [ '../../build/isolate.gypi' ],
+ 'sources': [ '../sandbox_mac_unittests.isolate' ],
+ },
+ ],
+ }],
+ ],
}
diff --git a/sandbox/mac/xpc_private_stubs.sig b/sandbox/mac/xpc_private_stubs.sig
index 7ab2934c52..b8e1c50b29 100644
--- a/sandbox/mac/xpc_private_stubs.sig
+++ b/sandbox/mac/xpc_private_stubs.sig
@@ -10,6 +10,9 @@
void xpc_dictionary_set_mach_send(xpc_object_t dictionary, const char* name, mach_port_t port);
void xpc_dictionary_get_audit_token(xpc_object_t dictionary, audit_token_t* token);
+// Raw object getters.
+mach_port_t xpc_mach_send_get_right(xpc_object_t value);
+
// Pipe methods.
xpc_pipe_t xpc_pipe_create_from_port(mach_port_t port, int flags);
int xpc_pipe_receive(mach_port_t port, xpc_object_t* message);
diff --git a/sandbox/mac/xpc_stubs.sig b/sandbox/mac/xpc_stubs.sig
index d20af58a6e..b8e769972f 100644
--- a/sandbox/mac/xpc_stubs.sig
+++ b/sandbox/mac/xpc_stubs.sig
@@ -16,4 +16,5 @@ uint64_t xpc_dictionary_get_uint64(xpc_object_t dictionary, const char* key);
void xpc_dictionary_set_uint64(xpc_object_t dictionary, const char* key, uint64_t value);
int64_t xpc_dictionary_get_int64(xpc_object_t dictionary, const char* key);
void xpc_dictionary_set_int64(xpc_object_t dictionary, const char* key, int64_t value);
+bool xpc_dictionary_get_bool(xpc_object_t dictionary, const char* key);
xpc_object_t xpc_dictionary_create_reply(xpc_object_t request);
diff --git a/sandbox/mac/xpc_stubs_header.fragment b/sandbox/mac/xpc_stubs_header.fragment
index 8197587fc7..2aa81ccc9e 100644
--- a/sandbox/mac/xpc_stubs_header.fragment
+++ b/sandbox/mac/xpc_stubs_header.fragment
@@ -6,6 +6,8 @@
#define SANDBOX_MAC_XPC_STUBS_HEADER_FRAGMENT_
#include <bsm/libbsm.h>
+#include <stddef.h>
+#include <stdint.h>
#include "sandbox/sandbox_export.h"
@@ -28,4 +30,49 @@ extern "C" {
typedef struct _xpc_pipe_s* xpc_pipe_t;
} // extern "C"
+#if defined(MAC_OS_X_VERSION_10_7) && \
+ MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7
+// Redeclare methods that only exist on 10.7+ to suppress
+// -Wpartial-availability warnings.
+extern "C" {
+XPC_EXPORT XPC_NONNULL1 XPC_NONNULL2 void
+xpc_dictionary_set_int64(xpc_object_t xdict, const char* key, int64_t value);
+
+XPC_EXPORT XPC_NONNULL1 void xpc_release(xpc_object_t object);
+
+XPC_EXPORT XPC_WARN_RESULT XPC_NONNULL_ALL
+bool xpc_dictionary_get_bool(xpc_object_t xdict, const char* key);
+
+XPC_EXPORT XPC_WARN_RESULT XPC_NONNULL_ALL int64_t
+xpc_dictionary_get_int64(xpc_object_t xdict, const char* key);
+
+XPC_EXPORT XPC_WARN_RESULT XPC_NONNULL_ALL
+const char* xpc_dictionary_get_string(xpc_object_t xdict, const char* key);
+
+XPC_EXPORT XPC_WARN_RESULT XPC_NONNULL_ALL uint64_t
+xpc_dictionary_get_uint64(xpc_object_t xdict, const char* key);
+
+XPC_EXPORT XPC_NONNULL1 XPC_NONNULL2 void
+xpc_dictionary_set_uint64(xpc_object_t xdict, const char* key, uint64_t value);
+
+XPC_EXPORT XPC_NONNULL1 XPC_NONNULL2
+void xpc_dictionary_set_string(xpc_object_t xdict, const char* key,
+ const char* string);
+
+XPC_EXPORT XPC_MALLOC XPC_RETURNS_RETAINED XPC_WARN_RESULT xpc_object_t
+xpc_dictionary_create(const char* const* keys,
+ const xpc_object_t* values,
+ size_t count);
+XPC_EXPORT XPC_MALLOC XPC_RETURNS_RETAINED XPC_WARN_RESULT XPC_NONNULL_ALL
+ xpc_object_t
+ xpc_dictionary_create_reply(xpc_object_t original);
+
+XPC_EXPORT XPC_WARN_RESULT XPC_NONNULL1 XPC_NONNULL2
+xpc_object_t xpc_dictionary_get_value(xpc_object_t xdict, const char* key);
+
+XPC_EXPORT XPC_MALLOC XPC_WARN_RESULT XPC_NONNULL1
+char* xpc_copy_description(xpc_object_t object);
+} // extern "C"
+#endif
+
#endif // SANDBOX_MAC_XPC_STUBS_HEADER_FRAGMENT_
diff --git a/sandbox/sandbox_export.h b/sandbox/sandbox_export.h
index 40a4036640..35d6a1ba26 100644
--- a/sandbox/sandbox_export.h
+++ b/sandbox/sandbox_export.h
@@ -13,16 +13,13 @@
#if defined(SANDBOX_IMPLEMENTATION)
#define SANDBOX_EXPORT __attribute__((visibility("default")))
-#define SANDBOX_EXPORT_PRIVATE __attribute__((visibility("default")))
#else
#define SANDBOX_EXPORT
-#define SANDBOX_EXPORT_PRIVATE
#endif // defined(SANDBOX_IMPLEMENTATION)
#else // defined(COMPONENT_BUILD)
#define SANDBOX_EXPORT
-#define SANDBOX_EXPORT_PRIVATE
#endif // defined(COMPONENT_BUILD)
diff --git a/sandbox/sandbox_linux_unittests.isolate b/sandbox/sandbox_linux_unittests.isolate
index 2dadddd098..2b7c2a73af 100644
--- a/sandbox/sandbox_linux_unittests.isolate
+++ b/sandbox/sandbox_linux_unittests.isolate
@@ -12,10 +12,6 @@
'command': [
'<(PRODUCT_DIR)/sandbox_linux_unittests',
],
- 'files': [
- '<(PRODUCT_DIR)/sandbox_linux_unittests',
- ],
- 'read_only': 1,
},
}],
],
diff --git a/sandbox/win/BUILD.gn b/sandbox/win/BUILD.gn
index 3063f7f17d..327396b5d1 100644
--- a/sandbox/win/BUILD.gn
+++ b/sandbox/win/BUILD.gn
@@ -4,7 +4,11 @@
import("//testing/test.gni")
-source_set("sandbox") {
+# This needs to be a static library rather than a sources set because small
+# portions of this are used in some contexts (like chrome_elf), and it
+# doesnn't seem to dead-code strip very well. This saves 12K on chrome_elf.dll,
+# over a source set, for example.
+static_library("sandbox") {
sources = [
"src/acl.cc",
"src/acl.h",
@@ -34,8 +38,6 @@ source_set("sandbox") {
"src/handle_interception.h",
"src/handle_policy.cc",
"src/handle_policy.h",
- "src/handle_table.cc",
- "src/handle_table.h",
"src/interception.cc",
"src/interception.h",
"src/interception_agent.cc",
@@ -101,14 +103,14 @@ source_set("sandbox") {
"src/sandbox_policy.h",
"src/sandbox_policy_base.cc",
"src/sandbox_policy_base.h",
+ "src/sandbox_rand.cc",
+ "src/sandbox_rand.h",
"src/sandbox_types.h",
"src/sandbox_utils.cc",
"src/sandbox_utils.h",
"src/security_level.h",
"src/service_resolver.cc",
"src/service_resolver.h",
- "src/shared_handles.cc",
- "src/shared_handles.h",
"src/sharedmem_ipc_client.cc",
"src/sharedmem_ipc_client.h",
"src/sharedmem_ipc_server.cc",
@@ -127,6 +129,8 @@ source_set("sandbox") {
"src/target_process.h",
"src/target_services.cc",
"src/target_services.h",
+ "src/top_level_dispatcher.cc",
+ "src/top_level_dispatcher.h",
"src/win2k_threadpool.cc",
"src/win2k_threadpool.h",
"src/win_utils.cc",
@@ -161,6 +165,8 @@ source_set("sandbox") {
]
}
+ configs += [ "//build/config:precompiled_headers" ]
+
deps = [
"//base",
"//base:base_static",
@@ -196,6 +202,7 @@ test("sbox_integration_tests") {
"src/handle_policy_test.cc",
"src/integrity_level_test.cc",
"src/ipc_ping_test.cc",
+ "src/lpc_policy_test.cc",
"src/named_pipe_policy_test.cc",
"src/policy_target_test.cc",
"src/process_mitigations_test.cc",
@@ -246,6 +253,7 @@ test("sbox_unittests") {
"src/policy_low_level_unittest.cc",
"src/policy_opcodes_unittest.cc",
"src/restricted_token_unittest.cc",
+ "src/sandbox_nt_util_unittest.cc",
"src/service_resolver_unittest.cc",
"src/sid_unittest.cc",
"src/threadpool_unittest.cc",
@@ -279,8 +287,8 @@ test("sandbox_poc") {
libs = [ "comctl32.lib" ]
deps = [
- ":sandbox",
":pocdll",
+ ":sandbox",
]
}
@@ -299,4 +307,8 @@ shared_library("pocdll") {
]
defines = [ "POCDLL_EXPORTS" ]
+
+ deps = [
+ "//build/config/sanitizers:deps",
+ ]
}
diff --git a/sandbox/win/OWNERS b/sandbox/win/OWNERS
index fd5dcfda2c..85047f7690 100644
--- a/sandbox/win/OWNERS
+++ b/sandbox/win/OWNERS
@@ -1,4 +1,3 @@
cpu@chromium.org
jschuh@chromium.org
-rvargas@chromium.org
wfh@chromium.org
diff --git a/sandbox/win/sandbox_poc/pocdll/utils.h b/sandbox/win/sandbox_poc/pocdll/utils.h
index ae4286147a..0a6ad377fd 100644
--- a/sandbox/win/sandbox_poc/pocdll/utils.h
+++ b/sandbox/win/sandbox_poc/pocdll/utils.h
@@ -7,7 +7,8 @@
#include <stdio.h>
#include <io.h>
-#include "base/basictypes.h"
+
+#include "base/macros.h"
// Class to convert a HANDLE to a FILE *. The FILE * is closed when the
// object goes out of scope
diff --git a/sandbox/win/sandbox_win.gypi b/sandbox/win/sandbox_win.gypi
index e085cfb5ef..f0d275aed8 100644
--- a/sandbox/win/sandbox_win.gypi
+++ b/sandbox/win/sandbox_win.gypi
@@ -41,8 +41,6 @@
'src/handle_interception.h',
'src/handle_policy.cc',
'src/handle_policy.h',
- 'src/handle_table.cc',
- 'src/handle_table.h',
'src/interception.cc',
'src/interception.h',
'src/interception_agent.cc',
@@ -106,6 +104,8 @@
'src/sandbox_policy_base.cc',
'src/sandbox_policy_base.h',
'src/sandbox_policy.h',
+ 'src/sandbox_rand.cc',
+ 'src/sandbox_rand.h',
'src/sandbox_types.h',
'src/sandbox_utils.cc',
'src/sandbox_utils.h',
@@ -114,8 +114,6 @@
'src/security_level.h',
'src/service_resolver.cc',
'src/service_resolver.h',
- 'src/shared_handles.cc',
- 'src/shared_handles.h',
'src/sharedmem_ipc_client.cc',
'src/sharedmem_ipc_client.h',
'src/sharedmem_ipc_server.cc',
@@ -134,6 +132,8 @@
'src/target_process.h',
'src/target_services.cc',
'src/target_services.h',
+ 'src/top_level_dispatcher.cc',
+ 'src/top_level_dispatcher.h',
'src/win_utils.cc',
'src/win_utils.h',
'src/win2k_threadpool.cc',
@@ -189,12 +189,6 @@
'include_dirs': [
'../..',
],
- 'direct_dependent_settings': {
- 'include_dirs': [
- 'src',
- '../..',
- ],
- },
'target_conditions': [
['target_arch=="ia32"', {
'copies': [
@@ -227,6 +221,7 @@
'src/handle_closer_test.cc',
'src/integrity_level_test.cc',
'src/ipc_ping_test.cc',
+ 'src/lpc_policy_test.cc',
'src/named_pipe_policy_test.cc',
'src/policy_target_test.cc',
'src/process_mitigations_test.cc',
@@ -278,6 +273,7 @@
'src/policy_low_level_unittest.cc',
'src/policy_opcodes_unittest.cc',
'src/ipc_unittest.cc',
+ 'src/sandbox_nt_util_unittest.cc',
'src/threadpool_unittest.cc',
'src/win_utils_unittest.cc',
'tests/common/test_utils.cc',
@@ -357,17 +353,54 @@
'include_dirs': [
'../..',
],
- 'direct_dependent_settings': {
- 'include_dirs': [
- 'src',
- '../..',
- ],
- },
'defines': [
'<@(nacl_win64_defines)',
]
},
],
}],
+ ['test_isolation_mode != "noop"', {
+ 'targets': [
+ {
+ 'target_name': 'sbox_integration_tests_run',
+ 'type': 'none',
+ 'dependencies': [
+ 'sbox_integration_tests',
+ ],
+ 'includes': [
+ '../../build/isolate.gypi',
+ ],
+ 'sources': [
+ '../sbox_integration_tests.isolate',
+ ],
+ },
+ {
+ 'target_name': 'sbox_unittests_run',
+ 'type': 'none',
+ 'dependencies': [
+ 'sbox_unittests',
+ ],
+ 'includes': [
+ '../../build/isolate.gypi',
+ ],
+ 'sources': [
+ '../sbox_unittests.isolate',
+ ],
+ },
+ {
+ 'target_name': 'sbox_validation_tests_run',
+ 'type': 'none',
+ 'dependencies': [
+ 'sbox_validation_tests',
+ ],
+ 'includes': [
+ '../../build/isolate.gypi',
+ ],
+ 'sources': [
+ '../sbox_validation_tests.isolate',
+ ],
+ },
+ ],
+ }],
],
}
diff --git a/sandbox/win/src/crosscall_client.h b/sandbox/win/src/crosscall_client.h
index 5b1bce71b2..60ff2437a0 100644
--- a/sandbox/win/src/crosscall_client.h
+++ b/sandbox/win/src/crosscall_client.h
@@ -5,6 +5,9 @@
#ifndef SANDBOX_SRC_CROSSCALL_CLIENT_H_
#define SANDBOX_SRC_CROSSCALL_CLIENT_H_
+#include <stddef.h>
+#include <stdint.h>
+
#include "sandbox/win/src/crosscall_params.h"
#include "sandbox/win/src/sandbox.h"
@@ -20,7 +23,7 @@
//
// The general interface of CrossCall is:
// ResultCode CrossCall(IPCProvider& ipc_provider,
-// uint32 tag,
+// uint32_t tag,
// const Par1& p1, const Par2& p2,...pn
// CrossCallReturn* answer)
//
@@ -40,7 +43,7 @@ namespace sandbox {
// this is the assumed channel size. This can be overridden in a given
// IPC implementation.
-const uint32 kIPCChannelSize = 1024;
+const uint32_t kIPCChannelSize = 1024;
// The copy helper uses templates to deduce the appropriate copy function to
// copy the input parameters in the buffer that is going to be send across the
@@ -67,9 +70,7 @@ class CopyHelper {
}
// Returns the size of the input in bytes.
- uint32 GetSize() const {
- return sizeof(T);
- }
+ uint32_t GetSize() const { return sizeof(T); }
// Returns true if the current type is used as an In or InOut parameter.
bool IsInOut() {
@@ -78,7 +79,7 @@ class CopyHelper {
// Returns this object's type.
ArgType GetType() {
- static_assert(sizeof(T) == sizeof(uint32), "specialization needed");
+ static_assert(sizeof(T) == sizeof(uint32_t), "specialization needed");
return UINT32_TYPE;
}
@@ -106,9 +107,7 @@ class CopyHelper<void*> {
}
// Returns the size of the input in bytes.
- uint32 GetSize() const {
- return sizeof(t_);
- }
+ uint32_t GetSize() const { return sizeof(t_); }
// Returns true if the current type is used as an In or InOut parameter.
bool IsInOut() {
@@ -147,12 +146,13 @@ class CopyHelper<const wchar_t*> {
// Returns the size of the string in bytes. We define a NULL string to
// be of zero length.
- uint32 GetSize() const {
+ uint32_t GetSize() const {
__try {
- return (!t_) ? 0 : static_cast<uint32>(StringLength(t_) * sizeof(t_[0]));
+ return (!t_) ? 0
+ : static_cast<uint32_t>(StringLength(t_) * sizeof(t_[0]));
}
__except(EXCEPTION_EXECUTE_HANDLER) {
- return kuint32max;
+ return UINT32_MAX;
}
}
@@ -194,9 +194,7 @@ class CopyHelper<wchar_t*> : public CopyHelper<const wchar_t*> {
return Base::Update(buffer);
}
- uint32 GetSize() const {
- return Base::GetSize();
- }
+ uint32_t GetSize() const { return Base::GetSize(); }
bool IsInOut() {
return Base::IsInOut();
@@ -224,9 +222,7 @@ class CopyHelper<const wchar_t[n]> : public CopyHelper<const wchar_t*> {
return Base::Update(buffer);
}
- uint32 GetSize() const {
- return Base::GetSize();
- }
+ uint32_t GetSize() const { return Base::GetSize(); }
bool IsInOut() {
return Base::IsInOut();
@@ -242,7 +238,8 @@ class CopyHelper<const wchar_t[n]> : public CopyHelper<const wchar_t*> {
// parameters.
class InOutCountedBuffer : public CountedBuffer {
public:
- InOutCountedBuffer(void* buffer, uint32 size) : CountedBuffer(buffer, size) {}
+ InOutCountedBuffer(void* buffer, uint32_t size)
+ : CountedBuffer(buffer, size) {}
};
// This copy helper template specialization catches the cases where the
@@ -272,9 +269,7 @@ class CopyHelper<InOutCountedBuffer> {
// Returns the size of the string in bytes. We define a NULL string to
// be of zero length.
- uint32 GetSize() const {
- return t_.Size();
- }
+ uint32_t GetSize() const { return t_.Size(); }
// Returns true if the current type is used as an In or InOut parameter.
bool IsInOut() {
@@ -317,7 +312,9 @@ class CopyHelper<InOutCountedBuffer> {
// CrossCall template with one input parameter
template <typename IPCProvider, typename Par1>
-ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1,
+ResultCode CrossCall(IPCProvider& ipc_provider,
+ uint32_t tag,
+ const Par1& p1,
CrossCallReturn* answer) {
XCALL_GEN_PARAMS_OBJ(1, call_params);
XCALL_GEN_COPY_PARAM(1, call_params);
@@ -334,8 +331,11 @@ ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1,
// CrossCall template with two input parameters.
template <typename IPCProvider, typename Par1, typename Par2>
-ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1,
- const Par2& p2, CrossCallReturn* answer) {
+ResultCode CrossCall(IPCProvider& ipc_provider,
+ uint32_t tag,
+ const Par1& p1,
+ const Par2& p2,
+ CrossCallReturn* answer) {
XCALL_GEN_PARAMS_OBJ(2, call_params);
XCALL_GEN_COPY_PARAM(1, call_params);
XCALL_GEN_COPY_PARAM(2, call_params);
@@ -352,8 +352,12 @@ ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1,
// CrossCall template with three input parameters.
template <typename IPCProvider, typename Par1, typename Par2, typename Par3>
-ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1,
- const Par2& p2, const Par3& p3, CrossCallReturn* answer) {
+ResultCode CrossCall(IPCProvider& ipc_provider,
+ uint32_t tag,
+ const Par1& p1,
+ const Par2& p2,
+ const Par3& p3,
+ CrossCallReturn* answer) {
XCALL_GEN_PARAMS_OBJ(3, call_params);
XCALL_GEN_COPY_PARAM(1, call_params);
XCALL_GEN_COPY_PARAM(2, call_params);
@@ -371,10 +375,17 @@ ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1,
}
// CrossCall template with four input parameters.
-template <typename IPCProvider, typename Par1, typename Par2, typename Par3,
+template <typename IPCProvider,
+ typename Par1,
+ typename Par2,
+ typename Par3,
typename Par4>
-ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1,
- const Par2& p2, const Par3& p3, const Par4& p4,
+ResultCode CrossCall(IPCProvider& ipc_provider,
+ uint32_t tag,
+ const Par1& p1,
+ const Par2& p2,
+ const Par3& p3,
+ const Par4& p4,
CrossCallReturn* answer) {
XCALL_GEN_PARAMS_OBJ(4, call_params);
XCALL_GEN_COPY_PARAM(1, call_params);
@@ -395,11 +406,20 @@ ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1,
}
// CrossCall template with five input parameters.
-template <typename IPCProvider, typename Par1, typename Par2, typename Par3,
- typename Par4, typename Par5>
-ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1,
- const Par2& p2, const Par3& p3, const Par4& p4,
- const Par5& p5, CrossCallReturn* answer) {
+template <typename IPCProvider,
+ typename Par1,
+ typename Par2,
+ typename Par3,
+ typename Par4,
+ typename Par5>
+ResultCode CrossCall(IPCProvider& ipc_provider,
+ uint32_t tag,
+ const Par1& p1,
+ const Par2& p2,
+ const Par3& p3,
+ const Par4& p4,
+ const Par5& p5,
+ CrossCallReturn* answer) {
XCALL_GEN_PARAMS_OBJ(5, call_params);
XCALL_GEN_COPY_PARAM(1, call_params);
XCALL_GEN_COPY_PARAM(2, call_params);
@@ -421,11 +441,22 @@ ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1,
}
// CrossCall template with six input parameters.
-template <typename IPCProvider, typename Par1, typename Par2, typename Par3,
- typename Par4, typename Par5, typename Par6>
-ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1,
- const Par2& p2, const Par3& p3, const Par4& p4,
- const Par5& p5, const Par6& p6, CrossCallReturn* answer) {
+template <typename IPCProvider,
+ typename Par1,
+ typename Par2,
+ typename Par3,
+ typename Par4,
+ typename Par5,
+ typename Par6>
+ResultCode CrossCall(IPCProvider& ipc_provider,
+ uint32_t tag,
+ const Par1& p1,
+ const Par2& p2,
+ const Par3& p3,
+ const Par4& p4,
+ const Par5& p5,
+ const Par6& p6,
+ CrossCallReturn* answer) {
XCALL_GEN_PARAMS_OBJ(6, call_params);
XCALL_GEN_COPY_PARAM(1, call_params);
XCALL_GEN_COPY_PARAM(2, call_params);
@@ -449,11 +480,23 @@ ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1,
}
// CrossCall template with seven input parameters.
-template <typename IPCProvider, typename Par1, typename Par2, typename Par3,
- typename Par4, typename Par5, typename Par6, typename Par7>
-ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1,
- const Par2& p2, const Par3& p3, const Par4& p4,
- const Par5& p5, const Par6& p6, const Par7& p7,
+template <typename IPCProvider,
+ typename Par1,
+ typename Par2,
+ typename Par3,
+ typename Par4,
+ typename Par5,
+ typename Par6,
+ typename Par7>
+ResultCode CrossCall(IPCProvider& ipc_provider,
+ uint32_t tag,
+ const Par1& p1,
+ const Par2& p2,
+ const Par3& p3,
+ const Par4& p4,
+ const Par5& p5,
+ const Par6& p6,
+ const Par7& p7,
CrossCallReturn* answer) {
XCALL_GEN_PARAMS_OBJ(7, call_params);
XCALL_GEN_COPY_PARAM(1, call_params);
diff --git a/sandbox/win/src/crosscall_params.h b/sandbox/win/src/crosscall_params.h
index 6facb202da..eb59c44239 100644
--- a/sandbox/win/src/crosscall_params.h
+++ b/sandbox/win/src/crosscall_params.h
@@ -7,30 +7,29 @@
#include <windows.h>
#include <lmaccess.h>
+#include <stddef.h>
+#include <stdint.h>
#include <memory>
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "sandbox/win/src/internal_types.h"
#include "sandbox/win/src/sandbox_types.h"
-namespace {
-
-// Increases |value| until there is no need for padding given an int64
+// Increases |value| until there is no need for padding given an int64_t
// alignment. Returns the increased value.
-uint32 Align(uint32 value) {
- uint32 alignment = sizeof(int64);
+inline uint32_t Align(uint32_t value) {
+ uint32_t alignment = sizeof(int64_t);
return ((value + alignment - 1) / alignment) * alignment;
}
-}
// This header is part of CrossCall: the sandbox inter-process communication.
// This header defines the basic types used both in the client IPC and in the
// server IPC code. CrossCallParams and ActualCallParams model the input
// parameters of an IPC call and CrossCallReturn models the output params and
// the return value.
//
-// An IPC call is defined by its 'tag' which is a (uint32) unique identifier
+// An IPC call is defined by its 'tag' which is a (uint32_t) unique identifier
// that is used to route the IPC call to the proper server. Every tag implies
// a complete call signature including the order and type of each parameter.
//
@@ -39,7 +38,7 @@ uint32 Align(uint32 value) {
// them are not supported.
//
// Another limitation of CrossCall is that the return value and output
-// parameters can only be uint32 integers. Returning complex structures or
+// parameters can only be uint32_t integers. Returning complex structures or
// strings is not supported.
namespace sandbox {
@@ -50,7 +49,7 @@ const size_t kExtendedReturnCount = 8;
// Union of multiple types to be used as extended results
// in the CrossCallReturn.
union MultiType {
- uint32 unsigned_int;
+ uint32_t unsigned_int;
void* pointer;
HANDLE handle;
ULONG_PTR ulong_ptr;
@@ -66,8 +65,8 @@ const int kMaxIpcParams = 9;
// Contains the information about a parameter in the ipc buffer.
struct ParamInfo {
ArgType type_;
- uint32 offset_;
- uint32 size_;
+ uint32_t offset_;
+ uint32_t size_;
};
// Models the return value and the return parameters of an IPC call
@@ -76,7 +75,7 @@ struct ParamInfo {
// might have to use other integer types.
struct CrossCallReturn {
// the IPC tag. It should match the original IPC tag.
- uint32 tag;
+ uint32_t tag;
// The result of the IPC operation itself.
ResultCode call_outcome;
// the result of the IPC call as executed in the server. The interpretation
@@ -86,7 +85,7 @@ struct CrossCallReturn {
DWORD win32_result;
};
// Number of extended return values.
- uint32 extended_count;
+ uint32_t extended_count;
// for calls that should return a windows handle. It is found here.
HANDLE handle;
// The array of extended values.
@@ -107,9 +106,7 @@ struct CrossCallReturn {
class CrossCallParams {
public:
// Returns the tag (ipc unique id) associated with this IPC.
- uint32 GetTag() const {
- return tag_;
- }
+ uint32_t GetTag() const { return tag_; }
// Returns the beggining of the buffer where the IPC params can be stored.
// prior to an IPC call
@@ -118,9 +115,7 @@ class CrossCallParams {
}
// Returns how many parameter this IPC call should have.
- const uint32 GetParamsCount() const {
- return params_count_;
- }
+ uint32_t GetParamsCount() const { return params_count_; }
// Returns a pointer to the CrossCallReturn structure.
CrossCallReturn* GetCallReturn() {
@@ -128,9 +123,7 @@ class CrossCallParams {
}
// Returns TRUE if this call contains InOut parameters.
- const bool IsInOut() const {
- return (1 == is_in_out_);
- }
+ bool IsInOut() const { return (1 == is_in_out_); }
// Tells the CrossCall object if it contains InOut parameters.
void SetIsInOut(bool value) {
@@ -142,17 +135,14 @@ class CrossCallParams {
protected:
// constructs the IPC call params. Called only from the derived classes
- CrossCallParams(uint32 tag, uint32 params_count)
- : tag_(tag),
- params_count_(params_count),
- is_in_out_(0) {
- }
+ CrossCallParams(uint32_t tag, uint32_t params_count)
+ : tag_(tag), is_in_out_(0), params_count_(params_count) {}
private:
- uint32 tag_;
- uint32 is_in_out_;
+ uint32_t tag_;
+ uint32_t is_in_out_;
CrossCallReturn call_return;
- const uint32 params_count_;
+ const uint32_t params_count_;
DISALLOW_COPY_AND_ASSIGN(CrossCallParams);
};
@@ -198,37 +188,40 @@ template <size_t NUMBER_PARAMS, size_t BLOCK_SIZE>
class ActualCallParams : public CrossCallParams {
public:
// constructor. Pass the ipc unique tag as input
- explicit ActualCallParams(uint32 tag)
+ explicit ActualCallParams(uint32_t tag)
: CrossCallParams(tag, NUMBER_PARAMS) {
param_info_[0].offset_ =
- static_cast<uint32>(parameters_ - reinterpret_cast<char*>(this));
+ static_cast<uint32_t>(parameters_ - reinterpret_cast<char*>(this));
}
// Testing-only constructor. Allows setting the |number_params| to a
// wrong value.
- ActualCallParams(uint32 tag, uint32 number_params)
+ ActualCallParams(uint32_t tag, uint32_t number_params)
: CrossCallParams(tag, number_params) {
param_info_[0].offset_ =
- static_cast<uint32>(parameters_ - reinterpret_cast<char*>(this));
+ static_cast<uint32_t>(parameters_ - reinterpret_cast<char*>(this));
}
// Testing-only method. Allows setting the apparent size to a wrong value.
// returns the previous size.
- uint32 OverrideSize(uint32 new_size) {
- uint32 previous_size = param_info_[NUMBER_PARAMS].offset_;
+ uint32_t OverrideSize(uint32_t new_size) {
+ uint32_t previous_size = param_info_[NUMBER_PARAMS].offset_;
param_info_[NUMBER_PARAMS].offset_ = new_size;
return previous_size;
}
// Copies each paramter into the internal buffer. For each you must supply:
// index: 0 for the first param, 1 for the next an so on
- bool CopyParamIn(uint32 index, const void* parameter_address, uint32 size,
- bool is_in_out, ArgType type) {
+ bool CopyParamIn(uint32_t index,
+ const void* parameter_address,
+ uint32_t size,
+ bool is_in_out,
+ ArgType type) {
if (index >= NUMBER_PARAMS) {
return false;
}
- if (kuint32max == size) {
+ if (UINT32_MAX == size) {
// Memory error while getting the size.
return false;
}
@@ -273,9 +266,7 @@ class ActualCallParams : public CrossCallParams {
// Returns the total size of the buffer. Only valid once all the paramters
// have been copied in with CopyParamIn.
- uint32 GetSize() const {
- return param_info_[NUMBER_PARAMS].offset_;
- }
+ uint32_t GetSize() const { return param_info_[NUMBER_PARAMS].offset_; }
protected:
ActualCallParams() : CrossCallParams(0, NUMBER_PARAMS) { }
diff --git a/sandbox/win/src/interception_internal.h b/sandbox/win/src/interception_internal.h
index 810478addb..45a0557e5e 100644
--- a/sandbox/win/src/interception_internal.h
+++ b/sandbox/win/src/interception_internal.h
@@ -9,6 +9,8 @@
#ifndef SANDBOX_SRC_INTERCEPTION_INTERNAL_H_
#define SANDBOX_SRC_INTERCEPTION_INTERNAL_H_
+#include <stddef.h>
+
#include "sandbox/win/src/sandbox_types.h"
namespace sandbox {
diff --git a/sandbox/win/src/internal_types.h b/sandbox/win/src/internal_types.h
index 026bedb064..e1028189d8 100644
--- a/sandbox/win/src/internal_types.h
+++ b/sandbox/win/src/internal_types.h
@@ -5,6 +5,8 @@
#ifndef SANDBOX_WIN_SRC_INTERNAL_TYPES_H_
#define SANDBOX_WIN_SRC_INTERNAL_TYPES_H_
+#include <stdint.h>
+
namespace sandbox {
const wchar_t kNtdllName[] = L"ntdll.dll";
@@ -28,18 +30,16 @@ enum ArgType {
// Encapsulates a pointer to a buffer and the size of the buffer.
class CountedBuffer {
public:
- CountedBuffer(void* buffer, uint32 size) : size_(size), buffer_(buffer) {}
+ CountedBuffer(void* buffer, uint32_t size) : size_(size), buffer_(buffer) {}
- uint32 Size() const {
- return size_;
- }
+ uint32_t Size() const { return size_; }
void* Buffer() const {
return buffer_;
}
private:
- uint32 size_;
+ uint32_t size_;
void* buffer_;
};
diff --git a/sandbox/win/src/nt_internals.h b/sandbox/win/src/nt_internals.h
index 40b29c6beb..2a39d5b94e 100644
--- a/sandbox/win/src/nt_internals.h
+++ b/sandbox/win/src/nt_internals.h
@@ -8,6 +8,7 @@
#define SANDBOX_WIN_SRC_NT_INTERNALS_H__
#include <windows.h>
+#include <stddef.h>
typedef LONG NTSTATUS;
#define NT_SUCCESS(st) (st >= 0)
@@ -308,15 +309,27 @@ typedef enum _PROCESSINFOCLASS {
} PROCESSINFOCLASS;
typedef PVOID PPEB;
-typedef PVOID KPRIORITY;
+typedef LONG KPRIORITY;
typedef struct _PROCESS_BASIC_INFORMATION {
- NTSTATUS ExitStatus;
+ union {
+ NTSTATUS ExitStatus;
+ PVOID padding_for_x64_0;
+ };
PPEB PebBaseAddress;
KAFFINITY AffinityMask;
- KPRIORITY BasePriority;
- ULONG UniqueProcessId;
- ULONG InheritedFromUniqueProcessId;
+ union {
+ KPRIORITY BasePriority;
+ PVOID padding_for_x64_1;
+ };
+ union {
+ DWORD UniqueProcessId;
+ PVOID padding_for_x64_2;
+ };
+ union {
+ DWORD InheritedFromUniqueProcessId;
+ PVOID padding_for_x64_3;
+ };
} PROCESS_BASIC_INFORMATION, *PPROCESS_BASIC_INFORMATION;
typedef NTSTATUS (WINAPI *NtQueryInformationProcessFunction)(
diff --git a/sandbox/win/src/policy_engine_params.h b/sandbox/win/src/policy_engine_params.h
index 5b3c5ef11c..fb4c00e3da 100644
--- a/sandbox/win/src/policy_engine_params.h
+++ b/sandbox/win/src/policy_engine_params.h
@@ -5,7 +5,8 @@
#ifndef SANDBOX_SRC_POLICY_ENGINE_PARAMS_H__
#define SANDBOX_SRC_POLICY_ENGINE_PARAMS_H__
-#include "base/basictypes.h"
+#include <stdint.h>
+
#include "sandbox/win/src/internal_types.h"
#include "sandbox/win/src/nt_internals.h"
#include "sandbox/win/src/sandbox_nt_util.h"
@@ -61,11 +62,11 @@ class ParameterSet {
ParameterSet() : real_type_(INVALID_TYPE), address_(NULL) {}
// Retrieve the stored parameter. If the type does not match ulong fail.
- bool Get(uint32* destination) const {
+ bool Get(uint32_t* destination) const {
if (real_type_ != UINT32_TYPE) {
return false;
}
- *destination = Void2TypePointerCopy<uint32>();
+ *destination = Void2TypePointerCopy<uint32_t>();
return true;
}
@@ -152,9 +153,8 @@ class ParameterSetEx<wchar_t const*> : public ParameterSet {
: ParameterSet(WCHAR_TYPE, address) {}
};
-
-template<>
-class ParameterSetEx<uint32> : public ParameterSet {
+template <>
+class ParameterSetEx<uint32_t> : public ParameterSet {
public:
ParameterSetEx(const void* address)
: ParameterSet(UINT32_TYPE, address) {}
diff --git a/sandbox/win/src/sandbox_factory.h b/sandbox/win/src/sandbox_factory.h
index 7a0280f908..f5888ffcda 100644
--- a/sandbox/win/src/sandbox_factory.h
+++ b/sandbox/win/src/sandbox_factory.h
@@ -5,6 +5,7 @@
#ifndef SANDBOX_SRC_SANDBOX_FACTORY_H__
#define SANDBOX_SRC_SANDBOX_FACTORY_H__
+#include "base/macros.h"
#include "sandbox/win/src/sandbox.h"
// SandboxFactory is a set of static methods to get access to the broker
diff --git a/sandbox/win/src/sandbox_policy.h b/sandbox/win/src/sandbox_policy.h
index 54bb2a9096..cc39c62839 100644
--- a/sandbox/win/src/sandbox_policy.h
+++ b/sandbox/win/src/sandbox_policy.h
@@ -5,9 +5,11 @@
#ifndef SANDBOX_WIN_SRC_SANDBOX_POLICY_H_
#define SANDBOX_WIN_SRC_SANDBOX_POLICY_H_
+#include <stddef.h>
+#include <stdint.h>
+
#include <string>
-#include "base/basictypes.h"
#include "base/strings/string16.h"
#include "sandbox/win/src/sandbox_types.h"
#include "sandbox/win/src/security_level.h"
@@ -75,12 +77,12 @@ class TargetPolicy {
// initial: the security level for the initial token. This is the token that
// is used by the process from the creation of the process until the moment
// the process calls TargetServices::LowerToken() or the process calls
- // win32's ReverToSelf(). Once this happens the initial token is no longer
+ // win32's RevertToSelf(). Once this happens the initial token is no longer
// available and the lockdown token is in effect. Using an initial token is
// not compatible with AppContainer, see SetAppContainer.
// lockdown: the security level for the token that comes into force after the
// process calls TargetServices::LowerToken() or the process calls
- // ReverToSelf(). See the explanation of each level in the TokenLevel
+ // RevertToSelf(). See the explanation of each level in the TokenLevel
// definition.
// Return value: SBOX_ALL_OK if the setting succeeds and false otherwise.
// Returns false if the lockdown value is more permissive than the initial
@@ -130,7 +132,8 @@ class TargetPolicy {
// http://msdn2.microsoft.com/en-us/library/ms684152.aspx
//
// Note: the recommended level is JOB_RESTRICTED or JOB_LOCKDOWN.
- virtual ResultCode SetJobLevel(JobLevel job_level, uint32 ui_exceptions) = 0;
+ virtual ResultCode SetJobLevel(JobLevel job_level,
+ uint32_t ui_exceptions) = 0;
// Sets a hard limit on the size of the commit set for the sandboxed process.
// If the limit is reached, the process will be terminated with
diff --git a/sandbox/win/src/sandbox_types.h b/sandbox/win/src/sandbox_types.h
index 3e531be4f4..b749b9ca51 100644
--- a/sandbox/win/src/sandbox_types.h
+++ b/sandbox/win/src/sandbox_types.h
@@ -54,13 +54,14 @@ enum ResultCode {
// If the sandbox cannot create a secure environment for the target, the
// target will be forcibly terminated. These are the process exit codes.
enum TerminationCodes {
- SBOX_FATAL_INTEGRITY = 7006, // Could not set the integrity level.
- SBOX_FATAL_DROPTOKEN = 7007, // Could not lower the token.
- SBOX_FATAL_FLUSHANDLES = 7008, // Failed to flush registry handles.
- SBOX_FATAL_CACHEDISABLE = 7009, // Failed to forbid HCKU caching.
- SBOX_FATAL_CLOSEHANDLES = 7010, // Failed to close pending handles.
- SBOX_FATAL_MITIGATION = 7011, // Could not set the mitigation policy.
- SBOX_FATAL_MEMORY_EXCEEDED = 7012, // Exceeded the job memory limit.
+ SBOX_FATAL_INTEGRITY = 7006, // Could not set the integrity level.
+ SBOX_FATAL_DROPTOKEN = 7007, // Could not lower the token.
+ SBOX_FATAL_FLUSHANDLES = 7008, // Failed to flush registry handles.
+ SBOX_FATAL_CACHEDISABLE = 7009, // Failed to forbid HCKU caching.
+ SBOX_FATAL_CLOSEHANDLES = 7010, // Failed to close pending handles.
+ SBOX_FATAL_MITIGATION = 7011, // Could not set the mitigation policy.
+ SBOX_FATAL_MEMORY_EXCEEDED = 7012, // Exceeded the job memory limit.
+ SBOX_FATAL_WARMUP = 7013, // Failed to warmup.
SBOX_FATAL_LAST
};
diff --git a/sandbox/win/src/security_level.h b/sandbox/win/src/security_level.h
index c89bbb4e24..26ec306a62 100644
--- a/sandbox/win/src/security_level.h
+++ b/sandbox/win/src/security_level.h
@@ -5,7 +5,7 @@
#ifndef SANDBOX_SRC_SECURITY_LEVEL_H_
#define SANDBOX_SRC_SECURITY_LEVEL_H_
-#include "base/basictypes.h"
+#include <stdint.h>
namespace sandbox {
@@ -138,7 +138,7 @@ enum JobLevel {
// Flags that are unsupported for the target OS will be silently ignored.
// Flags that are invalid for their application (pre or post startup) will
// return SBOX_ERROR_BAD_PARAMS.
-typedef uint64 MitigationFlags;
+typedef uint64_t MitigationFlags;
// Permanently enables DEP for the target process. Corresponds to
// PROCESS_CREATION_MITIGATION_POLICY_DEP_ENABLE.
diff --git a/sandbox/win/src/sidestep/preamble_patcher_with_stub.cpp b/sandbox/win/src/sidestep/preamble_patcher_with_stub.cpp
index 999d76bb21..b5016009d6 100644
--- a/sandbox/win/src/sidestep/preamble_patcher_with_stub.cpp
+++ b/sandbox/win/src/sidestep/preamble_patcher_with_stub.cpp
@@ -6,6 +6,8 @@
#include "sandbox/win/src/sidestep/preamble_patcher.h"
+#include <stddef.h>
+
#include "sandbox/win/src/sandbox_nt_util.h"
#include "sandbox/win/src/sidestep/mini_disassembler.h"