Compare commits

..

No commits in common. "v134.0.6998.39-1" and "master" have entirely different histories.

2550 changed files with 196101 additions and 133847 deletions

View file

@ -25,7 +25,7 @@ jobs:
path: | path: |
src/third_party/llvm-build/Release+Asserts/ src/third_party/llvm-build/Release+Asserts/
src/gn/ src/gn/
src/qemu-user-static*.deb src/qemu-user*.deb
key: toolchains-posix-${{ hashFiles('CHROMIUM_VERSION') }}-v${{ env.CACHE_EPOCH }} key: toolchains-posix-${{ hashFiles('CHROMIUM_VERSION') }}-v${{ env.CACHE_EPOCH }}
- name: Cache PGO (Linux, OpenWrt) - name: Cache PGO (Linux, OpenWrt)
uses: actions/cache@v4 uses: actions/cache@v4
@ -45,8 +45,8 @@ jobs:
- run: ./get-clang.sh - run: ./get-clang.sh
- run: EXTRA_FLAGS='target_os="android"' ./get-clang.sh - run: EXTRA_FLAGS='target_os="android"' ./get-clang.sh
- run: | - run: |
if [ ! -f qemu-user-static*.deb ]; then if [ ! -f qemu-user*.deb ]; then
wget https://snapshot.debian.org/archive/debian/20230611T210420Z/pool/main/q/qemu/qemu-user-static_8.0%2Bdfsg-4_amd64.deb wget https://snapshot.debian.org/archive/debian/20250405T083429Z/pool/main/q/qemu/qemu-user_9.2.2%2Bds-1%2Bb2_amd64.deb
fi fi
cache-toolchains-win: cache-toolchains-win:
runs-on: windows-2022 runs-on: windows-2022
@ -97,7 +97,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
arch: [x64, x86, arm64, arm, mipsel, mips64el, riscv64] arch: [x64, x86, arm64, arm, mipsel, mips64el, riscv64, loong64]
env: env:
EXTRA_FLAGS: 'target_cpu="${{ matrix.arch }}"' EXTRA_FLAGS: 'target_cpu="${{ matrix.arch }}"'
BUNDLE: naiveproxy-${{ github.event.release.tag_name }}-${{ github.job }}-${{ matrix.arch }} BUNDLE: naiveproxy-${{ github.event.release.tag_name }}-${{ github.job }}-${{ matrix.arch }}
@ -109,7 +109,7 @@ jobs:
path: | path: |
src/third_party/llvm-build/Release+Asserts/ src/third_party/llvm-build/Release+Asserts/
src/gn/ src/gn/
src/qemu-user-static*.deb src/qemu-user*.deb
key: toolchains-posix-${{ hashFiles('CHROMIUM_VERSION') }}-v${{ env.CACHE_EPOCH }} key: toolchains-posix-${{ hashFiles('CHROMIUM_VERSION') }}-v${{ env.CACHE_EPOCH }}
- name: Cache PGO (Linux, OpenWrt) - name: Cache PGO (Linux, OpenWrt)
uses: actions/cache@v4 uses: actions/cache@v4
@ -138,13 +138,13 @@ jobs:
sudo apt update sudo apt update
sudo apt install ninja-build pkg-config ccache bubblewrap sudo apt install ninja-build pkg-config ccache bubblewrap
sudo apt remove -y qemu-user-binfmt sudo apt remove -y qemu-user-binfmt
sudo dpkg -i qemu-user-static*.deb sudo dpkg -i qemu-user*.deb
# libc6-i386 interferes with x86 build # libc6-i386 interferes with x86 build
sudo apt remove libc6-i386 sudo apt remove libc6-i386
- run: ./get-clang.sh - run: ./get-clang.sh
- run: ccache -z - run: ccache -z
- run: ./build.sh - run: ./build.sh
- run: ccache -s - run: ccache -s && ccache --evict-older-than 1d
- run: ../tests/basic.sh out/Release/naive - run: ../tests/basic.sh out/Release/naive
- name: Pack naiveproxy assets - name: Pack naiveproxy assets
run: | run: |
@ -192,7 +192,7 @@ jobs:
path: | path: |
src/third_party/llvm-build/Release+Asserts/ src/third_party/llvm-build/Release+Asserts/
src/gn/ src/gn/
src/qemu-user-static*.deb src/qemu-user*.deb
key: toolchains-posix-${{ hashFiles('CHROMIUM_VERSION') }}-v${{ env.CACHE_EPOCH }} key: toolchains-posix-${{ hashFiles('CHROMIUM_VERSION') }}-v${{ env.CACHE_EPOCH }}
- name: Cache AFDO (Android) - name: Cache AFDO (Android)
uses: actions/cache@v4 uses: actions/cache@v4
@ -222,13 +222,13 @@ jobs:
sudo apt update sudo apt update
sudo apt install ninja-build pkg-config ccache bubblewrap sudo apt install ninja-build pkg-config ccache bubblewrap
sudo apt remove -y qemu-user-binfmt sudo apt remove -y qemu-user-binfmt
sudo dpkg -i qemu-user-static*.deb sudo dpkg -i qemu-user*.deb
# libc6-i386 interferes with x86 build # libc6-i386 interferes with x86 build
sudo apt remove libc6-i386 sudo apt remove libc6-i386
- run: ./get-clang.sh - run: ./get-clang.sh
- run: ccache -z - run: ccache -z
- run: ./build.sh - run: ./build.sh
- run: ccache -s - run: ccache -s && ccache --evict-older-than 1d
- run: ./get-android-sys.sh - run: ./get-android-sys.sh
- run: ../tests/basic.sh out/Release/naive - run: ../tests/basic.sh out/Release/naive
- name: Gradle cache - name: Gradle cache
@ -355,7 +355,7 @@ jobs:
- run: ./get-clang.sh - run: ./get-clang.sh
- run: ccache -z - run: ccache -z
- run: ./build.sh - run: ./build.sh
- run: ccache -s - run: ccache -s && ccache --evict-older-than 1d
- run: ../tests/basic.sh out/Release/naive - run: ../tests/basic.sh out/Release/naive
# No real or emulated environment is available to test this. # No real or emulated environment is available to test this.
if: ${{ matrix.arch != 'arm64' }} if: ${{ matrix.arch != 'arm64' }}
@ -510,6 +510,11 @@ jobs:
target_cpu: riscv64 target_cpu: riscv64
openwrt_release: '23.05.0' openwrt_release: '23.05.0'
openwrt_gcc_ver: '12.3.0' openwrt_gcc_ver: '12.3.0'
- arch: loongarch64
openwrt: "target=loongarch64 subtarget=generic"
target_cpu: loong64
openwrt_release: '24.10.0'
openwrt_gcc_ver: '13.3.0'
env: env:
EXTRA_FLAGS: target_cpu="${{ matrix.target_cpu }}" target_os="openwrt" ${{ matrix.extra }} enable_shadow_metadata=false EXTRA_FLAGS: target_cpu="${{ matrix.target_cpu }}" target_os="openwrt" ${{ matrix.extra }} enable_shadow_metadata=false
OPENWRT_FLAGS: arch=${{ matrix.arch }} release=${{ matrix.openwrt_release || '18.06.0' }} gcc_ver=${{ matrix.openwrt_gcc_ver || '7.3.0' }} ${{ matrix.openwrt }} OPENWRT_FLAGS: arch=${{ matrix.arch }} release=${{ matrix.openwrt_release || '18.06.0' }} gcc_ver=${{ matrix.openwrt_gcc_ver || '7.3.0' }} ${{ matrix.openwrt }}
@ -522,7 +527,7 @@ jobs:
path: | path: |
src/third_party/llvm-build/Release+Asserts/ src/third_party/llvm-build/Release+Asserts/
src/gn/ src/gn/
src/qemu-user-static*.deb src/qemu-user*.deb
key: toolchains-posix-${{ hashFiles('CHROMIUM_VERSION') }}-v${{ env.CACHE_EPOCH }} key: toolchains-posix-${{ hashFiles('CHROMIUM_VERSION') }}-v${{ env.CACHE_EPOCH }}
- name: Cache PGO (Linux, OpenWrt) - name: Cache PGO (Linux, OpenWrt)
uses: actions/cache@v4 uses: actions/cache@v4
@ -547,13 +552,13 @@ jobs:
sudo apt update sudo apt update
sudo apt install ninja-build pkg-config ccache bubblewrap sudo apt install ninja-build pkg-config ccache bubblewrap
sudo apt remove -y qemu-user-binfmt sudo apt remove -y qemu-user-binfmt
sudo dpkg -i qemu-user-static*.deb sudo dpkg -i qemu-user*.deb
# libc6-i386 interferes with x86 build # libc6-i386 interferes with x86 build
sudo apt remove libc6-i386 sudo apt remove libc6-i386
- run: ./get-clang.sh - run: ./get-clang.sh
- run: ccache -z - run: ccache -z
- run: ./build.sh - run: ./build.sh
- run: ccache -s - run: ccache -s && ccache --evict-older-than 1d
- run: ../tests/basic.sh out/Release/naive - run: ../tests/basic.sh out/Release/naive
- name: Pack naiveproxy assets - name: Pack naiveproxy assets
run: | run: |

View file

@ -1 +1 @@
134.0.6998.39 135.0.7049.38

View file

@ -21,7 +21,7 @@ The Naïve server here works as a forward proxy and a packet length padding laye
## Download NaïveProxy ## Download NaïveProxy
Download [here](https://github.com/klzgrad/naiveproxy/releases/latest). Supported platforms include: Windows, Android (with [Exclave](https://github.com/dyhkwong/Exclave), [NekoBox](https://github.com/MatsuriDayo/NekoBoxForAndroid)), Linux, Mac OS, and OpenWrt ([support status](https://github.com/klzgrad/naiveproxy/wiki/OpenWrt-Support)). Download [here](https://github.com/klzgrad/naiveproxy/releases/latest). Supported platforms include: Windows, Android (with [Exclave](https://github.com/dyhkwong/Exclave), [husi](https://github.com/xchacha20-poly1305/husi), [NekoBox](https://github.com/MatsuriDayo/NekoBoxForAndroid)), Linux, Mac OS, and OpenWrt ([support status](https://github.com/klzgrad/naiveproxy/wiki/OpenWrt-Support)).
Users should always use the latest version to keep signatures identical to Chrome. Users should always use the latest version to keep signatures identical to Chrome.
@ -79,9 +79,7 @@ Or `quic://user:pass@example.com`, if it works better. See also [parameter usage
## Third-party integration ## Third-party integration
* [v2rayN](https://github.com/2dust/v2rayN), GUI client, Windows * [v2rayN](https://github.com/2dust/v2rayN), GUI client
* [NekoBox for Android](https://github.com/MatsuriDayo/NekoBoxForAndroid), Proxy toolchain, Android
* [NekoRay / NekoBox For PC](https://github.com/MatsuriDayo/nekoray), Qt based GUI, Windows, Linux
## Notes for downstream ## Notes for downstream

View file

@ -351,6 +351,7 @@ Dax Kelson <dkelson@gurulabs.com>
Dean Leitersdorf <dean.leitersdorf@gmail.com> Dean Leitersdorf <dean.leitersdorf@gmail.com>
Debadree Chatterjee <debadree333@gmail.com> Debadree Chatterjee <debadree333@gmail.com>
Debashish Samantaray <d.samantaray@samsung.com> Debashish Samantaray <d.samantaray@samsung.com>
Debin Zhang <debinzhang3@gmail.com>
Debug Wang <debugwang@tencent.com> Debug Wang <debugwang@tencent.com>
Deep Shah <deep.shah@samsung.com> Deep Shah <deep.shah@samsung.com>
Deepak Dilip Borade <deepak.db@samsung.com> Deepak Dilip Borade <deepak.db@samsung.com>
@ -1029,6 +1030,7 @@ Mohamed Mansour <m0.interactive@gmail.com>
Mohamed Hany Youns <mohamedhyouns@gmail.com> Mohamed Hany Youns <mohamedhyouns@gmail.com>
Mohammad Azam <m.azam@samsung.com> Mohammad Azam <m.azam@samsung.com>
MohammadSabri <mohammad.kh.sabri@exalt.ps> MohammadSabri <mohammad.kh.sabri@exalt.ps>
Mohammed Ashraf <mohammedashraf4599@gmail.com>
Mohammed Wajahat Ali Siddiqui <wajahat.s@samsung.com> Mohammed Wajahat Ali Siddiqui <wajahat.s@samsung.com>
Mohan Reddy <mohan.reddy@samsung.com> Mohan Reddy <mohan.reddy@samsung.com>
Mohit Bhalla <bhallam@amazon.com> Mohit Bhalla <bhallam@amazon.com>
@ -1310,6 +1312,7 @@ Serhii Matrunchyk <sergiy.matrunchyk@gmail.com>
Seshadri Mahalingam <seshadri.mahalingam@gmail.com> Seshadri Mahalingam <seshadri.mahalingam@gmail.com>
Seungkyu Lee <zx6658@gmail.com> Seungkyu Lee <zx6658@gmail.com>
Sevan Janiyan <venture37@geeklan.co.uk> Sevan Janiyan <venture37@geeklan.co.uk>
Shaheen Fazim <fazim.pentester@gmail.com>
Shahriar Rostami <shahriar.rostami@gmail.com> Shahriar Rostami <shahriar.rostami@gmail.com>
Shail Singhal <shail.s@samsung.com> Shail Singhal <shail.s@samsung.com>
Shane Hansen <shanemhansen@gmail.com> Shane Hansen <shanemhansen@gmail.com>

526
src/DEPS

File diff suppressed because it is too large Load diff

View file

@ -25,7 +25,6 @@ import("//build/buildflag_header.gni")
import("//build/config/arm.gni") import("//build/config/arm.gni")
import("//build/config/c++/c++.gni") import("//build/config/c++/c++.gni")
import("//build/config/cast.gni") import("//build/config/cast.gni")
import("//build/config/chromeos/ui_mode.gni")
import("//build/config/compiler/compiler.gni") import("//build/config/compiler/compiler.gni")
import("//build/config/cronet/config.gni") import("//build/config/cronet/config.gni")
import("//build/config/dcheck_always_on.gni") import("//build/config/dcheck_always_on.gni")
@ -41,7 +40,7 @@ import("//build/util/process_version.gni")
import("//build_overrides/build.gni") import("//build_overrides/build.gni")
if (is_ios) { if (is_ios) {
# Used to access target_environment. # Used to access target_environment and target_platform.
import("//build/config/apple/mobile_config.gni") import("//build/config/apple/mobile_config.gni")
# Used to access ios_is_app_extension variable definition. # Used to access ios_is_app_extension variable definition.
@ -244,8 +243,6 @@ component("base") {
"containers/unique_ptr_adapters.h", "containers/unique_ptr_adapters.h",
"containers/util.h", "containers/util.h",
"containers/vector_buffer.h", "containers/vector_buffer.h",
"cpu_reduction_experiment.cc",
"cpu_reduction_experiment.h",
"critical_closure.h", "critical_closure.h",
"dcheck_is_on.h", "dcheck_is_on.h",
"debug/alias.cc", "debug/alias.cc",
@ -561,6 +558,8 @@ component("base") {
"run_loop.h", "run_loop.h",
"sampling_heap_profiler/lock_free_address_hash_set.cc", "sampling_heap_profiler/lock_free_address_hash_set.cc",
"sampling_heap_profiler/lock_free_address_hash_set.h", "sampling_heap_profiler/lock_free_address_hash_set.h",
"sampling_heap_profiler/lock_free_bloom_filter.cc",
"sampling_heap_profiler/lock_free_bloom_filter.h",
"sampling_heap_profiler/poisson_allocation_sampler.cc", "sampling_heap_profiler/poisson_allocation_sampler.cc",
"sampling_heap_profiler/poisson_allocation_sampler.h", "sampling_heap_profiler/poisson_allocation_sampler.h",
"sampling_heap_profiler/sampling_heap_profiler.cc", "sampling_heap_profiler/sampling_heap_profiler.cc",
@ -585,6 +584,7 @@ component("base") {
"strings/abseil_string_number_conversions.cc", "strings/abseil_string_number_conversions.cc",
"strings/abseil_string_number_conversions.h", "strings/abseil_string_number_conversions.h",
"strings/cstring_view.h", "strings/cstring_view.h",
"strings/durable_string_view.h",
"strings/escape.cc", "strings/escape.cc",
"strings/escape.h", "strings/escape.h",
"strings/latin1_string_conversions.cc", "strings/latin1_string_conversions.cc",
@ -868,6 +868,8 @@ component("base") {
"trace_event/heap_profiler_allocation_context.h", "trace_event/heap_profiler_allocation_context.h",
"trace_event/heap_profiler_allocation_context_tracker.cc", "trace_event/heap_profiler_allocation_context_tracker.cc",
"trace_event/heap_profiler_allocation_context_tracker.h", "trace_event/heap_profiler_allocation_context_tracker.h",
"trace_event/histogram_scope.cc",
"trace_event/histogram_scope.h",
"trace_event/memory_allocator_dump_guid.cc", "trace_event/memory_allocator_dump_guid.cc",
"trace_event/memory_allocator_dump_guid.h", "trace_event/memory_allocator_dump_guid.h",
"trace_event/named_trigger.cc", "trace_event/named_trigger.cc",
@ -894,6 +896,7 @@ component("base") {
"types/same_as_any.h", "types/same_as_any.h",
"types/strong_alias.h", "types/strong_alias.h",
"types/supports_ostream_operator.h", "types/supports_ostream_operator.h",
"types/supports_to_string.h",
"types/to_address.h", "types/to_address.h",
"types/token_type.h", "types/token_type.h",
"types/variant_util.h", "types/variant_util.h",
@ -1059,10 +1062,13 @@ component("base") {
"//base/numerics:base_numerics", "//base/numerics:base_numerics",
"//base/third_party/icu", "//base/third_party/icu",
"//build:chromecast_buildflags", "//build:chromecast_buildflags",
"//build:chromeos_buildflags",
"//third_party/abseil-cpp:absl", "//third_party/abseil-cpp:absl",
] ]
# TODO(crbug.com/354842935): Remove this dependency once other modules don't
# accidentally (transitively) depend on it anymore.
public_deps += [ "//build:chromeos_buildflags" ]
# Needed for <atomic> if using newer C++ library than sysroot, except if # Needed for <atomic> if using newer C++ library than sysroot, except if
# building inside the cros_sdk environment - use host_toolchain as a # building inside the cros_sdk environment - use host_toolchain as a
# more robust check for this. # more robust check for this.
@ -1182,7 +1188,6 @@ component("base") {
if (is_robolectric) { if (is_robolectric) {
# Make jni.h available. # Make jni.h available.
configs += [ "//third_party/jdk" ] configs += [ "//third_party/jdk" ]
deps += [ ":base_robolectric_jni" ]
} }
if (is_robolectric) { if (is_robolectric) {
sources += [ sources += [
@ -1191,6 +1196,8 @@ component("base") {
"android/callback_android.cc", "android/callback_android.cc",
"android/callback_android.h", "android/callback_android.h",
"android/command_line_android.cc", "android/command_line_android.cc",
"android/int_string_callback.cc",
"android/int_string_callback.h",
"android/java_exception_reporter.cc", "android/java_exception_reporter.cc",
"android/java_exception_reporter.h", "android/java_exception_reporter.h",
"android/jni_android.cc", "android/jni_android.cc",
@ -1208,8 +1215,13 @@ component("base") {
"android/jni_utils.cc", "android/jni_utils.cc",
"android/jni_utils.h", "android/jni_utils.h",
"android/jni_weak_ref.h", "android/jni_weak_ref.h",
"android/library_loader/anchor_functions.cc",
"android/library_loader/anchor_functions.h",
"android/library_loader/library_loader_hooks.cc", "android/library_loader/library_loader_hooks.cc",
"android/library_loader/library_loader_hooks.h", "android/library_loader/library_loader_hooks.h",
"android/library_loader/library_prefetcher.cc",
"android/library_loader/library_prefetcher.h",
"android/library_loader/library_prefetcher_hooks.cc",
"android/native_uma_recorder.cc", "android/native_uma_recorder.cc",
"android/scoped_java_ref.h", "android/scoped_java_ref.h",
"android/token_android.cc", "android/token_android.cc",
@ -1882,8 +1894,8 @@ component("base") {
"apple/call_with_eh_frame.cc", "apple/call_with_eh_frame.cc",
"apple/call_with_eh_frame.h", "apple/call_with_eh_frame.h",
"apple/call_with_eh_frame_asm.S", "apple/call_with_eh_frame_asm.S",
"apple/dispatch_source_mach.cc", "apple/dispatch_source.cc",
"apple/dispatch_source_mach.h", "apple/dispatch_source.h",
"apple/foundation_util.h", "apple/foundation_util.h",
"apple/foundation_util.mm", "apple/foundation_util.mm",
"apple/mach_logging.cc", "apple/mach_logging.cc",
@ -1914,10 +1926,9 @@ component("base") {
"message_loop/message_pump_apple.h", "message_loop/message_pump_apple.h",
"message_loop/message_pump_apple.mm", "message_loop/message_pump_apple.mm",
"native_library_apple.mm", "native_library_apple.mm",
"process/process_metrics_apple.cc", "process/process_metrics_apple.mm",
"profiler/module_cache_apple.cc", "profiler/module_cache_apple.cc",
"strings/sys_string_conversions_apple.mm", "strings/sys_string_conversions_apple.mm",
"synchronization/waitable_event_apple.cc",
"system/sys_info_apple.mm", "system/sys_info_apple.mm",
"threading/platform_thread_apple.mm", "threading/platform_thread_apple.mm",
"time/time_apple.mm", "time/time_apple.mm",
@ -1929,6 +1940,10 @@ component("base") {
"Foundation.framework", "Foundation.framework",
"Security.framework", "Security.framework",
] ]
if (!is_ios || !use_blink) {
sources += [ "synchronization/waitable_event_apple.cc" ]
}
} }
# Desktop Mac. # Desktop Mac.
@ -2065,12 +2080,20 @@ component("base") {
"process/process_handle_mac.cc", "process/process_handle_mac.cc",
"process/process_ios.cc", "process/process_ios.cc",
"process/process_iterator_mac.cc", "process/process_iterator_mac.cc",
"process/process_mac.cc",
"process/process_posix.cc", "process/process_posix.cc",
"sync_socket_posix.cc", "sync_socket_posix.cc",
"synchronization/waitable_event_watcher_mac.cc", "synchronization/waitable_event_posix.cc",
"synchronization/waitable_event_watcher_posix.cc",
] ]
if (target_platform == "tvos") {
# tvOS apps must be single-process. Build a Process version that does
# the bare minimum and does not use Mach ports.
sources += [ "process/process_tvos.cc" ]
} else {
sources += [ "process/process_mac.cc" ]
}
# We include launch_mac on simulator builds so unittests can fork. # We include launch_mac on simulator builds so unittests can fork.
if (target_environment == "simulator") { if (target_environment == "simulator") {
sources += [ sources += [
@ -2093,6 +2116,11 @@ component("base") {
"message_loop/message_pump_io_ios.cc", "message_loop/message_pump_io_ios.cc",
"message_loop/message_pump_io_ios.h", "message_loop/message_pump_io_ios.h",
] ]
} else if (use_blink) {
sources += [
"message_loop/message_pump_io_ios_libdispatch.cc",
"message_loop/message_pump_io_ios_libdispatch.h",
]
} else { } else {
sources += [ sources += [
"message_loop/message_pump_kqueue.cc", "message_loop/message_pump_kqueue.cc",
@ -2248,7 +2276,6 @@ component("base") {
if (enable_base_tracing) { if (enable_base_tracing) {
sources += [ sources += [
"trace_event/auto_open_close_event.h", "trace_event/auto_open_close_event.h",
"trace_event/builtin_categories.cc",
"trace_event/builtin_categories.h", "trace_event/builtin_categories.h",
"trace_event/heap_profiler.h", "trace_event/heap_profiler.h",
"trace_event/interned_args_helper.cc", "trace_event/interned_args_helper.cc",
@ -2451,7 +2478,7 @@ buildflag_header("debugging_buildflags") {
buildflag_header("feature_list_buildflags") { buildflag_header("feature_list_buildflags") {
header = "feature_list_buildflags.h" header = "feature_list_buildflags.h"
if (is_chromeos_ash) { if (is_chromeos) {
flags = [ flags = [
"ENABLE_BANNED_BASE_FEATURE_PREFIX=true", "ENABLE_BANNED_BASE_FEATURE_PREFIX=true",
"BANNED_BASE_FEATURE_PREFIX=\"CrOSLateBoot\"", "BANNED_BASE_FEATURE_PREFIX=\"CrOSLateBoot\"",
@ -2573,10 +2600,7 @@ static_library("base_static") {
"immediate_crash.h", "immediate_crash.h",
] ]
deps = [ deps = [ ":fuzzing_buildflags" ]
":fuzzing_buildflags",
"//build:chromeos_buildflags",
]
if (is_win) { if (is_win) {
sources += [ sources += [

View file

@ -12,7 +12,6 @@
#include "base/time/time.h" #include "base/time/time.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "build/chromecast_buildflags.h" #include "build/chromecast_buildflags.h"
#include "build/chromeos_buildflags.h"
#include "partition_alloc/buildflags.h" #include "partition_alloc/buildflags.h"
#include "partition_alloc/partition_alloc_base/time/time.h" #include "partition_alloc/partition_alloc_base/time/time.h"
#include "partition_alloc/partition_alloc_constants.h" #include "partition_alloc/partition_alloc_constants.h"
@ -274,16 +273,15 @@ BASE_FEATURE(kPartitionAllocPermissiveMte,
#endif #endif
); );
// Note: Do not use the prepared macro to implement following FeatureParams BASE_FEATURE(kAsanBrpDereferenceCheck,
// as of no need for a local cache. "AsanBrpDereferenceCheck",
constinit const FeatureParam<bool> kBackupRefPtrAsanEnableDereferenceCheckParam{ FEATURE_ENABLED_BY_DEFAULT);
&kPartitionAllocBackupRefPtr, "asan-enable-dereference-check", true}; BASE_FEATURE(kAsanBrpExtractionCheck,
constinit const FeatureParam<bool> kBackupRefPtrAsanEnableExtractionCheckParam{ "AsanBrpExtractionCheck", // Not much noise at the moment to
&kPartitionAllocBackupRefPtr, "asan-enable-extraction-check", FEATURE_DISABLED_BY_DEFAULT); // enable by default.
false}; // Not much noise at the moment to enable by default. BASE_FEATURE(kAsanBrpInstantiationCheck,
constinit const FeatureParam<bool> "AsanBrpInstantiationCheck",
kBackupRefPtrAsanEnableInstantiationCheckParam{ FEATURE_ENABLED_BY_DEFAULT);
&kPartitionAllocBackupRefPtr, "asan-enable-instantiation-check", true};
// If enabled, switches the bucket distribution to a denser one. // If enabled, switches the bucket distribution to a denser one.
// //
@ -468,12 +466,6 @@ BASE_FEATURE(kPartitionAllocDisableBRPInBufferPartition,
"PartitionAllocDisableBRPInBufferPartition", "PartitionAllocDisableBRPInBufferPartition",
FEATURE_DISABLED_BY_DEFAULT); FEATURE_DISABLED_BY_DEFAULT);
#if PA_BUILDFLAG(USE_FREELIST_DISPATCHER)
BASE_FEATURE(kUsePoolOffsetFreelists,
"PartitionAllocUsePoolOffsetFreelists",
FEATURE_ENABLED_BY_DEFAULT);
#endif
BASE_FEATURE(kPartitionAllocAdjustSizeWhenInForeground, BASE_FEATURE(kPartitionAllocAdjustSizeWhenInForeground,
"PartitionAllocAdjustSizeWhenInForeground", "PartitionAllocAdjustSizeWhenInForeground",
#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) #if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)

View file

@ -162,15 +162,9 @@ BASE_EXPORT BASE_DECLARE_FEATURE_PARAM(MemoryTaggingEnabledProcesses,
// enabled. // enabled.
BASE_EXPORT BASE_DECLARE_FEATURE(kKillPartitionAllocMemoryTagging); BASE_EXPORT BASE_DECLARE_FEATURE(kKillPartitionAllocMemoryTagging);
BASE_EXPORT BASE_DECLARE_FEATURE(kPartitionAllocPermissiveMte); BASE_EXPORT BASE_DECLARE_FEATURE(kPartitionAllocPermissiveMte);
BASE_EXPORT BASE_DECLARE_FEATURE_PARAM( BASE_EXPORT BASE_DECLARE_FEATURE(kAsanBrpDereferenceCheck);
bool, BASE_EXPORT BASE_DECLARE_FEATURE(kAsanBrpExtractionCheck);
kBackupRefPtrAsanEnableDereferenceCheckParam); BASE_EXPORT BASE_DECLARE_FEATURE(kAsanBrpInstantiationCheck);
BASE_EXPORT BASE_DECLARE_FEATURE_PARAM(
bool,
kBackupRefPtrAsanEnableExtractionCheckParam);
BASE_EXPORT BASE_DECLARE_FEATURE_PARAM(
bool,
kBackupRefPtrAsanEnableInstantiationCheckParam);
BASE_EXPORT BASE_DECLARE_FEATURE_PARAM(BucketDistributionMode, BASE_EXPORT BASE_DECLARE_FEATURE_PARAM(BucketDistributionMode,
kPartitionAllocBucketDistributionParam); kPartitionAllocBucketDistributionParam);
@ -216,13 +210,6 @@ BASE_EXPORT int GetThreadCacheMinCachedMemoryForPurgingBytes();
BASE_EXPORT BASE_DECLARE_FEATURE(kPartitionAllocDisableBRPInBufferPartition); BASE_EXPORT BASE_DECLARE_FEATURE(kPartitionAllocDisableBRPInBufferPartition);
// This feature is additionally gated behind a buildflag because
// pool offset freelists cannot be represented when PartitionAlloc uses
// 32-bit pointers.
#if PA_BUILDFLAG(USE_FREELIST_DISPATCHER)
BASE_EXPORT BASE_DECLARE_FEATURE(kUsePoolOffsetFreelists);
#endif
// When set, partitions use a larger ring buffer and free memory less // When set, partitions use a larger ring buffer and free memory less
// aggressively when in the foreground. // aggressively when in the foreground.
BASE_EXPORT BASE_DECLARE_FEATURE(kPartitionAllocAdjustSizeWhenInForeground); BASE_EXPORT BASE_DECLARE_FEATURE(kPartitionAllocAdjustSizeWhenInForeground);

View file

@ -107,12 +107,9 @@ BootloaderOverride GetBootloaderOverride() {
} }
#endif #endif
// When under this experiment avoid running periodic purging or reclaim for the // Avoid running periodic purging or reclaim for the first minute after the
// first minute after the first attempt. This is based on the insight that // first attempt. This is based on the insight that processes often don't live
// processes often don't live paste this minute. // paste this minute.
static BASE_FEATURE(kDelayFirstPeriodicPAPurgeOrReclaim,
"DelayFirstPeriodicPAPurgeOrReclaim",
base::FEATURE_ENABLED_BY_DEFAULT);
constexpr base::TimeDelta kFirstPAPurgeOrReclaimDelay = base::Minutes(1); constexpr base::TimeDelta kFirstPAPurgeOrReclaimDelay = base::Minutes(1);
// This is defined in content/public/common/content_switches.h, which is not // This is defined in content/public/common/content_switches.h, which is not
@ -171,6 +168,8 @@ void MemoryReclaimerSupport::Start(scoped_refptr<TaskRunner> task_runner) {
return; return;
} }
task_runner_ = task_runner;
// The caller of the API fully controls where running the reclaim. // The caller of the API fully controls where running the reclaim.
// However there are a few reasons to recommend that the caller runs // However there are a few reasons to recommend that the caller runs
// it on the main thread: // it on the main thread:
@ -186,13 +185,7 @@ void MemoryReclaimerSupport::Start(scoped_refptr<TaskRunner> task_runner) {
// seconds is useful. Since this is meant to run during idle time only, it is // seconds is useful. Since this is meant to run during idle time only, it is
// a reasonable starting point balancing effectivenes vs cost. See // a reasonable starting point balancing effectivenes vs cost. See
// crbug.com/942512 for details and experimental results. // crbug.com/942512 for details and experimental results.
TimeDelta delay; MaybeScheduleTask(kFirstPAPurgeOrReclaimDelay);
if (base::FeatureList::IsEnabled(kDelayFirstPeriodicPAPurgeOrReclaim)) {
delay = std::max(delay, kFirstPAPurgeOrReclaimDelay);
}
task_runner_ = task_runner;
MaybeScheduleTask(delay);
} }
void MemoryReclaimerSupport::SetForegrounded(bool in_foreground) { void MemoryReclaimerSupport::SetForegrounded(bool in_foreground) {
@ -253,12 +246,9 @@ void MemoryReclaimerSupport::MaybeScheduleTask(TimeDelta delay) {
void StartThreadCachePeriodicPurge() { void StartThreadCachePeriodicPurge() {
auto& instance = ::partition_alloc::ThreadCacheRegistry::Instance(); auto& instance = ::partition_alloc::ThreadCacheRegistry::Instance();
TimeDelta delay = TimeDelta delay = std::max(
Microseconds(instance.GetPeriodicPurgeNextIntervalInMicroseconds()); Microseconds(instance.GetPeriodicPurgeNextIntervalInMicroseconds()),
kFirstPAPurgeOrReclaimDelay);
if (base::FeatureList::IsEnabled(kDelayFirstPeriodicPAPurgeOrReclaim)) {
delay = std::max(delay, kFirstPAPurgeOrReclaimDelay);
}
SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask( SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
FROM_HERE, BindOnce(RunThreadCachePeriodicPurge), delay); FROM_HERE, BindOnce(RunThreadCachePeriodicPurge), delay);
@ -1013,18 +1003,17 @@ void PartitionAllocSupport::ReconfigureAfterFeatureListInit(
if (ShouldEnableFeatureOnProcess( if (ShouldEnableFeatureOnProcess(
base::features::kBackupRefPtrEnabledProcessesParam.Get(), base::features::kBackupRefPtrEnabledProcessesParam.Get(),
process_type)) { process_type)) {
base::RawPtrAsanService::GetInstance().Configure( RawPtrAsanService::GetInstance().Configure(
base::EnableDereferenceCheck( EnableDereferenceCheck(
base::features::kBackupRefPtrAsanEnableDereferenceCheckParam.Get()), FeatureList::IsEnabled(features::kAsanBrpDereferenceCheck)),
base::EnableExtractionCheck( EnableExtractionCheck(
base::features::kBackupRefPtrAsanEnableExtractionCheckParam.Get()), FeatureList::IsEnabled(features::kAsanBrpExtractionCheck)),
base::EnableInstantiationCheck( EnableInstantiationCheck(
base::features::kBackupRefPtrAsanEnableInstantiationCheckParam FeatureList::IsEnabled(features::kAsanBrpInstantiationCheck)));
.Get()));
} else { } else {
base::RawPtrAsanService::GetInstance().Configure( RawPtrAsanService::GetInstance().Configure(EnableDereferenceCheck(false),
base::EnableDereferenceCheck(false), base::EnableExtractionCheck(false), EnableExtractionCheck(false),
base::EnableInstantiationCheck(false)); EnableInstantiationCheck(false));
} }
#endif // PA_BUILDFLAG(USE_ASAN_BACKUP_REF_PTR) #endif // PA_BUILDFLAG(USE_ASAN_BACKUP_REF_PTR)
@ -1054,13 +1043,6 @@ void PartitionAllocSupport::ReconfigureAfterFeatureListInit(
const bool fewer_memory_regions = base::FeatureList::IsEnabled( const bool fewer_memory_regions = base::FeatureList::IsEnabled(
base::features::kPartitionAllocFewerMemoryRegions); base::features::kPartitionAllocFewerMemoryRegions);
#if PA_BUILDFLAG(USE_FREELIST_DISPATCHER)
const bool use_pool_offset_freelists =
base::FeatureList::IsEnabled(base::features::kUsePoolOffsetFreelists);
#else
const bool use_pool_offset_freelists = false;
#endif // PA_BUILDFLAG(USE_FREELIST_DISPATCHER)
bool enable_memory_tagging = false; bool enable_memory_tagging = false;
partition_alloc::TagViolationReportingMode memory_tagging_reporting_mode = partition_alloc::TagViolationReportingMode memory_tagging_reporting_mode =
partition_alloc::TagViolationReportingMode::kUndefined; partition_alloc::TagViolationReportingMode::kUndefined;
@ -1163,7 +1145,6 @@ void PartitionAllocSupport::ReconfigureAfterFeatureListInit(
allocator_shim::ZappingByFreeFlags(zapping_by_free_flags), allocator_shim::ZappingByFreeFlags(zapping_by_free_flags),
allocator_shim::EventuallyZeroFreedMemory(eventually_zero_freed_memory), allocator_shim::EventuallyZeroFreedMemory(eventually_zero_freed_memory),
allocator_shim::FewerMemoryRegions(fewer_memory_regions), allocator_shim::FewerMemoryRegions(fewer_memory_regions),
allocator_shim::UsePoolOffsetFreelists(use_pool_offset_freelists),
use_small_single_slot_spans); use_small_single_slot_spans);
const uint32_t extras_size = allocator_shim::GetMainPartitionRootExtrasSize(); const uint32_t extras_size = allocator_shim::GetMainPartitionRootExtrasSize();
@ -1173,12 +1154,8 @@ void PartitionAllocSupport::ReconfigureAfterFeatureListInit(
UmaHistogramCounts100("Memory.PartitionAlloc.PartitionRoot.ExtrasSize", UmaHistogramCounts100("Memory.PartitionAlloc.PartitionRoot.ExtrasSize",
int(extras_size)); int(extras_size));
#if !defined(__MUSL__)
// This call causes hanging in pthread_getattr_np() under qemu-user, see
// https://www.openwall.com/lists/musl/2017/06/15/9.
partition_alloc::internal::StackTopRegistry::Get().NotifyThreadCreated( partition_alloc::internal::StackTopRegistry::Get().NotifyThreadCreated(
partition_alloc::internal::GetStackTop()); partition_alloc::internal::GetStackTop());
#endif
allocator_shim::internal::PartitionAllocMalloc::Allocator() allocator_shim::internal::PartitionAllocMalloc::Allocator()
->EnableThreadCacheIfSupported(); ->EnableThreadCacheIfSupported();

View file

@ -52,7 +52,6 @@ is_nacl = false
is_win = current_os == "win" || current_os == "winuwp" is_win = current_os == "win" || current_os == "winuwp"
is_cast_android = false is_cast_android = false
is_castos = false is_castos = false
is_chromeos_ash = false
is_cronet_build = false is_cronet_build = false
enable_expensive_dchecks = false enable_expensive_dchecks = false
dcheck_is_configurable = false dcheck_is_configurable = false

View file

@ -123,12 +123,34 @@ source_set("buildflag_macro") {
public_configs = [ ":public_includes" ] public_configs = [ ":public_includes" ]
} }
# When developers are repeatedly growing a buffer with `realloc`, they are
# expected to request a new size that is larger than the current size by
# some growth factor. This growth factor allows to amortize the cost of
# memcpy. Unfortunately, some nVidia drivers have a bug where they repeatedly
# increase the buffer by 4144 byte only.
#
# In particular, most Skia Linux bots are using the affected nVidia driver. So
# this flag is used as a workaround for Skia standalone, not in production.
#
# External link:
# https://forums.developer.nvidia.com/t/550-54-14-very-bad-performance-due-to-bunch-of-reallocations-during-glcore-initialization/287027
#
# Internal discussion at @chrome-memory-safety:
# https://groups.google.com/a/google.com/d/msgid/chrome-memory-safety/CAAzos5HrexY2njz2YzWrffTq1xEfkx15GVpSvHUyQED6wBSXvA%40mail.gmail.com?utm_medium=email&utm_source=footer
declare_args() {
partition_alloc_realloc_growth_factor_mitigation = false
}
pa_buildflag_header("buildflags") { pa_buildflag_header("buildflags") {
header = "buildflags.h" header = "buildflags.h"
flags = [ flags = [
"ASSERT_CPP_20=$assert_cpp20", "ASSERT_CPP_20=$assert_cpp20",
"BACKUP_REF_PTR_EXTRA_OOB_CHECKS=$backup_ref_ptr_extra_oob_checks", "BACKUP_REF_PTR_EXTRA_OOB_CHECKS=$backup_ref_ptr_extra_oob_checks",
"BACKUP_REF_PTR_POISON_OOB_PTR=$backup_ref_ptr_poison_oob_ptr", "BACKUP_REF_PTR_POISON_OOB_PTR=$backup_ref_ptr_poison_oob_ptr",
"CAN_UNWIND_WITH_FRAME_POINTERS=$can_unwind_with_frame_pointers",
"DCHECKS_ARE_ON=$partition_alloc_dchecks_are_on",
"DCHECK_IS_CONFIGURABLE=$dcheck_is_configurable",
"ENABLE_ALLOCATOR_SHIM_PARTITION_ALLOC_DISPATCH_WITH_ADVANCED_CHECKS_SUPPORT=$enable_allocator_shim_partition_alloc_dispatch_with_advanced_checks_support",
"ENABLE_BACKUP_REF_PTR_FEATURE_FLAG=$enable_backup_ref_ptr_feature_flag", "ENABLE_BACKUP_REF_PTR_FEATURE_FLAG=$enable_backup_ref_ptr_feature_flag",
"ENABLE_BACKUP_REF_PTR_INSTANCE_TRACER=$enable_backup_ref_ptr_instance_tracer", "ENABLE_BACKUP_REF_PTR_INSTANCE_TRACER=$enable_backup_ref_ptr_instance_tracer",
"ENABLE_BACKUP_REF_PTR_SLOW_CHECKS=$enable_backup_ref_ptr_slow_checks", "ENABLE_BACKUP_REF_PTR_SLOW_CHECKS=$enable_backup_ref_ptr_slow_checks",
@ -143,6 +165,7 @@ pa_buildflag_header("buildflags") {
"ENABLE_POINTER_SUBTRACTION_CHECK=$enable_pointer_subtraction_check", "ENABLE_POINTER_SUBTRACTION_CHECK=$enable_pointer_subtraction_check",
"ENABLE_SHADOW_METADATA_FOR_64_BITS_POINTERS=$enable_shadow_metadata", "ENABLE_SHADOW_METADATA_FOR_64_BITS_POINTERS=$enable_shadow_metadata",
"ENABLE_THREAD_ISOLATION=$enable_pkeys", "ENABLE_THREAD_ISOLATION=$enable_pkeys",
"EXPENSIVE_DCHECKS_ARE_ON=$enable_expensive_dchecks",
"FORCE_DISABLE_BACKUP_REF_PTR_FEATURE=$force_disable_backup_ref_ptr_feature", "FORCE_DISABLE_BACKUP_REF_PTR_FEATURE=$force_disable_backup_ref_ptr_feature",
"FORCE_ENABLE_RAW_PTR_EXCLUSION=$force_enable_raw_ptr_exclusion", "FORCE_ENABLE_RAW_PTR_EXCLUSION=$force_enable_raw_ptr_exclusion",
"FORWARD_THROUGH_MALLOC=$forward_through_malloc", "FORWARD_THROUGH_MALLOC=$forward_through_malloc",
@ -156,6 +179,7 @@ pa_buildflag_header("buildflags") {
"RAW_PTR_ZERO_ON_CONSTRUCT=$raw_ptr_zero_on_construct", "RAW_PTR_ZERO_ON_CONSTRUCT=$raw_ptr_zero_on_construct",
"RAW_PTR_ZERO_ON_DESTRUCT=$raw_ptr_zero_on_destruct", "RAW_PTR_ZERO_ON_DESTRUCT=$raw_ptr_zero_on_destruct",
"RAW_PTR_ZERO_ON_MOVE=$raw_ptr_zero_on_move", "RAW_PTR_ZERO_ON_MOVE=$raw_ptr_zero_on_move",
"REALLOC_GROWTH_FACTOR_MITIGATION=$partition_alloc_realloc_growth_factor_mitigation",
"RECORD_ALLOC_INFO=$record_alloc_info", "RECORD_ALLOC_INFO=$record_alloc_info",
"SMALLER_PARTITION_COOKIE=$smaller_partition_cookie", "SMALLER_PARTITION_COOKIE=$smaller_partition_cookie",
"STACK_SCAN_SUPPORTED=$stack_scan_supported", "STACK_SCAN_SUPPORTED=$stack_scan_supported",
@ -171,11 +195,6 @@ pa_buildflag_header("buildflags") {
"USE_RAW_PTR_ASAN_UNOWNED_IMPL=$use_raw_ptr_asan_unowned_impl", "USE_RAW_PTR_ASAN_UNOWNED_IMPL=$use_raw_ptr_asan_unowned_impl",
"USE_RAW_PTR_BACKUP_REF_IMPL=$use_raw_ptr_backup_ref_impl", "USE_RAW_PTR_BACKUP_REF_IMPL=$use_raw_ptr_backup_ref_impl",
"USE_RAW_PTR_HOOKABLE_IMPL=$use_raw_ptr_hookable_impl", "USE_RAW_PTR_HOOKABLE_IMPL=$use_raw_ptr_hookable_impl",
"ENABLE_ALLOCATOR_SHIM_PARTITION_ALLOC_DISPATCH_WITH_ADVANCED_CHECKS_SUPPORT=$enable_allocator_shim_partition_alloc_dispatch_with_advanced_checks_support",
"DCHECKS_ARE_ON=$partition_alloc_dchecks_are_on",
"EXPENSIVE_DCHECKS_ARE_ON=$enable_expensive_dchecks",
"DCHECK_IS_CONFIGURABLE=$dcheck_is_configurable",
"CAN_UNWIND_WITH_FRAME_POINTERS=$can_unwind_with_frame_pointers",
] ]
} }

View file

@ -200,14 +200,7 @@ bool UseMapJit() {
} }
#elif PA_BUILDFLAG(IS_IOS) #elif PA_BUILDFLAG(IS_IOS)
bool UseMapJit() { bool UseMapJit() {
// Always enable MAP_JIT in simulator as it is supported unconditionally.
#if TARGET_IPHONE_SIMULATOR
return true; return true;
#else
// TODO(crbug.com/40255826): Fill this out when the API it is
// available.
return false;
#endif // TARGET_IPHONE_SIMULATOR
} }
#endif // PA_BUILDFLAG(IS_IOS) #endif // PA_BUILDFLAG(IS_IOS)

View file

@ -83,6 +83,13 @@ uintptr_t SystemAllocPagesInternal(uintptr_t hint,
PageAccessibilityConfiguration::kInaccessibleWillJitLater && PageAccessibilityConfiguration::kInaccessibleWillJitLater &&
kUseMapJit) { kUseMapJit) {
map_flags |= MAP_JIT; map_flags |= MAP_JIT;
// iOS devices do not support toggling the page permissions after a MAP_JIT
// call, they must be set initially. iOS has per-thread W^X state that
// takes precedence over the mapping's permissions for MAP_JIT regions.
// See https://developer.apple.com/forums/thread/672804
#if PA_BUILDFLAG(IS_IOS)
access_flag = PROT_READ | PROT_WRITE | PROT_EXEC;
#endif
} }
#endif #endif

View file

@ -65,7 +65,7 @@ PA_ALWAYS_INLINE void DebugMemset(void* ptr, int value, size_t size) {
// faster. Note that for direct-mapped allocations, memory is decomitted at // faster. Note that for direct-mapped allocations, memory is decomitted at
// free() time, so freed memory usage cannot happen. // free() time, so freed memory usage cannot happen.
#if PA_BUILDFLAG(ENABLE_THREAD_ISOLATION) #if PA_BUILDFLAG(ENABLE_THREAD_ISOLATION) && PA_BUILDFLAG(ENABLE_PKEYS)
LiftThreadIsolationScope lift_thread_isolation_restrictions; LiftThreadIsolationScope lift_thread_isolation_restrictions;
#endif #endif
size_t size_to_memset = std::min(size, size_t{1} << 19); size_t size_to_memset = std::min(size, size_t{1} << 19);

View file

@ -7,13 +7,8 @@
#include <cstddef> #include <cstddef>
#include "partition_alloc/build_config.h"
#include "partition_alloc/partition_alloc_base/component_export.h" #include "partition_alloc/partition_alloc_base/component_export.h"
#if !PA_BUILDFLAG(IS_WIN)
#include <unistd.h>
#endif
namespace partition_alloc::internal::base::strings { namespace partition_alloc::internal::base::strings {
// Similar to std::ostringstream, but creates a C string, i.e. nul-terminated // Similar to std::ostringstream, but creates a C string, i.e. nul-terminated

View file

@ -2478,7 +2478,7 @@ void* PartitionRoot::ReallocInline(void* ptr,
constexpr bool no_hooks = ContainsFlags(alloc_flags, AllocFlags::kNoHooks); constexpr bool no_hooks = ContainsFlags(alloc_flags, AllocFlags::kNoHooks);
const bool hooks_enabled = PartitionAllocHooks::AreHooksEnabled(); const bool hooks_enabled = PartitionAllocHooks::AreHooksEnabled();
bool overridden = false; bool overridden = false;
size_t old_usable_size; size_t old_usable_size = 0;
if (!no_hooks && hooks_enabled) [[unlikely]] { if (!no_hooks && hooks_enabled) [[unlikely]] {
overridden = PartitionAllocHooks::ReallocOverrideHookIfEnabled( overridden = PartitionAllocHooks::ReallocOverrideHookIfEnabled(
&old_usable_size, ptr); &old_usable_size, ptr);
@ -2521,6 +2521,21 @@ void* PartitionRoot::ReallocInline(void* ptr,
} }
} }
#if PA_BUILDFLAG(REALLOC_GROWTH_FACTOR_MITIGATION)
// Some nVidia drivers have a performance bug where they repeatedly realloc a
// buffer with a small 4144 byte increment instead of using a growth factor to
// amortize the cost of a memcpy. To work around this, we apply a growth
// factor to the new size to avoid this issue. This workaround is only
// intended to be used for Skia bots, and is not intended to be a general
// solution.
if (new_size > old_usable_size && new_size > 12 << 20) {
// 1.5x growth factor.
// Note that in case of integer overflow, the std::max ensures that the
// new_size is at least as large as the old_usable_size.
new_size = std::max(new_size, old_usable_size * 3 / 2);
}
#endif
// This realloc cannot be resized in-place. Sadness. // This realloc cannot be resized in-place. Sadness.
void* ret = AllocInternal<alloc_flags>( void* ret = AllocInternal<alloc_flags>(
new_size, internal::PartitionPageSize(), type_name); new_size, internal::PartitionPageSize(), type_name);

View file

@ -1255,6 +1255,7 @@ struct pointer_traits<::raw_ptr<T, Traits>> {
} }
}; };
#if PA_BUILDFLAG(ASSERT_CPP_20)
// Mark `raw_ptr<T>` and `T*` as having a common reference type (the type to // Mark `raw_ptr<T>` and `T*` as having a common reference type (the type to
// which both can be converted or bound) of `T*`. This makes them satisfy // which both can be converted or bound) of `T*`. This makes them satisfy
// `std::equality_comparable`, which allows usage like: // `std::equality_comparable`, which allows usage like:
@ -1267,23 +1268,20 @@ struct pointer_traits<::raw_ptr<T, Traits>> {
// error about being unable to invoke `std::ranges::equal_to()`. // error about being unable to invoke `std::ranges::equal_to()`.
template <typename T, template <typename T,
base::RawPtrTraits Traits, base::RawPtrTraits Traits,
template <typename> template <typename> typename TQ,
typename TQ, template <typename> typename UQ>
template <typename> struct basic_common_reference<raw_ptr<T, Traits>, T*, TQ, UQ> {
typename UQ>
struct std::basic_common_reference<raw_ptr<T, Traits>, T*, TQ, UQ> {
using type = T*; using type = T*;
}; };
template <typename T, template <typename T,
base::RawPtrTraits Traits, base::RawPtrTraits Traits,
template <typename> template <typename> typename TQ,
typename TQ, template <typename> typename UQ>
template <typename> struct basic_common_reference<T*, raw_ptr<T, Traits>, TQ, UQ> {
typename UQ>
struct std::basic_common_reference<T*, raw_ptr<T, Traits>, TQ, UQ> {
using type = T*; using type = T*;
}; };
#endif // PA_BUILDFLAG(ASSERT_CPP_20)
} // namespace std } // namespace std

View file

@ -153,9 +153,6 @@ using EventuallyZeroFreedMemory = partition_alloc::internal::base::
using FewerMemoryRegions = using FewerMemoryRegions =
partition_alloc::internal::base::StrongAlias<class FewerMemoryRegionsTag, partition_alloc::internal::base::StrongAlias<class FewerMemoryRegionsTag,
bool>; bool>;
using UsePoolOffsetFreelists = partition_alloc::internal::base::
StrongAlias<class UsePoolOffsetFreelistsTag, bool>;
using UseSmallSingleSlotSpans = partition_alloc::internal::base:: using UseSmallSingleSlotSpans = partition_alloc::internal::base::
StrongAlias<class UseSmallSingleSlotSpansTag, bool>; StrongAlias<class UseSmallSingleSlotSpansTag, bool>;
@ -174,7 +171,6 @@ void ConfigurePartitions(
ZappingByFreeFlags zapping_by_free_flags, ZappingByFreeFlags zapping_by_free_flags,
EventuallyZeroFreedMemory eventually_zero_freed_memory, EventuallyZeroFreedMemory eventually_zero_freed_memory,
FewerMemoryRegions fewer_memory_regions, FewerMemoryRegions fewer_memory_regions,
UsePoolOffsetFreelists use_pool_offset_freelists,
UseSmallSingleSlotSpans use_small_single_slot_spans); UseSmallSingleSlotSpans use_small_single_slot_spans);
PA_COMPONENT_EXPORT(ALLOCATOR_SHIM) uint32_t GetMainPartitionRootExtrasSize(); PA_COMPONENT_EXPORT(ALLOCATOR_SHIM) uint32_t GetMainPartitionRootExtrasSize();

View file

@ -620,7 +620,6 @@ void ConfigurePartitions(
ZappingByFreeFlags zapping_by_free_flags, ZappingByFreeFlags zapping_by_free_flags,
EventuallyZeroFreedMemory eventually_zero_freed_memory, EventuallyZeroFreedMemory eventually_zero_freed_memory,
FewerMemoryRegions fewer_memory_regions, FewerMemoryRegions fewer_memory_regions,
UsePoolOffsetFreelists use_pool_offset_freelists,
UseSmallSingleSlotSpans use_small_single_slot_spans) { UseSmallSingleSlotSpans use_small_single_slot_spans) {
// Calling Get() is actually important, even if the return value isn't // Calling Get() is actually important, even if the return value isn't
// used, because it has a side effect of initializing the variable, if it // used, because it has a side effect of initializing the variable, if it
@ -668,9 +667,7 @@ void ConfigurePartitions(
: partition_alloc::PartitionOptions::kDisabled, : partition_alloc::PartitionOptions::kDisabled,
.reporting_mode = memory_tagging_reporting_mode}; .reporting_mode = memory_tagging_reporting_mode};
opts.use_pool_offset_freelists = opts.use_pool_offset_freelists =
use_pool_offset_freelists partition_alloc::PartitionOptions::kEnabled;
? partition_alloc::PartitionOptions::kEnabled
: partition_alloc::PartitionOptions::kDisabled;
opts.use_small_single_slot_spans = opts.use_small_single_slot_spans =
use_small_single_slot_spans use_small_single_slot_spans
? partition_alloc::PartitionOptions::kEnabled ? partition_alloc::PartitionOptions::kEnabled

View file

@ -181,15 +181,14 @@ PA_ALWAYS_INLINE void ConfigurePartitionsForTesting() {
auto zapping_by_free_flags = ZappingByFreeFlags(false); auto zapping_by_free_flags = ZappingByFreeFlags(false);
auto eventually_zero_freed_memory = EventuallyZeroFreedMemory(false); auto eventually_zero_freed_memory = EventuallyZeroFreedMemory(false);
auto fewer_memory_regions = FewerMemoryRegions(false); auto fewer_memory_regions = FewerMemoryRegions(false);
auto use_pool_offset_freelists = UsePoolOffsetFreelists(true);
auto use_small_single_slot_spans = UseSmallSingleSlotSpans(true); auto use_small_single_slot_spans = UseSmallSingleSlotSpans(true);
ConfigurePartitions( ConfigurePartitions(enable_brp, brp_extra_extras_size, enable_memory_tagging,
enable_brp, brp_extra_extras_size, enable_memory_tagging, memory_tagging_reporting_mode, distribution,
memory_tagging_reporting_mode, distribution, scheduler_loop_quarantine, scheduler_loop_quarantine,
scheduler_loop_quarantine_capacity_in_bytes, zapping_by_free_flags, scheduler_loop_quarantine_capacity_in_bytes,
eventually_zero_freed_memory, fewer_memory_regions, zapping_by_free_flags, eventually_zero_freed_memory,
use_pool_offset_freelists, use_small_single_slot_spans); fewer_memory_regions, use_small_single_slot_spans);
} }
#endif // PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) #endif // PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)

View file

@ -0,0 +1,196 @@
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/android/android_info.h"
#include <cstring>
#include <mutex>
#include <string>
#include <variant>
#include "base/android/jni_android.h"
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "base/android/scoped_java_ref.h"
#include "base/check.h"
#include "base/strings/string_number_conversions.h"
// Must come after all headers that specialize FromJniType() / ToJniType().
#include "base/android_info_jni/AndroidInfo_jni.h"
namespace base::android::android_info {
namespace {
struct AndroidInfo {
// Const char* is used instead of std::strings because these values must be
// available even if the process is in a crash state. Sadly
// std::string.c_str() doesn't guarantee that memory won't be allocated when
// it is called.
const char* device;
const char* manufacturer;
const char* model;
const char* brand;
const char* android_build_id;
const char* build_type;
const char* board;
const char* android_build_fp;
int sdk_int;
bool is_debug_android;
const char* version_incremental;
const char* hardware;
bool is_at_least_u;
const char* codename;
// Available only on android S+. For S-, this method returns empty string.
const char* soc_manufacturer;
bool is_at_least_t;
const char* abi_name;
};
std::optional<AndroidInfo> holder;
const AndroidInfo& get_android_info() {
[[maybe_unused]] static auto once = [] {
Java_AndroidInfo_nativeReadyForFields(AttachCurrentThread());
return std::monostate();
}();
// holder should be initialized as the java is supposed to call the native
// method FillFields which will initialize the fields within the holder.
DCHECK(holder.has_value());
return *holder;
}
} // namespace
static void JNI_AndroidInfo_FillFields(
JNIEnv* env,
const jni_zero::JavaParamRef<jstring>& brand,
const jni_zero::JavaParamRef<jstring>& device,
const jni_zero::JavaParamRef<jstring>& buildId,
const jni_zero::JavaParamRef<jstring>& manufacturer,
const jni_zero::JavaParamRef<jstring>& model,
const jni_zero::JavaParamRef<jstring>& type,
const jni_zero::JavaParamRef<jstring>& board,
const jni_zero::JavaParamRef<jstring>& androidBuildFingerprint,
const jni_zero::JavaParamRef<jstring>& versionIncremental,
const jni_zero::JavaParamRef<jstring>& hardware,
const jni_zero::JavaParamRef<jstring>& codeName,
const jni_zero::JavaParamRef<jstring>& socManufacturer,
const jni_zero::JavaParamRef<jstring>& supportedAbis,
jint sdkInt,
jboolean isDebugAndroid,
jboolean isAtleastU,
jboolean isAtleastT) {
DCHECK(!holder.has_value());
auto java_string_to_const_char =
[](const jni_zero::JavaParamRef<jstring>& str) {
return strdup(ConvertJavaStringToUTF8(str).c_str());
};
holder = AndroidInfo{
.device = java_string_to_const_char(device),
.manufacturer = java_string_to_const_char(manufacturer),
.model = java_string_to_const_char(model),
.brand = java_string_to_const_char(brand),
.android_build_id = java_string_to_const_char(buildId),
.build_type = java_string_to_const_char(type),
.board = java_string_to_const_char(board),
.android_build_fp = java_string_to_const_char(androidBuildFingerprint),
.sdk_int = sdkInt,
.is_debug_android = static_cast<bool>(isDebugAndroid),
.version_incremental = java_string_to_const_char(versionIncremental),
.hardware = java_string_to_const_char(hardware),
.is_at_least_u = static_cast<bool>(isAtleastU),
.codename = java_string_to_const_char(codeName),
.soc_manufacturer = java_string_to_const_char(socManufacturer),
.is_at_least_t = static_cast<bool>(isAtleastT),
.abi_name = java_string_to_const_char(supportedAbis),
};
}
const char* device() {
return get_android_info().device;
}
const char* manufacturer() {
return get_android_info().manufacturer;
}
const char* model() {
return get_android_info().model;
}
const char* brand() {
return get_android_info().brand;
}
const char* android_build_id() {
return get_android_info().android_build_id;
}
const char* build_type() {
return get_android_info().build_type;
}
const char* board() {
return get_android_info().board;
}
const char* android_build_fp() {
return get_android_info().android_build_fp;
}
int sdk_int() {
return get_android_info().sdk_int;
}
bool is_debug_android() {
return get_android_info().is_debug_android;
}
const char* version_incremental() {
return get_android_info().version_incremental;
}
const char* hardware() {
return get_android_info().hardware;
}
bool is_at_least_u() {
return get_android_info().is_at_least_u;
}
const char* codename() {
return get_android_info().codename;
}
// Available only on android S+. For S-, this method returns empty string.
const char* soc_manufacturer() {
return get_android_info().soc_manufacturer;
}
bool is_at_least_t() {
return get_android_info().is_at_least_t;
}
const char* abi_name() {
return get_android_info().abi_name;
}
} // namespace base::android::android_info

View file

@ -0,0 +1,74 @@
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_ANDROID_ANDROID_INFO_H_
#define BASE_ANDROID_ANDROID_INFO_H_
#include "base/base_export.h"
namespace base::android::android_info {
// This enumeration maps to the values returned by AndroidInfo::sdk_int(),
// indicating the Android release associated with a given SDK version.
enum SdkVersion {
SDK_VERSION_JELLY_BEAN = 16,
SDK_VERSION_JELLY_BEAN_MR1 = 17,
SDK_VERSION_JELLY_BEAN_MR2 = 18,
SDK_VERSION_KITKAT = 19,
SDK_VERSION_KITKAT_WEAR = 20,
SDK_VERSION_LOLLIPOP = 21,
SDK_VERSION_LOLLIPOP_MR1 = 22,
SDK_VERSION_MARSHMALLOW = 23,
SDK_VERSION_NOUGAT = 24,
SDK_VERSION_NOUGAT_MR1 = 25,
SDK_VERSION_OREO = 26,
SDK_VERSION_O_MR1 = 27,
SDK_VERSION_P = 28,
SDK_VERSION_Q = 29,
SDK_VERSION_R = 30,
SDK_VERSION_S = 31,
SDK_VERSION_Sv2 = 32,
SDK_VERSION_T = 33,
SDK_VERSION_U = 34,
SDK_VERSION_V = 35,
};
const char* device();
const char* manufacturer();
const char* model();
BASE_EXPORT const char* brand();
const char* android_build_id();
const char* build_type();
const char* board();
const char* android_build_fp();
BASE_EXPORT int sdk_int();
bool is_debug_android();
const char* version_incremental();
BASE_EXPORT const char* hardware();
bool is_at_least_u();
const char* codename();
// Available only on android S+. For S-, this method returns empty string.
const char* soc_manufacturer();
bool is_at_least_t();
const char* abi_name();
} // namespace base::android::android_info
#endif // BASE_ANDROID_ANDROID_INFO_H_

View file

@ -0,0 +1,131 @@
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/android/apk_info.h"
#include <string>
#include <variant>
#include "base/android/jni_android.h"
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "base/android/scoped_java_ref.h"
#include "base/strings/string_number_conversions.h"
// Must come after all headers that specialize FromJniType() / ToJniType().
#include "base/build_info_jni/ApkInfo_jni.h"
namespace base::android::apk_info {
namespace {
struct ApkInfo {
// Const char* is used instead of std::strings because these values must be
// available even if the process is in a crash state. Sadly
// std::string.c_str() doesn't guarantee that memory won't be allocated when
// it is called.
const char* host_package_name;
const char* host_version_code;
const char* host_package_label;
const char* package_version_code;
const char* package_version_name;
const char* package_name;
const char* resources_version;
const char* installer_package_name;
bool is_debug_app;
bool targets_at_least_u;
int target_sdk_version;
};
std::optional<ApkInfo> holder;
ApkInfo& get_apk_info() {
[[maybe_unused]] static auto once = [] {
Java_ApkInfo_nativeReadyForFields(AttachCurrentThread());
return std::monostate();
}();
// holder should be initialized as the java is supposed to call the native
// method FillFields which will initialize the fields within the holder.
DCHECK(holder.has_value());
return *holder;
}
} // namespace
static void JNI_ApkInfo_FillFields(
JNIEnv* env,
const jni_zero::JavaParamRef<jstring>& hostPackageName,
const jni_zero::JavaParamRef<jstring>& hostVersionCode,
const jni_zero::JavaParamRef<jstring>& hostPackageLabel,
const jni_zero::JavaParamRef<jstring>& packageVersionCode,
const jni_zero::JavaParamRef<jstring>& packageVersionName,
const jni_zero::JavaParamRef<jstring>& packageName,
const jni_zero::JavaParamRef<jstring>& resourcesVersion,
const jni_zero::JavaParamRef<jstring>& installerPackageName,
jboolean isDebugApp,
jboolean targetsAtleastU,
jint targetSdkVersion) {
DCHECK(!holder.has_value());
auto java_string_to_const_char =
[](const jni_zero::JavaParamRef<jstring>& str) {
return strdup(ConvertJavaStringToUTF8(str).c_str());
};
holder = ApkInfo{
.host_package_name = java_string_to_const_char(hostPackageName),
.host_version_code = java_string_to_const_char(hostVersionCode),
.host_package_label = java_string_to_const_char(hostPackageLabel),
.package_version_code = java_string_to_const_char(packageVersionCode),
.package_version_name = java_string_to_const_char(packageVersionName),
.package_name = java_string_to_const_char(packageName),
.resources_version = java_string_to_const_char(resourcesVersion),
.installer_package_name = java_string_to_const_char(installerPackageName),
.is_debug_app = static_cast<bool>(isDebugApp),
.targets_at_least_u = static_cast<bool>(targetsAtleastU),
.target_sdk_version = targetSdkVersion};
}
const char* host_package_name() {
return get_apk_info().host_package_name;
}
const char* host_version_code() {
return get_apk_info().host_version_code;
}
const char* host_package_label() {
return get_apk_info().host_package_label;
}
const char* package_version_code() {
return get_apk_info().package_version_code;
}
const char* package_version_name() {
return get_apk_info().package_version_name;
}
const char* package_name() {
return get_apk_info().package_name;
}
const char* resources_version() {
return get_apk_info().resources_version;
}
const char* installer_package_name() {
return get_apk_info().installer_package_name;
}
bool is_debug_app() {
return get_apk_info().is_debug_app;
}
int target_sdk_version() {
return get_apk_info().target_sdk_version;
}
bool targets_at_least_u() {
return get_apk_info().targets_at_least_u;
}
} // namespace base::android::apk_info

View file

@ -0,0 +1,43 @@
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_ANDROID_APK_INFO_H_
#define BASE_ANDROID_APK_INFO_H_
namespace base::android::apk_info {
// The package name of the host app which has loaded WebView, retrieved from
// the application context. In the context of the SDK Runtime, the package
// name of the app that owns this particular instance of the SDK Runtime will
// also be included. e.g.
// com.google.android.sdksandbox:com:com.example.myappwithads
const char* host_package_name();
// The application name (e.g. "Chrome"). For WebView, this is name of the
// embedding app. In the context of the SDK Runtime, this is the name of the
// app that owns this particular instance of the SDK Runtime.
const char* host_version_code();
// By default: same as versionCode. For WebView: versionCode of the embedding
// app. In the context of the SDK Runtime, this is the versionCode of the app
// that owns this particular instance of the SDK Runtime.
const char* host_package_label();
const char* package_version_code();
const char* package_version_name();
const char* package_name();
const char* resources_version();
const char* installer_package_name();
bool is_debug_app();
int target_sdk_version();
bool targets_at_least_u();
} // namespace base::android::apk_info
#endif // BASE_ANDROID_APK_INFO_H_

View file

@ -6,6 +6,9 @@
#include <string> #include <string>
#include "base/android/android_info.h"
#include "base/android/apk_info.h"
#include "base/android/device_info.h"
#include "base/android/jni_android.h" #include "base/android/jni_android.h"
#include "base/android/jni_array.h" #include "base/android/jni_array.h"
#include "base/android/jni_string.h" #include "base/android/jni_string.h"
@ -16,35 +19,13 @@
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
// Must come after all headers that specialize FromJniType() / ToJniType(). // Must come after all headers that specialize FromJniType() / ToJniType().
#include "base/base_jni/BuildInfo_jni.h" #include "base/build_info_jni/BuildInfo_jni.h"
namespace base { namespace base {
namespace android { namespace android {
namespace {
// We are leaking these strings.
const char* StrDupParam(const std::vector<std::string>& params, size_t index) {
return strdup(params[index].c_str());
}
int GetIntParam(const std::vector<std::string>& params, size_t index) {
int ret = 0;
bool success = StringToInt(params[index], &ret);
DCHECK(success);
return ret;
}
} // namespace
struct BuildInfoSingletonTraits { struct BuildInfoSingletonTraits {
static BuildInfo* New() { static BuildInfo* New() { return new BuildInfo(); }
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobjectArray> params_objs = Java_BuildInfo_getAll(env);
std::vector<std::string> params;
AppendJavaStringArrayToStringVector(env, params_objs, &params);
return new BuildInfo(params);
}
static void Delete(BuildInfo* x) { static void Delete(BuildInfo* x) {
// We're leaking this type, see kRegisterAtExit. // We're leaking this type, see kRegisterAtExit.
@ -57,51 +38,50 @@ struct BuildInfoSingletonTraits {
#endif #endif
}; };
BuildInfo::BuildInfo(const std::vector<std::string>& params) BuildInfo::BuildInfo()
: brand_(StrDupParam(params, 0)), : brand_(android_info::brand()),
device_(StrDupParam(params, 1)), device_(android_info::device()),
android_build_id_(StrDupParam(params, 2)), android_build_id_(android_info::android_build_id()),
manufacturer_(StrDupParam(params, 3)), manufacturer_(android_info::manufacturer()),
model_(StrDupParam(params, 4)), model_(android_info::model()),
sdk_int_(GetIntParam(params, 5)), sdk_int_(android_info::sdk_int()),
build_type_(StrDupParam(params, 6)), build_type_(android_info::build_type()),
board_(StrDupParam(params, 7)), board_(android_info::board()),
host_package_name_(StrDupParam(params, 8)), host_package_name_(apk_info::host_package_name()),
host_version_code_(StrDupParam(params, 9)), host_version_code_(apk_info::host_version_code()),
host_package_label_(StrDupParam(params, 10)), host_package_label_(apk_info::host_package_label()),
package_name_(StrDupParam(params, 11)), package_name_(apk_info::package_name()),
package_version_code_(StrDupParam(params, 12)), package_version_code_(apk_info::package_version_code()),
package_version_name_(StrDupParam(params, 13)), package_version_name_(apk_info::package_version_name()),
android_build_fp_(StrDupParam(params, 14)), android_build_fp_(android_info::android_build_fp()),
gms_version_code_(StrDupParam(params, 15)), installer_package_name_(apk_info::installer_package_name()),
installer_package_name_(StrDupParam(params, 16)), abi_name_(android_info::abi_name()),
abi_name_(StrDupParam(params, 17)), resources_version_(apk_info::resources_version()),
custom_themes_(StrDupParam(params, 18)), target_sdk_version_(apk_info::target_sdk_version()),
resources_version_(StrDupParam(params, 19)), is_debug_android_(android_info::is_debug_android()),
target_sdk_version_(GetIntParam(params, 20)), is_tv_(device_info::is_tv()),
is_debug_android_(GetIntParam(params, 21)), version_incremental_(android_info::version_incremental()),
is_tv_(GetIntParam(params, 22)), hardware_(android_info::hardware()),
version_incremental_(StrDupParam(params, 23)), is_at_least_t_(android_info::is_at_least_t()),
hardware_(StrDupParam(params, 24)), is_automotive_(device_info::is_automotive()),
is_at_least_t_(GetIntParam(params, 25)), is_at_least_u_(android_info::is_at_least_u()),
is_automotive_(GetIntParam(params, 26)), targets_at_least_u_(apk_info::targets_at_least_u()),
is_at_least_u_(GetIntParam(params, 27)), codename_(android_info::codename()),
targets_at_least_u_(GetIntParam(params, 28)), vulkan_deqp_level_(device_info::vulkan_deqp_level()),
codename_(StrDupParam(params, 29)), is_foldable_(device_info::is_foldable()),
vulkan_deqp_level_(GetIntParam(params, 30)), soc_manufacturer_(android_info::soc_manufacturer()),
is_foldable_(GetIntParam(params, 31)), is_debug_app_(apk_info::is_debug_app()),
soc_manufacturer_(StrDupParam(params, 32)), is_desktop_(device_info::is_desktop()) {}
is_debug_app_(GetIntParam(params, 33)),
is_desktop_(GetIntParam(params, 34)) {}
BuildInfo::~BuildInfo() = default; BuildInfo::~BuildInfo() = default;
const char* BuildInfo::gms_version_code() const {
return device_info::gms_version_code();
}
void BuildInfo::set_gms_version_code_for_test( void BuildInfo::set_gms_version_code_for_test(
const std::string& gms_version_code) { const std::string& gms_version_code) {
// This leaks the string, just like production code. device_info::set_gms_version_code_for_test(gms_version_code);
gms_version_code_ = strdup(gms_version_code.c_str());
Java_BuildInfo_setGmsVersionCodeForTest(AttachCurrentThread(),
gms_version_code);
} }
std::string BuildInfo::host_signing_cert_sha256() { std::string BuildInfo::host_signing_cert_sha256() {

View file

@ -10,36 +10,42 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "base/android/android_info.h"
#include "base/base_export.h" #include "base/base_export.h"
#include "base/memory/singleton.h" #include "base/memory/singleton.h"
namespace base::android { namespace base::android {
// DEPRECATED: Please use android_info::SdkVersion.
//
// This enumeration maps to the values returned by BuildInfo::sdk_int(), // This enumeration maps to the values returned by BuildInfo::sdk_int(),
// indicating the Android release associated with a given SDK version. // indicating the Android release associated with a given SDK version.
enum SdkVersion { enum SdkVersion {
SDK_VERSION_JELLY_BEAN = 16, SDK_VERSION_JELLY_BEAN = android_info::SDK_VERSION_JELLY_BEAN,
SDK_VERSION_JELLY_BEAN_MR1 = 17, SDK_VERSION_JELLY_BEAN_MR1 = android_info::SDK_VERSION_JELLY_BEAN_MR1,
SDK_VERSION_JELLY_BEAN_MR2 = 18, SDK_VERSION_JELLY_BEAN_MR2 = android_info::SDK_VERSION_JELLY_BEAN_MR2,
SDK_VERSION_KITKAT = 19, SDK_VERSION_KITKAT = android_info::SDK_VERSION_KITKAT,
SDK_VERSION_KITKAT_WEAR = 20, SDK_VERSION_KITKAT_WEAR = android_info::SDK_VERSION_KITKAT_WEAR,
SDK_VERSION_LOLLIPOP = 21, SDK_VERSION_LOLLIPOP = android_info::SDK_VERSION_LOLLIPOP,
SDK_VERSION_LOLLIPOP_MR1 = 22, SDK_VERSION_LOLLIPOP_MR1 = android_info::SDK_VERSION_LOLLIPOP_MR1,
SDK_VERSION_MARSHMALLOW = 23, SDK_VERSION_MARSHMALLOW = android_info::SDK_VERSION_MARSHMALLOW,
SDK_VERSION_NOUGAT = 24, SDK_VERSION_NOUGAT = android_info::SDK_VERSION_NOUGAT,
SDK_VERSION_NOUGAT_MR1 = 25, SDK_VERSION_NOUGAT_MR1 = android_info::SDK_VERSION_NOUGAT_MR1,
SDK_VERSION_OREO = 26, SDK_VERSION_OREO = android_info::SDK_VERSION_OREO,
SDK_VERSION_O_MR1 = 27, SDK_VERSION_O_MR1 = android_info::SDK_VERSION_O_MR1,
SDK_VERSION_P = 28, SDK_VERSION_P = android_info::SDK_VERSION_P,
SDK_VERSION_Q = 29, SDK_VERSION_Q = android_info::SDK_VERSION_Q,
SDK_VERSION_R = 30, SDK_VERSION_R = android_info::SDK_VERSION_R,
SDK_VERSION_S = 31, SDK_VERSION_S = android_info::SDK_VERSION_S,
SDK_VERSION_Sv2 = 32, SDK_VERSION_Sv2 = android_info::SDK_VERSION_Sv2,
SDK_VERSION_T = 33, SDK_VERSION_T = android_info::SDK_VERSION_T,
SDK_VERSION_U = 34, SDK_VERSION_U = android_info::SDK_VERSION_U,
SDK_VERSION_V = 35, SDK_VERSION_V = android_info::SDK_VERSION_V,
}; };
// DEPRECATED: Use AndroidInfo, DeviceInfo or ApkInfo instead.
// These are more efficient because they only retrieve the data being queried.
//
// BuildInfo is a singleton class that stores android build and device // BuildInfo is a singleton class that stores android build and device
// information. It will be called from Android specific code and gets used // information. It will be called from Android specific code and gets used
// primarily in crash reporting. // primarily in crash reporting.
@ -72,7 +78,7 @@ class BASE_EXPORT BuildInfo {
const char* android_build_fp() const { return android_build_fp_; } const char* android_build_fp() const { return android_build_fp_; }
const char* gms_version_code() const { return gms_version_code_; } const char* gms_version_code() const;
void set_gms_version_code_for_test(const std::string& gms_version_code); void set_gms_version_code_for_test(const std::string& gms_version_code);
@ -103,8 +109,6 @@ class BASE_EXPORT BuildInfo {
const char* package_name() const { return package_name_; } const char* package_name() const { return package_name_; }
const char* custom_themes() const { return custom_themes_; }
const char* resources_version() const { return resources_version_; } const char* resources_version() const { return resources_version_; }
const char* build_type() const { return build_type_; } const char* build_type() const { return build_type_; }
@ -158,7 +162,7 @@ class BASE_EXPORT BuildInfo {
private: private:
friend struct BuildInfoSingletonTraits; friend struct BuildInfoSingletonTraits;
explicit BuildInfo(const std::vector<std::string>& params); explicit BuildInfo();
// Const char* is used instead of std::strings because these values must be // Const char* is used instead of std::strings because these values must be
// available even if the process is in a crash state. Sadly // available even if the process is in a crash state. Sadly
@ -179,11 +183,8 @@ class BASE_EXPORT BuildInfo {
const char* const package_version_code_; const char* const package_version_code_;
const char* const package_version_name_; const char* const package_version_name_;
const char* const android_build_fp_; const char* const android_build_fp_;
// Can be overridden in tests.
const char* gms_version_code_ = nullptr;
const char* const installer_package_name_; const char* const installer_package_name_;
const char* const abi_name_; const char* const abi_name_;
const char* const custom_themes_;
const char* const resources_version_; const char* const resources_version_;
// Not needed by breakpad. // Not needed by breakpad.
const int target_sdk_version_; const int target_sdk_version_;

View file

@ -22,7 +22,7 @@ namespace base {
namespace android { namespace android {
struct BuildInfoSingletonTraits { struct BuildInfoSingletonTraits {
static BuildInfo* New() { return new BuildInfo({}); } static BuildInfo* New() { return new BuildInfo(); }
static void Delete(BuildInfo* x) { static void Delete(BuildInfo* x) {
// We're leaking this type, see kRegisterAtExit. // We're leaking this type, see kRegisterAtExit.
@ -32,7 +32,7 @@ struct BuildInfoSingletonTraits {
static const bool kRegisterAtExit = false; static const bool kRegisterAtExit = false;
}; };
BuildInfo::BuildInfo(const std::vector<std::string>& params) BuildInfo::BuildInfo()
: brand_(""), : brand_(""),
device_(""), device_(""),
android_build_id_(""), android_build_id_(""),
@ -48,10 +48,8 @@ BuildInfo::BuildInfo(const std::vector<std::string>& params)
package_version_code_(""), package_version_code_(""),
package_version_name_(""), package_version_name_(""),
android_build_fp_(""), android_build_fp_(""),
gms_version_code_(""),
installer_package_name_(""), installer_package_name_(""),
abi_name_(""), abi_name_(""),
custom_themes_(""),
resources_version_(""), resources_version_(""),
target_sdk_version_(0), target_sdk_version_(0),
is_debug_android_(false), is_debug_android_(false),

View file

@ -10,13 +10,9 @@
#include "base/android/scoped_java_ref.h" #include "base/android/scoped_java_ref.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "base/types/optional_ref.h" #include "base/types/optional_ref.h"
#include "build/robolectric_buildflags.h"
#if BUILDFLAG(IS_ROBOLECTRIC) // Must come after all headers that specialize FromJniType() / ToJniType().
#include "base/base_robolectric_jni/Callback_jni.h" // nogncheck
#else
#include "base/callback_jni/Callback_jni.h" #include "base/callback_jni/Callback_jni.h"
#endif
namespace base { namespace base {
namespace android { namespace android {

View file

@ -5,14 +5,9 @@
#include "base/command_line.h" #include "base/command_line.h"
#include "base/android/jni_string.h" #include "base/android/jni_string.h"
#include "build/robolectric_buildflags.h"
// Must come after all headers that specialize FromJniType() / ToJniType(). // Must come after all headers that specialize FromJniType() / ToJniType().
#if BUILDFLAG(IS_ROBOLECTRIC)
#include "base/base_robolectric_jni/CommandLine_jni.h" // nogncheck
#else
#include "base/command_line_jni/CommandLine_jni.h" #include "base/command_line_jni/CommandLine_jni.h"
#endif
using base::CommandLine; using base::CommandLine;
using base::android::JavaParamRef; using base::android::JavaParamRef;

View file

@ -0,0 +1,101 @@
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/android/device_info.h"
#include <string>
#include "base/android/jni_android.h"
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "base/android/scoped_java_ref.h"
#include "base/strings/string_number_conversions.h"
// Must come after all headers that specialize FromJniType() / ToJniType().
#include "base/build_info_jni/DeviceInfo_jni.h"
#include "base/synchronization/lock.h"
namespace base::android::device_info {
namespace {
struct DeviceInfo {
// Const char* is used instead of std::strings because these values must be
// available even if the process is in a crash state. Sadly
// std::string.c_str() doesn't guarantee that memory won't be allocated when
// it is called.
const char* gms_version_code;
bool is_tv;
bool is_automotive;
bool is_foldable;
bool is_desktop;
// Available only on Android T+.
int32_t vulkan_deqp_level;
};
std::optional<DeviceInfo> holder;
DeviceInfo& get_device_info() {
[[maybe_unused]] static auto once = [] {
Java_DeviceInfo_nativeReadyForFields(AttachCurrentThread());
return std::monostate();
}();
// holder should be initialized as the java is supposed to call the native
// method FillFields which will initialize the fields within the holder.
DCHECK(holder.has_value());
return *holder;
}
} // namespace
static void JNI_DeviceInfo_FillFields(
JNIEnv* env,
const jni_zero::JavaParamRef<jstring>& gmsVersionCode,
jboolean isTV,
jboolean isAutomotive,
jboolean isFoldable,
jboolean isDesktop,
jint vulkanDeqpLevel) {
DCHECK(!holder.has_value());
auto java_string_to_const_char =
[](const jni_zero::JavaParamRef<jstring>& str) {
return strdup(ConvertJavaStringToUTF8(str).c_str());
};
holder =
DeviceInfo{.gms_version_code = java_string_to_const_char(gmsVersionCode),
.is_tv = static_cast<bool>(isTV),
.is_automotive = static_cast<bool>(isAutomotive),
.is_foldable = static_cast<bool>(isFoldable),
.is_desktop = static_cast<bool>(isDesktop),
.vulkan_deqp_level = vulkanDeqpLevel};
}
const char* gms_version_code() {
return get_device_info().gms_version_code;
}
void set_gms_version_code_for_test(const std::string& gms_version_code) {
get_device_info().gms_version_code = strdup(gms_version_code.c_str());
Java_DeviceInfo_setGmsVersionCodeForTest(AttachCurrentThread(),
gms_version_code);
}
bool is_tv() {
return get_device_info().is_tv;
}
bool is_automotive() {
return get_device_info().is_automotive;
}
bool is_foldable() {
return get_device_info().is_foldable;
}
bool is_desktop() {
return get_device_info().is_desktop;
}
// Available only on Android T+.
int32_t vulkan_deqp_level() {
return get_device_info().vulkan_deqp_level;
}
} // namespace base::android::device_info

View file

@ -0,0 +1,24 @@
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_ANDROID_DEVICE_INFO_H_
#define BASE_ANDROID_DEVICE_INFO_H_
#include <string>
namespace base::android::device_info {
const char* gms_version_code();
void set_gms_version_code_for_test(const std::string& gms_version_code);
bool is_tv();
bool is_automotive();
bool is_foldable();
bool is_desktop();
// Available only on Android T+.
int32_t vulkan_deqp_level();
} // namespace base::android::device_info
#endif // BASE_ANDROID_DEVICE_INFO_H_

View file

@ -28,8 +28,8 @@ static void JNI_EarlyTraceEvent_RecordEarlyBeginEvent(JNIEnv* env,
TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(internal::kJavaTraceCategory); TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(internal::kJavaTraceCategory);
trace_event_internal::AddTraceEventWithThreadIdAndTimestamps( trace_event_internal::AddTraceEventWithThreadIdAndTimestamps(
TRACE_EVENT_PHASE_BEGIN, category_group_enabled, name.c_str(), TRACE_EVENT_PHASE_BEGIN, category_group_enabled, name.c_str(),
/*scope=*/nullptr, trace_event_internal::kNoId, thread_id, /*scope=*/nullptr, trace_event_internal::kNoId,
TimeTicks::FromJavaNanoTime(time_ns), PlatformThreadId(thread_id), TimeTicks::FromJavaNanoTime(time_ns),
ThreadTicks() + Milliseconds(thread_time_ms), ThreadTicks() + Milliseconds(thread_time_ms),
TRACE_EVENT_FLAG_JAVA_STRING_LITERALS | TRACE_EVENT_FLAG_COPY); TRACE_EVENT_FLAG_JAVA_STRING_LITERALS | TRACE_EVENT_FLAG_COPY);
#endif // BUILDFLAG(ENABLE_BASE_TRACING) #endif // BUILDFLAG(ENABLE_BASE_TRACING)
@ -45,8 +45,8 @@ static void JNI_EarlyTraceEvent_RecordEarlyEndEvent(JNIEnv* env,
TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(internal::kJavaTraceCategory); TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(internal::kJavaTraceCategory);
trace_event_internal::AddTraceEventWithThreadIdAndTimestamps( trace_event_internal::AddTraceEventWithThreadIdAndTimestamps(
TRACE_EVENT_PHASE_END, category_group_enabled, name.c_str(), TRACE_EVENT_PHASE_END, category_group_enabled, name.c_str(),
/*scope=*/nullptr, trace_event_internal::kNoId, thread_id, /*scope=*/nullptr, trace_event_internal::kNoId,
TimeTicks::FromJavaNanoTime(time_ns), PlatformThreadId(thread_id), TimeTicks::FromJavaNanoTime(time_ns),
ThreadTicks() + Milliseconds(thread_time_ms), ThreadTicks() + Milliseconds(thread_time_ms),
TRACE_EVENT_FLAG_JAVA_STRING_LITERALS | TRACE_EVENT_FLAG_COPY); TRACE_EVENT_FLAG_JAVA_STRING_LITERALS | TRACE_EVENT_FLAG_COPY);
#endif // BUILDFLAG(ENABLE_BASE_TRACING) #endif // BUILDFLAG(ENABLE_BASE_TRACING)
@ -64,8 +64,8 @@ static void JNI_EarlyTraceEvent_RecordEarlyToplevelBeginEvent(
internal::kToplevelTraceCategory); internal::kToplevelTraceCategory);
trace_event_internal::AddTraceEventWithThreadIdAndTimestamps( trace_event_internal::AddTraceEventWithThreadIdAndTimestamps(
TRACE_EVENT_PHASE_BEGIN, category_group_enabled, name.c_str(), TRACE_EVENT_PHASE_BEGIN, category_group_enabled, name.c_str(),
/*scope=*/nullptr, trace_event_internal::kNoId, thread_id, /*scope=*/nullptr, trace_event_internal::kNoId,
TimeTicks::FromJavaNanoTime(time_ns), PlatformThreadId(thread_id), TimeTicks::FromJavaNanoTime(time_ns),
ThreadTicks() + Milliseconds(thread_time_ms), ThreadTicks() + Milliseconds(thread_time_ms),
TRACE_EVENT_FLAG_JAVA_STRING_LITERALS | TRACE_EVENT_FLAG_COPY); TRACE_EVENT_FLAG_JAVA_STRING_LITERALS | TRACE_EVENT_FLAG_COPY);
#endif // BUILDFLAG(ENABLE_BASE_TRACING) #endif // BUILDFLAG(ENABLE_BASE_TRACING)
@ -83,8 +83,8 @@ static void JNI_EarlyTraceEvent_RecordEarlyToplevelEndEvent(
internal::kToplevelTraceCategory); internal::kToplevelTraceCategory);
trace_event_internal::AddTraceEventWithThreadIdAndTimestamps( trace_event_internal::AddTraceEventWithThreadIdAndTimestamps(
TRACE_EVENT_PHASE_END, category_group_enabled, name.c_str(), TRACE_EVENT_PHASE_END, category_group_enabled, name.c_str(),
/*scope=*/nullptr, trace_event_internal::kNoId, thread_id, /*scope=*/nullptr, trace_event_internal::kNoId,
TimeTicks::FromJavaNanoTime(time_ns), PlatformThreadId(thread_id), TimeTicks::FromJavaNanoTime(time_ns),
ThreadTicks() + Milliseconds(thread_time_ms), ThreadTicks() + Milliseconds(thread_time_ms),
TRACE_EVENT_FLAG_JAVA_STRING_LITERALS | TRACE_EVENT_FLAG_COPY); TRACE_EVENT_FLAG_JAVA_STRING_LITERALS | TRACE_EVENT_FLAG_COPY);
#endif // BUILDFLAG(ENABLE_BASE_TRACING) #endif // BUILDFLAG(ENABLE_BASE_TRACING)
@ -109,7 +109,7 @@ static void JNI_EarlyTraceEvent_RecordEarlyAsyncEndEvent(JNIEnv* env,
perfetto::Track(static_cast<uint64_t>(id))); perfetto::Track(static_cast<uint64_t>(id)));
} }
bool GetBackgroundStartupTracingFlag() { bool GetBackgroundStartupTracingFlagFromJava() {
JNIEnv* env = jni_zero::AttachCurrentThread(); JNIEnv* env = jni_zero::AttachCurrentThread();
return base::android::Java_EarlyTraceEvent_getBackgroundStartupTracingFlag( return base::android::Java_EarlyTraceEvent_getBackgroundStartupTracingFlag(
env); env);

View file

@ -12,7 +12,7 @@ namespace android {
// Returns true if background startup tracing flag was set on the previous // Returns true if background startup tracing flag was set on the previous
// startup. // startup.
BASE_EXPORT bool GetBackgroundStartupTracingFlag(); BASE_EXPORT bool GetBackgroundStartupTracingFlagFromJava();
// Sets a flag to chrome application preferences to enable startup tracing next // Sets a flag to chrome application preferences to enable startup tracing next
// time the app is started. // time the app is started.

View file

@ -73,6 +73,8 @@ static std::string JNI_FieldTrialList_GetVariationParameter(
// friend the JNI function and is, in turn, friended by // friend the JNI function and is, in turn, friended by
// FieldTrialListIncludingLowAnonymity which allows for the private // FieldTrialListIncludingLowAnonymity which allows for the private
// GetActiveFieldTrialGroups() to be reached. // GetActiveFieldTrialGroups() to be reached.
static void JNI_FieldTrialList_LogActiveTrials(JNIEnv* env);
class AndroidFieldTrialListLogActiveTrialsFriendHelper { class AndroidFieldTrialListLogActiveTrialsFriendHelper {
private: private:
friend void ::JNI_FieldTrialList_LogActiveTrials(JNIEnv* env); friend void ::JNI_FieldTrialList_LogActiveTrials(JNIEnv* env);
@ -110,3 +112,5 @@ static jboolean JNI_FieldTrialList_CreateFieldTrial(JNIEnv* env,
return base::FieldTrialList::CreateFieldTrial(trial_name, group_name) != return base::FieldTrialList::CreateFieldTrial(trial_name, group_name) !=
nullptr; nullptr;
} }
DEFINE_JNI_FOR_FieldTrialList()

View file

@ -13,7 +13,7 @@
#include "base/android/jni_string.h" #include "base/android/jni_string.h"
// Must come after all headers that specialize FromJniType() / ToJniType(). // Must come after all headers that specialize FromJniType() / ToJniType().
#include "base/base_jni/IntStringCallback_jni.h" #include "base/base_minimal_jni/IntStringCallback_jni.h"
namespace base { namespace base {
namespace android { namespace android {
@ -27,3 +27,5 @@ void RunIntStringCallbackAndroid(const JavaRef<jobject>& callback,
} // namespace android } // namespace android
} // namespace base } // namespace base
DEFINE_JNI_FOR_IntStringCallback()

View file

@ -11,16 +11,10 @@
#include "base/functional/callback.h" #include "base/functional/callback.h"
#include "base/lazy_instance.h" #include "base/lazy_instance.h"
#include "base/logging.h" #include "base/logging.h"
#include "build/robolectric_buildflags.h"
// Must come after all headers that specialize FromJniType() / ToJniType(). // Must come after all headers that specialize FromJniType() / ToJniType().
#if BUILDFLAG(IS_ROBOLECTRIC) #include "base/base_minimal_jni/JavaExceptionReporter_jni.h"
#include "base/base_robolectric_jni/JavaExceptionReporter_jni.h" // nogncheck
#else
#include "base/base_jni/JavaExceptionReporter_jni.h"
#endif
using jni_zero::JavaParamRef;
using jni_zero::JavaRef; using jni_zero::JavaRef;
namespace base { namespace base {
@ -83,7 +77,7 @@ void SetJavaException(const char* exception) {
void JNI_JavaExceptionReporter_ReportJavaException( void JNI_JavaExceptionReporter_ReportJavaException(
JNIEnv* env, JNIEnv* env,
jboolean crash_after_report, jboolean crash_after_report,
const JavaParamRef<jthrowable>& e) { const JavaRef<jthrowable>& e) {
std::string exception_info = base::android::GetJavaExceptionInfo(env, e); std::string exception_info = base::android::GetJavaExceptionInfo(env, e);
bool should_report_exception = g_java_exception_filter.Get().Run(e); bool should_report_exception = g_java_exception_filter.Get().Run(e);
if (should_report_exception) { if (should_report_exception) {
@ -108,3 +102,5 @@ void JNI_JavaExceptionReporter_ReportJavaStackTrace(JNIEnv* env,
} // namespace android } // namespace android
} // namespace base } // namespace base
DEFINE_JNI_FOR_JavaExceptionReporter()

View file

@ -19,11 +19,8 @@
#include "build/robolectric_buildflags.h" #include "build/robolectric_buildflags.h"
#include "third_party/jni_zero/jni_zero.h" #include "third_party/jni_zero/jni_zero.h"
#if BUILDFLAG(IS_ROBOLECTRIC) // Must come after all headers that specialize FromJniType() / ToJniType().
#include "base/base_robolectric_jni/JniAndroid_jni.h" // nogncheck #include "base/base_minimal_jni/JniAndroid_jni.h"
#else
#include "base/base_jni/JniAndroid_jni.h"
#endif
namespace base { namespace base {
namespace android { namespace android {
@ -268,3 +265,5 @@ std::string GetJavaStackTraceIfPresent() {
} // namespace android } // namespace android
} // namespace base } // namespace base
DEFINE_JNI_FOR_JniAndroid()

View file

@ -5,9 +5,9 @@
#include "base/android/jni_callback.h" #include "base/android/jni_callback.h"
// Must come after all headers that specialize FromJniType() / ToJniType(). // Must come after all headers that specialize FromJniType() / ToJniType().
#include "base/base_jni/JniCallbackUtils_jni.h" #include "base/base_minimal_jni/JniCallbackUtils_jni.h"
#include "base/base_jni/JniOnceCallback_jni.h" #include "base/base_minimal_jni/JniOnceCallback_jni.h"
#include "base/base_jni/JniRepeatingCallback_jni.h" #include "base/base_minimal_jni/JniRepeatingCallback_jni.h"
namespace base::android { namespace base::android {
@ -110,3 +110,7 @@ void JNI_JniCallbackUtils_Destroy(JNIEnv* env,
} }
} // namespace base::android } // namespace base::android
DEFINE_JNI_FOR_JniCallbackUtils()
DEFINE_JNI_FOR_JniOnceCallback()
DEFINE_JNI_FOR_JniRepeatingCallback()

View file

@ -7,26 +7,29 @@
#include "base/android/jni_string.h" #include "base/android/jni_string.h"
#include "base/android/scoped_java_ref.h" #include "base/android/scoped_java_ref.h"
#include "base/containers/flat_map.h" #include "base/containers/flat_map.h"
#include "base/lazy_instance.h"
#include "base/no_destructor.h" #include "base/no_destructor.h"
#include "base/synchronization/lock.h" #include "base/synchronization/lock.h"
#include "build/robolectric_buildflags.h"
#if BUILDFLAG(IS_ROBOLECTRIC) // Must come after all headers that specialize FromJniType() / ToJniType().
#include "base/base_robolectric_jni/JNIUtils_jni.h" // nogncheck #include "base/base_minimal_jni/JNIUtils_jni.h"
#else
#include "base/base_jni/JNIUtils_jni.h"
#endif
namespace base { namespace base {
namespace android { namespace android {
jobject GetSplitClassLoader(JNIEnv* env, const char* split_name) { namespace {
struct LockAndMap { struct LockAndMap {
base::Lock lock; base::Lock lock;
base::flat_map<const char*, ScopedJavaGlobalRef<jobject>> map; base::flat_map<const char*, ScopedJavaGlobalRef<jobject>> map;
}; };
LockAndMap* GetLockAndMap() {
static base::NoDestructor<LockAndMap> lock_and_map; static base::NoDestructor<LockAndMap> lock_and_map;
return lock_and_map.get();
}
} // namespace
jobject GetSplitClassLoader(JNIEnv* env, const char* split_name) {
LockAndMap* lock_and_map = GetLockAndMap();
base::AutoLock guard(lock_and_map->lock); base::AutoLock guard(lock_and_map->lock);
auto it = lock_and_map->map.find(split_name); auto it = lock_and_map->map.find(split_name);
if (it != lock_and_map->map.end()) { if (it != lock_and_map->map.end()) {
@ -34,7 +37,7 @@ jobject GetSplitClassLoader(JNIEnv* env, const char* split_name) {
} }
ScopedJavaGlobalRef<jobject> class_loader( ScopedJavaGlobalRef<jobject> class_loader(
Java_JNIUtils_getSplitClassLoader(env, split_name)); env, Java_JNIUtils_getSplitClassLoader(env, split_name));
jobject class_loader_obj = class_loader.obj(); jobject class_loader_obj = class_loader.obj();
lock_and_map->map.insert({split_name, std::move(class_loader)}); lock_and_map->map.insert({split_name, std::move(class_loader)});
return class_loader_obj; return class_loader_obj;
@ -42,3 +45,5 @@ jobject GetSplitClassLoader(JNIEnv* env, const char* split_name) {
} // namespace android } // namespace android
} // namespace base } // namespace base
DEFINE_JNI_FOR_JNIUtils()

View file

@ -16,13 +16,9 @@
#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h" #include "base/metrics/histogram_macros.h"
#include "base/system/sys_info.h" #include "base/system/sys_info.h"
#include "build/robolectric_buildflags.h"
#if BUILDFLAG(IS_ROBOLECTRIC) // Must come after all headers that specialize FromJniType() / ToJniType().
#include "base/base_robolectric_jni/LibraryLoader_jni.h" // nogncheck
#else
#include "base/library_loader_jni/LibraryLoader_jni.h" #include "base/library_loader_jni/LibraryLoader_jni.h"
#endif
#if BUILDFLAG(ORDERFILE_INSTRUMENTATION) #if BUILDFLAG(ORDERFILE_INSTRUMENTATION)
#include "base/android/orderfile/orderfile_instrumentation.h" #include "base/android/orderfile/orderfile_instrumentation.h"

View file

@ -2,10 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include <map>
#include "base/android/callback_android.h" #include "base/android/callback_android.h"
#include "base/android/jni_android.h" #include "base/android/jni_android.h"
#include "base/android/jni_array.h" #include "base/android/jni_array.h"
#include "base/android/jni_string.h" #include "base/android/jni_string.h"
#include "base/containers/map_util.h"
#include "base/format_macros.h" #include "base/format_macros.h"
#include "base/metrics/histogram.h" #include "base/metrics/histogram.h"
#include "base/metrics/histogram_base.h" #include "base/metrics/histogram_base.h"
@ -14,14 +17,9 @@
#include "base/metrics/user_metrics.h" #include "base/metrics/user_metrics.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "build/robolectric_buildflags.h"
// Must come after all headers that specialize FromJniType() / ToJniType(). // Must come after all headers that specialize FromJniType() / ToJniType().
#if BUILDFLAG(IS_ROBOLECTRIC)
#include "base/base_robolectric_jni/NativeUmaRecorder_jni.h" // nogncheck
#else
#include "base/metrics_jni/NativeUmaRecorder_jni.h" #include "base/metrics_jni/NativeUmaRecorder_jni.h"
#endif
namespace base { namespace base {
namespace android { namespace android {
@ -29,25 +27,25 @@ namespace android {
namespace { namespace {
using HistogramsSnapshot = using HistogramsSnapshot =
std::map<std::string, std::unique_ptr<HistogramSamples>>; std::map<std::string, std::unique_ptr<HistogramSamples>, std::less<>>;
std::string HistogramConstructionParamsToString(HistogramBase* histogram) { std::string HistogramConstructionParamsToString(HistogramBase* histogram) {
std::string params_str = histogram->histogram_name(); std::string_view name = histogram->histogram_name();
switch (histogram->GetHistogramType()) { switch (histogram->GetHistogramType()) {
case HISTOGRAM: case HISTOGRAM:
case LINEAR_HISTOGRAM: case LINEAR_HISTOGRAM:
case BOOLEAN_HISTOGRAM: case BOOLEAN_HISTOGRAM:
case CUSTOM_HISTOGRAM: { case CUSTOM_HISTOGRAM: {
Histogram* hist = static_cast<Histogram*>(histogram); Histogram* hist = static_cast<Histogram*>(histogram);
params_str += StringPrintf("/%d/%d/%" PRIuS, hist->declared_min(), return StringPrintf("%.*s/%d/%d/%" PRIuS, name.length(), name.data(),
hist->declared_max(), hist->bucket_count()); hist->declared_min(), hist->declared_max(),
break; hist->bucket_count());
} }
case SPARSE_HISTOGRAM: case SPARSE_HISTOGRAM:
case DUMMY_HISTOGRAM: case DUMMY_HISTOGRAM:
break; break;
} }
return params_str; return std::string(name);
} }
// Convert a jlong |histogram_hint| from Java to a HistogramBase* via a cast. // Convert a jlong |histogram_hint| from Java to a HistogramBase* via a cast.
@ -294,7 +292,8 @@ JNI_NativeUmaRecorder_GetHistogramSamplesForTesting(JNIEnv* env,
jlong JNI_NativeUmaRecorder_CreateHistogramSnapshotForTesting(JNIEnv* env) { jlong JNI_NativeUmaRecorder_CreateHistogramSnapshotForTesting(JNIEnv* env) {
HistogramsSnapshot* snapshot = new HistogramsSnapshot(); HistogramsSnapshot* snapshot = new HistogramsSnapshot();
for (const auto* const histogram : StatisticsRecorder::GetHistograms()) { for (const auto* const histogram : StatisticsRecorder::GetHistograms()) {
(*snapshot)[histogram->histogram_name()] = histogram->SnapshotSamples(); InsertOrAssign(*snapshot, histogram->histogram_name(),
histogram->SnapshotSamples());
} }
return reinterpret_cast<intptr_t>(snapshot); return reinterpret_cast<intptr_t>(snapshot);
} }

View file

@ -28,6 +28,7 @@
#include "base/task/thread_pool/thread_pool_instance.h" #include "base/task/thread_pool/thread_pool_instance.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "base/trace_event/base_tracing.h" #include "base/trace_event/base_tracing.h"
#include "base/trace_event/named_trigger.h" // no-presubmit-check
namespace base::android { namespace base::android {
namespace { namespace {
@ -73,8 +74,7 @@ std::string GetPreFreezeMetricName(std::string_view name,
std::string GetSelfCompactionMetricName(std::string_view name, std::string GetSelfCompactionMetricName(std::string_view name,
std::string_view suffix) { std::string_view suffix) {
const char* process_type = GetProcessType(); return StrCat({"Memory.SelfCompact2.Renderer.", name, ".", suffix});
return StrCat({"Memory.SelfCompact2.", process_type, ".", name, ".", suffix});
} }
class PrivateMemoryFootprintMetric class PrivateMemoryFootprintMetric
@ -221,7 +221,7 @@ void PreFreezeBackgroundMemoryTrimmer::RecordMetrics() {
// determine the current process, which is used for the names of metrics // determine the current process, which is used for the names of metrics
// below. // below.
CHECK(base::CommandLine::InitializedForCurrentProcess()); CHECK(base::CommandLine::InitializedForCurrentProcess());
base::AutoLock locker(lock_); base::AutoLock locker(lock());
if (metrics_.size() != values_before_.size()) { if (metrics_.size() != values_before_.size()) {
UmaHistogramEnumeration("Memory.PreFreeze2.RecordMetricsFailureType", UmaHistogramEnumeration("Memory.PreFreeze2.RecordMetricsFailureType",
MetricsFailure::kSizeMismatch); MetricsFailure::kSizeMismatch);
@ -306,7 +306,7 @@ void PreFreezeBackgroundMemoryTrimmer::CompactionMetric::
return; return;
} }
if (!ShouldContinueSelfCompaction(started_at_)) { if (!ShouldContinueSelfCompaction(self_compaction_triggered_at_)) {
return; return;
} }
@ -329,7 +329,7 @@ void PreFreezeBackgroundMemoryTrimmer::CompactionMetric::
void PreFreezeBackgroundMemoryTrimmer::CompactionMetric::RecordSmapsRollup( void PreFreezeBackgroundMemoryTrimmer::CompactionMetric::RecordSmapsRollup(
std::optional<debug::SmapsRollup>* target) { std::optional<debug::SmapsRollup>* target) {
if (!ShouldContinueSelfCompaction(started_at_)) { if (!ShouldContinueSelfCompaction(self_compaction_triggered_at_)) {
return; return;
} }
@ -402,7 +402,7 @@ void PreFreezeBackgroundMemoryTrimmer::PostDelayedBackgroundTaskModern(
return; return;
} }
base::AutoLock locker(lock_); base::AutoLock locker(lock());
PostDelayedBackgroundTaskModernHelper(std::move(task_runner), from_here, PostDelayedBackgroundTaskModernHelper(std::move(task_runner), from_here,
std::move(task), delay); std::move(task), delay);
} }
@ -423,7 +423,7 @@ PreFreezeBackgroundMemoryTrimmer::PostDelayedBackgroundTaskModernHelper(
// static // static
void PreFreezeBackgroundMemoryTrimmer::RegisterMemoryMetric( void PreFreezeBackgroundMemoryTrimmer::RegisterMemoryMetric(
const PreFreezeMetric* metric) { const PreFreezeMetric* metric) {
base::AutoLock locker(Instance().lock_); base::AutoLock locker(lock());
Instance().RegisterMemoryMetricInternal(metric); Instance().RegisterMemoryMetricInternal(metric);
} }
@ -441,7 +441,7 @@ void PreFreezeBackgroundMemoryTrimmer::RegisterMemoryMetricInternal(
// static // static
void PreFreezeBackgroundMemoryTrimmer::UnregisterMemoryMetric( void PreFreezeBackgroundMemoryTrimmer::UnregisterMemoryMetric(
const PreFreezeMetric* metric) { const PreFreezeMetric* metric) {
base::AutoLock locker(Instance().lock_); base::AutoLock locker(lock());
Instance().UnregisterMemoryMetricInternal(metric); Instance().UnregisterMemoryMetricInternal(metric);
} }
@ -457,6 +457,12 @@ void PreFreezeBackgroundMemoryTrimmer::UnregisterMemoryMetricInternal(
metrics_.erase(metrics_.begin() + index); metrics_.erase(metrics_.begin() + index);
} }
void PreFreezeBackgroundMemoryTrimmer::SetOnStartSelfCompactionCallback(
base::RepeatingCallback<void(void)> callback) {
base::AutoLock locker(lock());
Instance().on_self_compact_callback_ = callback;
}
// static // static
bool PreFreezeBackgroundMemoryTrimmer::SelfCompactionIsSupported() { bool PreFreezeBackgroundMemoryTrimmer::SelfCompactionIsSupported() {
return IsMadvisePageoutSupported(); return IsMadvisePageoutSupported();
@ -464,10 +470,10 @@ bool PreFreezeBackgroundMemoryTrimmer::SelfCompactionIsSupported() {
// static // static
bool PreFreezeBackgroundMemoryTrimmer::ShouldContinueSelfCompaction( bool PreFreezeBackgroundMemoryTrimmer::ShouldContinueSelfCompaction(
base::TimeTicks self_compaction_started_at) { base::TimeTicks self_compaction_triggered_at) {
base::AutoLock locker(Instance().lock_); base::AutoLock locker(lock());
return Instance().self_compaction_last_cancelled_ < return Instance().self_compaction_last_cancelled_ <
self_compaction_started_at; self_compaction_triggered_at;
} }
void PreFreezeBackgroundMemoryTrimmer::MaybePostSelfCompactionTask( void PreFreezeBackgroundMemoryTrimmer::MaybePostSelfCompactionTask(
@ -475,19 +481,18 @@ void PreFreezeBackgroundMemoryTrimmer::MaybePostSelfCompactionTask(
std::vector<debug::MappedMemoryRegion> regions, std::vector<debug::MappedMemoryRegion> regions,
scoped_refptr<CompactionMetric> metric, scoped_refptr<CompactionMetric> metric,
uint64_t max_size, uint64_t max_size,
base::TimeTicks started_at) { base::TimeTicks triggered_at) {
TRACE_EVENT0("base", "MaybePostSelfCompactionTask"); TRACE_EVENT0("base", "MaybePostSelfCompactionTask");
if (ShouldContinueSelfCompaction(started_at) && !regions.empty()) { if (ShouldContinueSelfCompaction(triggered_at) && !regions.empty()) {
task_runner->PostDelayedTask( task_runner->PostDelayedTask(
FROM_HERE, FROM_HERE,
// |base::Unretained| is safe here because we never destroy |this|. // |base::Unretained| is safe here because we never destroy |this|.
base::BindOnce(&PreFreezeBackgroundMemoryTrimmer::SelfCompactionTask, base::BindOnce(&PreFreezeBackgroundMemoryTrimmer::SelfCompactionTask,
base::Unretained(this), std::move(task_runner), base::Unretained(this), task_runner, std::move(regions),
std::move(regions), std::move(metric), max_size, std::move(metric), max_size, triggered_at),
started_at),
GetDelayBetweenSelfCompaction()); GetDelayBetweenSelfCompaction());
} else { } else {
FinishSelfCompaction(std::move(metric), started_at); FinishSelfCompaction(std::move(metric), triggered_at);
} }
} }
@ -496,8 +501,8 @@ void PreFreezeBackgroundMemoryTrimmer::SelfCompactionTask(
std::vector<debug::MappedMemoryRegion> regions, std::vector<debug::MappedMemoryRegion> regions,
scoped_refptr<CompactionMetric> metric, scoped_refptr<CompactionMetric> metric,
uint64_t max_size, uint64_t max_size,
base::TimeTicks started_at) { base::TimeTicks triggered_at) {
if (!ShouldContinueSelfCompaction(started_at)) { if (!ShouldContinueSelfCompaction(triggered_at)) {
return; return;
} }
@ -506,33 +511,45 @@ void PreFreezeBackgroundMemoryTrimmer::SelfCompactionTask(
CompactMemory(&regions, max_size); CompactMemory(&regions, max_size);
MaybePostSelfCompactionTask(std::move(task_runner), std::move(regions), MaybePostSelfCompactionTask(std::move(task_runner), std::move(regions),
std::move(metric), max_size, started_at); std::move(metric), max_size, triggered_at);
} }
void PreFreezeBackgroundMemoryTrimmer::StartSelfCompaction( void PreFreezeBackgroundMemoryTrimmer::StartSelfCompaction(
scoped_refptr<base::SequencedTaskRunner> task_runner, scoped_refptr<base::SequencedTaskRunner> task_runner,
std::vector<debug::MappedMemoryRegion> regions, std::vector<debug::MappedMemoryRegion> regions,
scoped_refptr<CompactionMetric> metric,
uint64_t max_bytes, uint64_t max_bytes,
base::TimeTicks started_at) { base::TimeTicks triggered_at) {
scoped_refptr<CompactionMetric> metric =
MakeRefCounted<CompactionMetric>(triggered_at, base::TimeTicks::Now());
TRACE_EVENT0("base", "StartSelfCompaction"); TRACE_EVENT0("base", "StartSelfCompaction");
base::trace_event::EmitNamedTrigger("start-self-compaction");
{ {
base::AutoLock locker(lock_); base::AutoLock locker(lock());
process_compacted_metadata_.emplace( process_compacted_metadata_.emplace(
"PreFreezeBackgroundMemoryTrimmer.ProcessCompacted", "PreFreezeBackgroundMemoryTrimmer.ProcessCompacted",
/*is_compacted=*/1, base::SampleMetadataScope::kProcess); /*is_compacted=*/1, base::SampleMetadataScope::kProcess);
if (on_self_compact_callback_) {
on_self_compact_callback_.Run();
}
} }
metric->RecordBeforeMetrics(); metric->RecordBeforeMetrics();
MaybePostSelfCompactionTask(std::move(task_runner), std::move(regions), MaybePostSelfCompactionTask(std::move(task_runner), std::move(regions),
std::move(metric), max_bytes, started_at); std::move(metric), max_bytes, triggered_at);
} }
void PreFreezeBackgroundMemoryTrimmer::FinishSelfCompaction( void PreFreezeBackgroundMemoryTrimmer::FinishSelfCompaction(
scoped_refptr<CompactionMetric> metric, scoped_refptr<CompactionMetric> metric,
base::TimeTicks started_at) { base::TimeTicks triggered_at) {
TRACE_EVENT0("base", "FinishSelfCompaction"); TRACE_EVENT0("base", "FinishSelfCompaction");
if (ShouldContinueSelfCompaction(started_at)) { {
base::AutoLock locker(lock());
self_compaction_last_finished_ = base::TimeTicks::Now();
}
if (ShouldContinueSelfCompaction(triggered_at)) {
metric->RecordDelayedMetrics(); metric->RecordDelayedMetrics();
base::AutoLock locker(lock());
metric->RecordTimeMetrics(self_compaction_last_finished_,
self_compaction_last_cancelled_);
} }
} }
@ -545,24 +562,41 @@ PreFreezeBackgroundMemoryTrimmer::GetDelayBetweenSelfCompaction() {
} }
// static // static
void PreFreezeBackgroundMemoryTrimmer::MaybeCancelSelfCompaction() { void PreFreezeBackgroundMemoryTrimmer::MaybeCancelSelfCompaction(
Instance().MaybeCancelSelfCompactionInternal(); SelfCompactCancellationReason cancellation_reason) {
Instance().MaybeCancelSelfCompactionInternal(cancellation_reason);
} }
void PreFreezeBackgroundMemoryTrimmer::MaybeCancelSelfCompactionInternal() { void PreFreezeBackgroundMemoryTrimmer::MaybeCancelSelfCompactionInternal(
base::AutoLock locker(lock_); SelfCompactCancellationReason cancellation_reason) {
base::AutoLock locker(lock());
process_compacted_metadata_.reset(); process_compacted_metadata_.reset();
self_compaction_last_cancelled_ = base::TimeTicks::Now(); // Check for the last time cancelled here in order to avoid recording this
// metric multiple times. Also, only record this metric if a compaction is
// currently running.
if (self_compaction_last_cancelled_ < self_compaction_last_triggered_ &&
self_compaction_last_finished_ < self_compaction_last_triggered_) {
UmaHistogramEnumeration("Memory.SelfCompact2.Renderer.CancellationReason2",
cancellation_reason);
}
self_compaction_last_finished_ = self_compaction_last_cancelled_ =
base::TimeTicks::Now();
} }
// static // static
void PreFreezeBackgroundMemoryTrimmer::CompactSelf() { void PreFreezeBackgroundMemoryTrimmer::CompactSelf(
scoped_refptr<base::SequencedTaskRunner> task_runner,
base::TimeTicks triggered_at) {
// MADV_PAGEOUT was only added in Linux 5.4, so do nothing in earlier // MADV_PAGEOUT was only added in Linux 5.4, so do nothing in earlier
// versions. // versions.
if (!SelfCompactionIsSupported()) { if (!SelfCompactionIsSupported()) {
return; return;
} }
if (!ShouldContinueSelfCompaction(triggered_at)) {
return;
}
TRACE_EVENT0("base", "CompactSelf"); TRACE_EVENT0("base", "CompactSelf");
std::vector<debug::MappedMemoryRegion> regions; std::vector<debug::MappedMemoryRegion> regions;
@ -579,28 +613,29 @@ void PreFreezeBackgroundMemoryTrimmer::CompactSelf() {
} }
} }
auto started_at = base::TimeTicks::Now(); Instance().StartSelfCompaction(std::move(task_runner), std::move(regions),
Instance().StartSelfCompaction( MiBToBytes(kShouldFreezeSelfMaxSize.Get()),
base::ThreadPool::CreateSequencedTaskRunner( triggered_at);
{base::TaskPriority::BEST_EFFORT, MayBlock()}),
std::move(regions), MakeRefCounted<CompactionMetric>(started_at),
MiBToBytes(kShouldFreezeSelfMaxSize.Get()), started_at);
} }
// static // static
std::optional<uint64_t> PreFreezeBackgroundMemoryTrimmer::CompactRegion( std::optional<uint64_t> PreFreezeBackgroundMemoryTrimmer::CompactRegion(
debug::MappedMemoryRegion region) { debug::MappedMemoryRegion region) {
#if defined(MADV_PAGEOUT) #if defined(MADV_PAGEOUT)
using Permission = debug::MappedMemoryRegion::Permission;
// Skip file-backed regions // Skip file-backed regions
if (region.inode != 0 || region.dev_major != 0) { if (region.inode != 0 || region.dev_major != 0) {
return 0; return 0;
} }
// Skip shared regions // Skip shared regions
if ((region.permissions & debug::MappedMemoryRegion::Permission::PRIVATE) == if ((region.permissions & Permission::PRIVATE) == 0) {
0) {
return 0; return 0;
} }
const bool is_inaccessible =
(region.permissions &
(Permission::READ | Permission::WRITE | Permission::EXECUTE)) == 0;
TRACE_EVENT1("base", __PRETTY_FUNCTION__, "size", region.end - region.start); TRACE_EVENT1("base", __PRETTY_FUNCTION__, "size", region.end - region.start);
int error = madvise(reinterpret_cast<void*>(region.start), int error = madvise(reinterpret_cast<void*>(region.start),
@ -621,7 +656,7 @@ std::optional<uint64_t> PreFreezeBackgroundMemoryTrimmer::CompactRegion(
return 0; return 0;
} }
return region.end - region.start; return is_inaccessible ? 0 : region.end - region.start;
#else #else
return std::nullopt; return std::nullopt;
#endif #endif
@ -659,19 +694,23 @@ void PreFreezeBackgroundMemoryTrimmer::PostMetricsTasksIfModern() {
void PreFreezeBackgroundMemoryTrimmer::OnSelfFreeze() { void PreFreezeBackgroundMemoryTrimmer::OnSelfFreeze() {
TRACE_EVENT0("base", "OnSelfFreeze"); TRACE_EVENT0("base", "OnSelfFreeze");
Instance().OnSelfFreezeInternal(); auto task_runner = base::ThreadPool::CreateSequencedTaskRunner(
{base::TaskPriority::BEST_EFFORT, MayBlock()});
Instance().OnSelfFreezeInternal(std::move(task_runner));
} }
void PreFreezeBackgroundMemoryTrimmer::OnSelfFreezeInternal() { void PreFreezeBackgroundMemoryTrimmer::OnSelfFreezeInternal(
base::AutoLock locker(lock_); scoped_refptr<SequencedTaskRunner> task_runner) {
const auto triggered_at = base::TimeTicks::Now();
base::AutoLock locker(lock());
self_compaction_last_triggered_ = triggered_at;
if (base::FeatureList::IsEnabled(kShouldFreezeSelf)) { if (base::FeatureList::IsEnabled(kShouldFreezeSelf)) {
RunPreFreezeTasks(); RunPreFreezeTasks();
} }
task_runner->PostDelayedTask(
base::ThreadPool::PostDelayedTask( FROM_HERE,
FROM_HERE, {base::TaskPriority::BEST_EFFORT, MayBlock()},
base::BindOnce(&PreFreezeBackgroundMemoryTrimmer::CompactSelf, base::BindOnce(&PreFreezeBackgroundMemoryTrimmer::CompactSelf,
base::Unretained(this)), base::Unretained(this), task_runner, triggered_at),
base::Seconds(kShouldFreezeSelfDelayAfterPreFreezeTasks.Get())); base::Seconds(kShouldFreezeSelfDelayAfterPreFreezeTasks.Get()));
} }
@ -680,7 +719,7 @@ void PreFreezeBackgroundMemoryTrimmer::OnPreFreeze() {
// If we have scheduled a self compaction task, cancel it, since App Freezer // If we have scheduled a self compaction task, cancel it, since App Freezer
// will handle the compaction for us, and we don't want to potentially run // will handle the compaction for us, and we don't want to potentially run
// self compaction after we have resumed. // self compaction after we have resumed.
MaybeCancelSelfCompaction(); MaybeCancelSelfCompaction(SelfCompactCancellationReason::kAppFreezer);
Instance().OnPreFreezeInternal(); Instance().OnPreFreezeInternal();
} }
@ -705,13 +744,13 @@ void PreFreezeBackgroundMemoryTrimmer::RunPreFreezeTasks() {
// (1) To avoid holding it too long while running all the background tasks. // (1) To avoid holding it too long while running all the background tasks.
// (2) To prevent a deadlock if the |background_task| needs to acquire the // (2) To prevent a deadlock if the |background_task| needs to acquire the
// lock (e.g. to post another task). // lock (e.g. to post another task).
base::AutoUnlock unlocker(lock_); base::AutoUnlock unlocker(lock());
BackgroundTask::RunNow(std::move(background_task)); BackgroundTask::RunNow(std::move(background_task));
} }
} }
void PreFreezeBackgroundMemoryTrimmer::OnPreFreezeInternal() { void PreFreezeBackgroundMemoryTrimmer::OnPreFreezeInternal() {
base::AutoLock locker(lock_); base::AutoLock locker(lock());
PostMetricsTasksIfModern(); PostMetricsTasksIfModern();
if (!ShouldUseModernTrim()) { if (!ShouldUseModernTrim()) {
@ -729,13 +768,13 @@ void PreFreezeBackgroundMemoryTrimmer::UnregisterBackgroundTask(
void PreFreezeBackgroundMemoryTrimmer::UnregisterBackgroundTaskInternal( void PreFreezeBackgroundMemoryTrimmer::UnregisterBackgroundTaskInternal(
BackgroundTask* timer) { BackgroundTask* timer) {
base::AutoLock locker(lock_); base::AutoLock locker(lock());
std::erase_if(background_tasks_, [&](auto& t) { return t.get() == timer; }); std::erase_if(background_tasks_, [&](auto& t) { return t.get() == timer; });
} }
// static // static
void PreFreezeBackgroundMemoryTrimmer::RegisterPrivateMemoryFootprintMetric() { void PreFreezeBackgroundMemoryTrimmer::RegisterPrivateMemoryFootprintMetric() {
base::AutoLock locker(Instance().lock_); base::AutoLock locker(lock());
static base::NoDestructor<PrivateMemoryFootprintMetric> pmf_metric; static base::NoDestructor<PrivateMemoryFootprintMetric> pmf_metric;
if (!PrivateMemoryFootprintMetric::did_register_) { if (!PrivateMemoryFootprintMetric::did_register_) {
PrivateMemoryFootprintMetric::did_register_ = true; PrivateMemoryFootprintMetric::did_register_ = true;
@ -766,40 +805,41 @@ void PreFreezeBackgroundMemoryTrimmer::SetSupportsModernTrimForTesting(
// static // static
void PreFreezeBackgroundMemoryTrimmer::ClearMetricsForTesting() { void PreFreezeBackgroundMemoryTrimmer::ClearMetricsForTesting() {
base::AutoLock locker(Instance().lock_); base::AutoLock locker(lock());
Instance().metrics_.clear(); Instance().metrics_.clear();
PrivateMemoryFootprintMetric::did_register_ = false; PrivateMemoryFootprintMetric::did_register_ = false;
} }
bool PreFreezeBackgroundMemoryTrimmer::DidRegisterTasksForTesting() const { bool PreFreezeBackgroundMemoryTrimmer::DidRegisterTasksForTesting() const {
base::AutoLock locker(lock_); base::AutoLock locker(lock());
return metrics_.size() != 0; return metrics_.size() != 0;
} }
size_t size_t
PreFreezeBackgroundMemoryTrimmer::GetNumberOfPendingBackgroundTasksForTesting() PreFreezeBackgroundMemoryTrimmer::GetNumberOfPendingBackgroundTasksForTesting()
const { const {
base::AutoLock locker(lock_); base::AutoLock locker(lock());
return background_tasks_.size(); return background_tasks_.size();
} }
size_t PreFreezeBackgroundMemoryTrimmer::GetNumberOfKnownMetricsForTesting() size_t PreFreezeBackgroundMemoryTrimmer::GetNumberOfKnownMetricsForTesting()
const { const {
base::AutoLock locker(lock_); base::AutoLock locker(lock());
return metrics_.size(); return metrics_.size();
} }
size_t PreFreezeBackgroundMemoryTrimmer::GetNumberOfValuesBeforeForTesting() size_t PreFreezeBackgroundMemoryTrimmer::GetNumberOfValuesBeforeForTesting()
const { const {
base::AutoLock locker(lock_); base::AutoLock locker(lock());
return values_before_.size(); return values_before_.size();
} }
// static // static
void PreFreezeBackgroundMemoryTrimmer:: void PreFreezeBackgroundMemoryTrimmer::ResetSelfCompactionForTesting() {
ResetSelfCompactionLastCancelledForTesting() { base::AutoLock locker(lock());
base::AutoLock locker(Instance().lock_);
Instance().self_compaction_last_cancelled_ = base::TimeTicks::Min(); Instance().self_compaction_last_cancelled_ = base::TimeTicks::Min();
Instance().self_compaction_last_finished_ = base::TimeTicks::Min();
Instance().self_compaction_last_triggered_ = base::TimeTicks::Min();
} }
// static // static
@ -879,8 +919,10 @@ PreFreezeBackgroundMemoryTrimmer::PreFreezeMetric::PreFreezeMetric(
PreFreezeBackgroundMemoryTrimmer::PreFreezeMetric::~PreFreezeMetric() = default; PreFreezeBackgroundMemoryTrimmer::PreFreezeMetric::~PreFreezeMetric() = default;
PreFreezeBackgroundMemoryTrimmer::CompactionMetric::CompactionMetric( PreFreezeBackgroundMemoryTrimmer::CompactionMetric::CompactionMetric(
base::TimeTicks triggered_at,
base::TimeTicks started_at) base::TimeTicks started_at)
: started_at_(started_at) {} : self_compaction_triggered_at_(triggered_at),
self_compaction_started_at_(started_at) {}
PreFreezeBackgroundMemoryTrimmer::CompactionMetric::~CompactionMetric() = PreFreezeBackgroundMemoryTrimmer::CompactionMetric::~CompactionMetric() =
default; default;
@ -896,4 +938,13 @@ void PreFreezeBackgroundMemoryTrimmer::CompactionMetric::
RecordSmapsRollupWithDelay(&smaps_after_60s_, base::Seconds(60)); RecordSmapsRollupWithDelay(&smaps_after_60s_, base::Seconds(60));
} }
void PreFreezeBackgroundMemoryTrimmer::CompactionMetric::RecordTimeMetrics(
base::TimeTicks last_finished,
base::TimeTicks last_cancelled) {
UmaHistogramMediumTimes("Memory.SelfCompact2.Renderer.SelfCompactionTime",
last_finished - self_compaction_started_at_);
UmaHistogramMediumTimes("Memory.SelfCompact2.Renderer.TimeSinceLastCancel",
last_finished - last_cancelled);
}
} // namespace base::android } // namespace base::android

View file

@ -35,6 +35,14 @@ BASE_EXPORT BASE_DECLARE_FEATURE(kShouldFreezeSelf);
// be frozen. // be frozen.
class BASE_EXPORT PreFreezeBackgroundMemoryTrimmer { class BASE_EXPORT PreFreezeBackgroundMemoryTrimmer {
public: public:
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class SelfCompactCancellationReason {
kAppFreezer,
kPageResumed,
kMaxValue = kPageResumed
};
static PreFreezeBackgroundMemoryTrimmer& Instance(); static PreFreezeBackgroundMemoryTrimmer& Instance();
~PreFreezeBackgroundMemoryTrimmer() = delete; ~PreFreezeBackgroundMemoryTrimmer() = delete;
@ -45,7 +53,7 @@ class BASE_EXPORT PreFreezeBackgroundMemoryTrimmer {
scoped_refptr<base::SequencedTaskRunner> task_runner, scoped_refptr<base::SequencedTaskRunner> task_runner,
const base::Location& from_here, const base::Location& from_here,
OnceCallback<void(void)> task, OnceCallback<void(void)> task,
base::TimeDelta delay) LOCKS_EXCLUDED(lock_) { base::TimeDelta delay) LOCKS_EXCLUDED(lock()) {
PostDelayedBackgroundTask( PostDelayedBackgroundTask(
task_runner, from_here, task_runner, from_here,
BindOnce( BindOnce(
@ -60,7 +68,7 @@ class BASE_EXPORT PreFreezeBackgroundMemoryTrimmer {
scoped_refptr<base::SequencedTaskRunner> task_runner, scoped_refptr<base::SequencedTaskRunner> task_runner,
const base::Location& from_here, const base::Location& from_here,
OnceCallback<void(MemoryReductionTaskContext)> task, OnceCallback<void(MemoryReductionTaskContext)> task,
base::TimeDelta delay) LOCKS_EXCLUDED(lock_); base::TimeDelta delay) LOCKS_EXCLUDED(lock());
class PreFreezeMetric { class PreFreezeMetric {
public: public:
@ -102,38 +110,47 @@ class BASE_EXPORT PreFreezeBackgroundMemoryTrimmer {
// See "Memory.PreFreeze2.{process_type}.{name}.{suffix}" for details on the // See "Memory.PreFreeze2.{process_type}.{name}.{suffix}" for details on the
// exact metrics. // exact metrics.
static void RegisterMemoryMetric(const PreFreezeMetric* metric) static void RegisterMemoryMetric(const PreFreezeMetric* metric)
LOCKS_EXCLUDED(Instance().lock_); LOCKS_EXCLUDED(lock());
static void UnregisterMemoryMetric(const PreFreezeMetric* metric) static void UnregisterMemoryMetric(const PreFreezeMetric* metric)
LOCKS_EXCLUDED(Instance().lock_); LOCKS_EXCLUDED(lock());
// The callback runs in the thread pool. The caller cannot make any thread
// safety assumptions for the callback execution (e.g. it could run
// concurrently with the thread that registered it).
static void SetOnStartSelfCompactionCallback(base::RepeatingClosure callback)
LOCKS_EXCLUDED(lock());
static bool SelfCompactionIsSupported(); static bool SelfCompactionIsSupported();
// Compacts the memory for the process. // Compacts the memory for the process.
void CompactSelf(); void CompactSelf(scoped_refptr<SequencedTaskRunner> task_runner,
base::TimeTicks triggered_at);
// If we are currently running self compaction, cancel it. // If we are currently running self compaction, cancel it. If it was running,
static void MaybeCancelSelfCompaction(); // record a metric with the reason for the cancellation.
static void MaybeCancelSelfCompaction(
SelfCompactCancellationReason cancellation_reason);
static void SetSupportsModernTrimForTesting(bool is_supported); static void SetSupportsModernTrimForTesting(bool is_supported);
static void ClearMetricsForTesting() LOCKS_EXCLUDED(lock_); static void ClearMetricsForTesting() LOCKS_EXCLUDED(lock());
size_t GetNumberOfPendingBackgroundTasksForTesting() const size_t GetNumberOfPendingBackgroundTasksForTesting() const
LOCKS_EXCLUDED(lock_); LOCKS_EXCLUDED(lock());
size_t GetNumberOfKnownMetricsForTesting() const LOCKS_EXCLUDED(lock_); size_t GetNumberOfKnownMetricsForTesting() const LOCKS_EXCLUDED(lock());
size_t GetNumberOfValuesBeforeForTesting() const LOCKS_EXCLUDED(lock_); size_t GetNumberOfValuesBeforeForTesting() const LOCKS_EXCLUDED(lock());
bool DidRegisterTasksForTesting() const; bool DidRegisterTasksForTesting() const;
static void OnPreFreezeForTesting() LOCKS_EXCLUDED(lock_) { OnPreFreeze(); } static void OnPreFreezeForTesting() LOCKS_EXCLUDED(lock()) { OnPreFreeze(); }
static void ResetSelfCompactionLastCancelledForTesting(); static void ResetSelfCompactionForTesting();
static std::optional<uint64_t> CompactRegion( static std::optional<uint64_t> CompactRegion(
debug::MappedMemoryRegion region); debug::MappedMemoryRegion region);
// Called when Chrome is about to be frozen. Runs as many delayed tasks as // Called when Chrome is about to be frozen. Runs as many delayed tasks as
// possible immediately, before we are frozen. // possible immediately, before we are frozen.
static void OnPreFreeze() LOCKS_EXCLUDED(lock_); static void OnPreFreeze() LOCKS_EXCLUDED(lock());
static void OnSelfFreeze() LOCKS_EXCLUDED(lock_); static void OnSelfFreeze() LOCKS_EXCLUDED(lock());
static bool SupportsModernTrim(); static bool SupportsModernTrim();
static bool ShouldUseModernTrim(); static bool ShouldUseModernTrim();
@ -149,6 +166,7 @@ class BASE_EXPORT PreFreezeBackgroundMemoryTrimmer {
friend class PreFreezeSelfCompactionTest; friend class PreFreezeSelfCompactionTest;
FRIEND_TEST_ALL_PREFIXES(PreFreezeSelfCompactionTest, Cancel); FRIEND_TEST_ALL_PREFIXES(PreFreezeSelfCompactionTest, Cancel);
FRIEND_TEST_ALL_PREFIXES(PreFreezeSelfCompactionTest, NotCanceled); FRIEND_TEST_ALL_PREFIXES(PreFreezeSelfCompactionTest, NotCanceled);
FRIEND_TEST_ALL_PREFIXES(PreFreezeSelfCompactionTest, OnSelfFreezeCancel);
// We use our own implementation here, based on |PostCancelableDelayedTask|, // We use our own implementation here, based on |PostCancelableDelayedTask|,
// rather than relying on something like |base::OneShotTimer|, since // rather than relying on something like |base::OneShotTimer|, since
@ -190,20 +208,30 @@ class BASE_EXPORT PreFreezeBackgroundMemoryTrimmer {
private: private:
class CompactionMetric : public RefCountedThreadSafe<CompactionMetric> { class CompactionMetric : public RefCountedThreadSafe<CompactionMetric> {
public: public:
explicit CompactionMetric(base::TimeTicks started_at); CompactionMetric(base::TimeTicks triggered_at, base::TimeTicks started_at);
void RecordDelayedMetrics(); void RecordDelayedMetrics();
void RecordTimeMetrics(base::TimeTicks self_compaction_last_finished,
base::TimeTicks self_compaction_last_cancelled);
void RecordBeforeMetrics(); void RecordBeforeMetrics();
void MaybeRecordCompactionMetrics(); void MaybeRecordCompactionMetrics() LOCKS_EXCLUDED(lock());
private: private:
friend class RefCountedThreadSafe<CompactionMetric>; friend class RefCountedThreadSafe<CompactionMetric>;
~CompactionMetric(); ~CompactionMetric();
void RecordSmapsRollup(std::optional<debug::SmapsRollup>* target); void RecordSmapsRollup(std::optional<debug::SmapsRollup>* target)
LOCKS_EXCLUDED(lock());
void RecordSmapsRollupWithDelay(std::optional<debug::SmapsRollup>* target, void RecordSmapsRollupWithDelay(std::optional<debug::SmapsRollup>* target,
base::TimeDelta delay); base::TimeDelta delay);
base::TimeTicks started_at_; // When the self compaction was first triggered. There is a delay between
// this time and when we actually begin the compaction.
base::TimeTicks self_compaction_triggered_at_;
// When the self compaction first started. This should generally be
// |self_compaction_triggered_at_ +
// kShouldFreezeSelfDelayAfterPreFreezeTasks.Get()|, but may be longer if
// the task was delayed.
base::TimeTicks self_compaction_started_at_;
// We use std::optional here because: // We use std::optional here because:
// - We record these incrementally. // - We record these incrementally.
// - We may stop recording at some point. // - We may stop recording at some point.
@ -217,84 +245,84 @@ class BASE_EXPORT PreFreezeBackgroundMemoryTrimmer {
PreFreezeBackgroundMemoryTrimmer(); PreFreezeBackgroundMemoryTrimmer();
static base::Lock& lock() { return Instance().lock_; }
void StartSelfCompaction(scoped_refptr<base::SequencedTaskRunner> task_runner, void StartSelfCompaction(scoped_refptr<base::SequencedTaskRunner> task_runner,
std::vector<debug::MappedMemoryRegion> regions, std::vector<debug::MappedMemoryRegion> regions,
scoped_refptr<CompactionMetric> metric,
uint64_t max_size, uint64_t max_size,
base::TimeTicks started_at); base::TimeTicks triggered_at) LOCKS_EXCLUDED(lock());
static base::TimeDelta GetDelayBetweenSelfCompaction(); static base::TimeDelta GetDelayBetweenSelfCompaction();
void MaybePostSelfCompactionTask( void MaybePostSelfCompactionTask(
scoped_refptr<base::SequencedTaskRunner> task_runner, scoped_refptr<base::SequencedTaskRunner> task_runner,
std::vector<debug::MappedMemoryRegion> regions, std::vector<debug::MappedMemoryRegion> regions,
scoped_refptr<CompactionMetric> metric, scoped_refptr<CompactionMetric> metric,
uint64_t max_size, uint64_t max_size,
base::TimeTicks started_at); base::TimeTicks triggered_at) LOCKS_EXCLUDED(lock());
void SelfCompactionTask(scoped_refptr<base::SequencedTaskRunner> task_runner, void SelfCompactionTask(scoped_refptr<base::SequencedTaskRunner> task_runner,
std::vector<debug::MappedMemoryRegion> regions, std::vector<debug::MappedMemoryRegion> regions,
scoped_refptr<CompactionMetric> metric, scoped_refptr<CompactionMetric> metric,
uint64_t max_size, uint64_t max_size,
base::TimeTicks started_at); base::TimeTicks triggered_at) LOCKS_EXCLUDED(lock());
void FinishSelfCompaction(scoped_refptr<CompactionMetric> metric, void FinishSelfCompaction(scoped_refptr<CompactionMetric> metric,
base::TimeTicks started_at); base::TimeTicks triggered_at)
LOCKS_EXCLUDED(lock());
static bool ShouldContinueSelfCompaction( static bool ShouldContinueSelfCompaction(
base::TimeTicks compaction_started_at) LOCKS_EXCLUDED(Instance().lock_); base::TimeTicks self_compaction_triggered_at) LOCKS_EXCLUDED(lock());
static std::optional<uint64_t> CompactMemory( static std::optional<uint64_t> CompactMemory(
std::vector<debug::MappedMemoryRegion>* regions, std::vector<debug::MappedMemoryRegion>* regions,
const uint64_t max_bytes); const uint64_t max_bytes);
void RegisterMemoryMetricInternal(const PreFreezeMetric* metric) void RegisterMemoryMetricInternal(const PreFreezeMetric* metric)
EXCLUSIVE_LOCKS_REQUIRED(lock_); EXCLUSIVE_LOCKS_REQUIRED(lock());
void UnregisterMemoryMetricInternal(const PreFreezeMetric* metric) void UnregisterMemoryMetricInternal(const PreFreezeMetric* metric)
EXCLUSIVE_LOCKS_REQUIRED(lock_); EXCLUSIVE_LOCKS_REQUIRED(lock());
static void UnregisterBackgroundTask(BackgroundTask*) LOCKS_EXCLUDED(lock_); static void UnregisterBackgroundTask(BackgroundTask*) LOCKS_EXCLUDED(lock());
void UnregisterBackgroundTaskInternal(BackgroundTask*) LOCKS_EXCLUDED(lock_); void UnregisterBackgroundTaskInternal(BackgroundTask*) LOCKS_EXCLUDED(lock());
static void RegisterPrivateMemoryFootprintMetric() LOCKS_EXCLUDED(lock_); static void RegisterPrivateMemoryFootprintMetric() LOCKS_EXCLUDED(lock());
void RegisterPrivateMemoryFootprintMetricInternal() LOCKS_EXCLUDED(lock_); void RegisterPrivateMemoryFootprintMetricInternal() LOCKS_EXCLUDED(lock());
void PostDelayedBackgroundTaskInternal( void PostDelayedBackgroundTaskInternal(
scoped_refptr<base::SequencedTaskRunner> task_runner, scoped_refptr<base::SequencedTaskRunner> task_runner,
const base::Location& from_here, const base::Location& from_here,
OnceCallback<void(MemoryReductionTaskContext)> task, OnceCallback<void(MemoryReductionTaskContext)> task,
base::TimeDelta delay) LOCKS_EXCLUDED(lock_); base::TimeDelta delay) LOCKS_EXCLUDED(lock());
void PostDelayedBackgroundTaskModern( void PostDelayedBackgroundTaskModern(
scoped_refptr<base::SequencedTaskRunner> task_runner, scoped_refptr<base::SequencedTaskRunner> task_runner,
const base::Location& from_here, const base::Location& from_here,
OnceCallback<void(MemoryReductionTaskContext)> task, OnceCallback<void(MemoryReductionTaskContext)> task,
base::TimeDelta delay) LOCKS_EXCLUDED(lock_); base::TimeDelta delay) LOCKS_EXCLUDED(lock());
BackgroundTask* PostDelayedBackgroundTaskModernHelper( BackgroundTask* PostDelayedBackgroundTaskModernHelper(
scoped_refptr<base::SequencedTaskRunner> task_runner, scoped_refptr<base::SequencedTaskRunner> task_runner,
const base::Location& from_here, const base::Location& from_here,
OnceCallback<void(MemoryReductionTaskContext)> task, OnceCallback<void(MemoryReductionTaskContext)> task,
base::TimeDelta delay) EXCLUSIVE_LOCKS_REQUIRED(lock_); base::TimeDelta delay) EXCLUSIVE_LOCKS_REQUIRED(lock());
void OnPreFreezeInternal() LOCKS_EXCLUDED(lock_); void OnPreFreezeInternal() LOCKS_EXCLUDED(lock());
void RunPreFreezeTasks() EXCLUSIVE_LOCKS_REQUIRED(lock_); void RunPreFreezeTasks() EXCLUSIVE_LOCKS_REQUIRED(lock());
void OnSelfFreezeInternal(); void OnSelfFreezeInternal(scoped_refptr<SequencedTaskRunner> task_runner);
void MaybeCancelSelfCompactionInternal() LOCKS_EXCLUDED(lock_); void MaybeCancelSelfCompactionInternal(
SelfCompactCancellationReason cancellation_reason) LOCKS_EXCLUDED(lock());
void PostMetricsTasksIfModern() EXCLUSIVE_LOCKS_REQUIRED(lock_); void PostMetricsTasksIfModern() EXCLUSIVE_LOCKS_REQUIRED(lock());
void PostMetricsTask() EXCLUSIVE_LOCKS_REQUIRED(lock_); void PostMetricsTask() EXCLUSIVE_LOCKS_REQUIRED(lock());
void RecordMetrics() LOCKS_EXCLUDED(lock_); void RecordMetrics() LOCKS_EXCLUDED(lock());
void RecordSmapsRollup(std::optional<debug::SmapsRollup>* target,
base::TimeTicks started_at);
mutable base::Lock lock_; mutable base::Lock lock_;
std::deque<std::unique_ptr<BackgroundTask>> background_tasks_ std::deque<std::unique_ptr<BackgroundTask>> background_tasks_
GUARDED_BY(lock_); GUARDED_BY(lock());
std::vector<const PreFreezeMetric*> metrics_ GUARDED_BY(lock_); std::vector<const PreFreezeMetric*> metrics_ GUARDED_BY(lock());
// When a metrics task is posted (see |RecordMetrics|), the values of each // When a metrics task is posted (see |RecordMetrics|), the values of each
// metric before any tasks are run are saved here. The "i"th entry corresponds // metric before any tasks are run are saved here. The "i"th entry corresponds
// to the "i"th entry in |metrics_|. When there is no pending metrics task, // to the "i"th entry in |metrics_|. When there is no pending metrics task,
// |values_before_| should be empty. // |values_before_| should be empty.
std::vector<std::optional<uint64_t>> values_before_ GUARDED_BY(lock_); std::vector<std::optional<uint64_t>> values_before_ GUARDED_BY(lock());
// Whether or not we should continue self compaction. There are two reasons // Whether or not we should continue self compaction. There are two reasons
// why we would cancel: // why we would cancel:
// (1) We have resumed, meaning we are likely to touch much of the process // (1) We have resumed, meaning we are likely to touch much of the process
@ -304,10 +332,18 @@ class BASE_EXPORT PreFreezeBackgroundMemoryTrimmer {
// work for us. This situation should be relatively rare, because we // work for us. This situation should be relatively rare, because we
// attempt to not do self compaction if we know that we are going to // attempt to not do self compaction if we know that we are going to
// frozen by App Freezer. // frozen by App Freezer.
base::TimeTicks self_compaction_last_cancelled_ GUARDED_BY(lock_) = base::TimeTicks self_compaction_last_cancelled_ GUARDED_BY(lock()) =
base::TimeTicks::Min();
// When we last triggered self compaction. Used to record metrics.
base::TimeTicks self_compaction_last_triggered_ GUARDED_BY(lock()) =
base::TimeTicks::Min();
// When we last finished self compaction (either successfully, or from
// being cancelled). Used to record metrics.
base::TimeTicks self_compaction_last_finished_ GUARDED_BY(lock()) =
base::TimeTicks::Min(); base::TimeTicks::Min();
std::optional<base::ScopedSampleMetadata> process_compacted_metadata_ std::optional<base::ScopedSampleMetadata> process_compacted_metadata_
GUARDED_BY(lock_); GUARDED_BY(lock());
base::RepeatingClosure on_self_compact_callback_ GUARDED_BY(lock());
bool supports_modern_trim_; bool supports_modern_trim_;
}; };

View file

@ -4,15 +4,8 @@
#include "base/android/token_android.h" #include "base/android/token_android.h"
#include "build/robolectric_buildflags.h" #include "base/base_minimal_jni/TokenBase_jni.h"
#include "base/base_minimal_jni/Token_jni.h"
#if BUILDFLAG(IS_ROBOLECTRIC)
#include "base/base_robolectric_jni/TokenBase_jni.h" // nogncheck
#include "base/base_robolectric_jni/Token_jni.h" // nogncheck
#else
#include "base/base_jni/TokenBase_jni.h"
#include "base/base_jni/Token_jni.h"
#endif
namespace base::android { namespace base::android {
@ -36,3 +29,5 @@ static base::Token JNI_Token_CreateRandom(JNIEnv* env) {
} }
} // namespace base::android } // namespace base::android
DEFINE_JNI_FOR_Token()

View file

@ -13,13 +13,6 @@
#include "base/metrics/histogram_macros.h" #include "base/metrics/histogram_macros.h"
#include "base/trace_event/base_tracing.h" #include "base/trace_event/base_tracing.h"
#include "base/tracing_buildflags.h" #include "base/tracing_buildflags.h"
#include "build/robolectric_buildflags.h"
#if BUILDFLAG(IS_ROBOLECTRIC)
#include "base/base_robolectric_jni/TraceEvent_jni.h" // nogncheck
#else
#include "base/tasks_jni/TraceEvent_jni.h"
#endif
#if BUILDFLAG(ENABLE_BASE_TRACING) #if BUILDFLAG(ENABLE_BASE_TRACING)
#include "base/trace_event/trace_event_impl.h" // no-presubmit-check #include "base/trace_event/trace_event_impl.h" // no-presubmit-check
@ -27,6 +20,9 @@
#include "third_party/perfetto/protos/perfetto/config/chrome/chrome_config.gen.h" // nogncheck #include "third_party/perfetto/protos/perfetto/config/chrome/chrome_config.gen.h" // nogncheck
#endif // BUILDFLAG(ENABLE_BASE_TRACING) #endif // BUILDFLAG(ENABLE_BASE_TRACING)
// Must come after all headers that specialize FromJniType() / ToJniType().
#include "base/tasks_minimal_jni/TraceEvent_jni.h"
namespace base { namespace base {
namespace android { namespace android {
@ -310,21 +306,24 @@ static void JNI_TraceEvent_WebViewStartupStage1(JNIEnv* env,
#endif // BUILDFLAG(ENABLE_BASE_TRACING) #endif // BUILDFLAG(ENABLE_BASE_TRACING)
} }
static void JNI_TraceEvent_WebViewStartupStage2(JNIEnv* env, static void JNI_TraceEvent_WebViewStartupFirstInstance(
jlong start_time_ms, JNIEnv* env,
jlong duration_ms, jlong start_time_ms,
jboolean is_cold_startup) { jlong duration_ms,
jboolean included_global_startup) {
#if BUILDFLAG(ENABLE_BASE_TRACING) #if BUILDFLAG(ENABLE_BASE_TRACING)
auto t = perfetto::Track::ThreadScoped( auto t = perfetto::Track::ThreadScoped(
reinterpret_cast<void*>(trace_event::GetNextGlobalTraceId())); reinterpret_cast<void*>(trace_event::GetNextGlobalTraceId()));
if (is_cold_startup) { if (included_global_startup) {
TRACE_EVENT_BEGIN("android_webview.timeline", TRACE_EVENT_BEGIN(
"WebView.Startup.CreationTime.Stage2.ProviderInit.Cold", "android_webview.timeline",
t, TimeTicks() + Milliseconds(start_time_ms)); "WebView.Startup.CreationTime.FirstInstanceWithGlobalStartup", t,
TimeTicks() + Milliseconds(start_time_ms));
} else { } else {
TRACE_EVENT_BEGIN("android_webview.timeline", TRACE_EVENT_BEGIN(
"WebView.Startup.CreationTime.Stage2.ProviderInit.Warm", "android_webview.timeline",
t, TimeTicks() + Milliseconds(start_time_ms)); "WebView.Startup.CreationTime.FirstInstanceWithoutGlobalStartup", t,
TimeTicks() + Milliseconds(start_time_ms));
} }
TRACE_EVENT_END("android_webview.timeline", t, TRACE_EVENT_END("android_webview.timeline", t,
@ -332,6 +331,20 @@ static void JNI_TraceEvent_WebViewStartupStage2(JNIEnv* env,
#endif // BUILDFLAG(ENABLE_BASE_TRACING) #endif // BUILDFLAG(ENABLE_BASE_TRACING)
} }
static void JNI_TraceEvent_WebViewStartupNotFirstInstance(JNIEnv* env,
jlong start_time_ms,
jlong duration_ms) {
#if BUILDFLAG(ENABLE_BASE_TRACING)
auto t = perfetto::Track::ThreadScoped(
reinterpret_cast<void*>(trace_event::GetNextGlobalTraceId()));
TRACE_EVENT_BEGIN("android_webview.timeline",
"WebView.Startup.CreationTime.NotFirstInstance", t,
TimeTicks() + Milliseconds(start_time_ms));
TRACE_EVENT_END("android_webview.timeline", t,
TimeTicks() + Milliseconds(start_time_ms + duration_ms));
#endif // BUILDFLAG(ENABLE_BASE_TRACING)
}
static void JNI_TraceEvent_WebViewStartupStartChromiumLocked( static void JNI_TraceEvent_WebViewStartupStartChromiumLocked(
JNIEnv* env, JNIEnv* env,
jlong start_time_ms, jlong start_time_ms,

View file

@ -4,16 +4,9 @@
#include "base/android/unguessable_token_android.h" #include "base/android/unguessable_token_android.h"
#include "build/robolectric_buildflags.h"
// Must come after all headers that specialize FromJniType() / ToJniType(). // Must come after all headers that specialize FromJniType() / ToJniType().
#if BUILDFLAG(IS_ROBOLECTRIC) #include "base/base_minimal_jni/TokenBase_jni.h"
#include "base/base_robolectric_jni/TokenBase_jni.h" // nogncheck #include "base/base_minimal_jni/UnguessableToken_jni.h"
#include "base/base_robolectric_jni/UnguessableToken_jni.h" // nogncheck
#else
#include "base/base_jni/TokenBase_jni.h"
#include "base/base_jni/UnguessableToken_jni.h"
#endif
namespace base { namespace base {
namespace android { namespace android {
@ -50,3 +43,5 @@ UnguessableTokenAndroid::ParcelAndUnparcelForTesting(
} // namespace android } // namespace android
} // namespace base } // namespace base
DEFINE_JNI_FOR_UnguessableToken()

View file

@ -0,0 +1,101 @@
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/apple/dispatch_source.h"
#include "base/apple/scoped_dispatch_object.h"
namespace base::apple {
struct DispatchSource::Storage {
// The dispatch queue used to service the source_.
ScopedDispatchObject<dispatch_queue_t> queue;
// Dispatch source type, either DISPATCH_SOURCE_TYPE_MACH_RECV,
// DISPATCH_SOURCE_TYPE_READ or DISPATCH_SOURCE_TYPE_WRITE.
ScopedDispatchObject<dispatch_source_t> source;
// Semaphore used to wait on the |source_|'s cancellation in the destructor.
ScopedDispatchObject<dispatch_semaphore_t> source_canceled;
};
DispatchSource::DispatchSource(const char* name,
mach_port_t port,
void (^event_handler)())
: DispatchSource(dispatch_queue_create(name, DISPATCH_QUEUE_SERIAL),
port,
event_handler) {
// Since the queue was created above in the delegated constructor, and it was
// subsequently retained, release it here.
dispatch_release(storage_->queue.get());
}
DispatchSource::DispatchSource(dispatch_queue_t queue,
int fd,
dispatch_source_type_t type,
void (^event_handler)())
: storage_(std::make_unique<Storage>()) {
DCHECK(type == DISPATCH_SOURCE_TYPE_READ ||
type == DISPATCH_SOURCE_TYPE_WRITE);
storage_->queue.reset(queue, base::scoped_policy::RETAIN);
storage_->source.reset(dispatch_source_create(
type, static_cast<uintptr_t>(fd), 0, storage_->queue.get()));
storage_->source_canceled.reset(dispatch_semaphore_create(0));
dispatch_source_set_event_handler(storage_->source.get(), event_handler);
dispatch_source_set_cancel_handler(storage_->source.get(), ^{
dispatch_semaphore_signal(storage_->source_canceled.get());
});
}
DispatchSource::DispatchSource(dispatch_queue_t queue,
mach_port_t port,
void (^event_handler)())
: storage_(std::make_unique<Storage>()) {
storage_->queue.reset(queue, base::scoped_policy::RETAIN);
storage_->source.reset(dispatch_source_create(
DISPATCH_SOURCE_TYPE_MACH_RECV, port, 0, storage_->queue.get()));
storage_->source_canceled.reset(dispatch_semaphore_create(0));
dispatch_source_set_event_handler(storage_->source.get(), event_handler);
dispatch_source_set_cancel_handler(storage_->source.get(), ^{
dispatch_semaphore_signal(storage_->source_canceled.get());
});
}
DispatchSource::~DispatchSource() {
if (suspended_) {
Resume();
}
// Cancel the source and wait for the semaphore to be signaled. This will
// ensure the source managed by this class is not used after it is freed.
dispatch_source_cancel(storage_->source.get());
storage_->source.reset();
dispatch_semaphore_wait(storage_->source_canceled.get(),
DISPATCH_TIME_FOREVER);
}
void DispatchSource::Resume() {
if (!suspended_) {
return;
}
suspended_ = false;
dispatch_resume(storage_->source.get());
}
void DispatchSource::Suspend() {
if (suspended_) {
return;
}
suspended_ = true;
dispatch_suspend(storage_->source.get());
}
dispatch_queue_t DispatchSource::Queue() const {
return storage_->queue.get();
}
} // namespace base::apple

View file

@ -0,0 +1,63 @@
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_APPLE_DISPATCH_SOURCE_H_
#define BASE_APPLE_DISPATCH_SOURCE_H_
#include <dispatch/dispatch.h>
#include <memory>
#include "base/base_export.h"
namespace base::apple {
// This class encapsulates a dispatch source of type dispatch_source_type_t.
// When this object is destroyed, the source will be cancelled and it will wait
// for the source to stop executing work. The source can run on either a
// user-supplied queue, or it can create its own for the source.
class BASE_EXPORT DispatchSource {
public:
// Creates a new dispatch source for the |port| and schedules it on a new
// queue that will be created with |name|. When a Mach message is received,
// the |event_handler| will be called.
DispatchSource(const char* name, mach_port_t port, void (^event_handler)());
// Creates a new dispatch source with the same semantics as above, but rather
// than creating a new queue, it schedules the source on |queue|.
DispatchSource(dispatch_queue_t queue,
mach_port_t port,
void (^event_handler)());
// Create a dispatch source for a file descriptor.
// `type` should either be DISPATCH_SOURCE_TYPE_READ or
// DISPATCH_SOURCE_TYPE_WRITE.
DispatchSource(dispatch_queue_t queue,
int fd,
dispatch_source_type_t type,
void (^event_handler)());
DispatchSource(const DispatchSource&) = delete;
DispatchSource& operator=(const DispatchSource&) = delete;
// Cancels the source and waits for it to become fully cancelled before
// releasing the source.
~DispatchSource();
// Resumes the source. This must be called before any Mach messages will
// be received.
void Resume();
void Suspend();
dispatch_queue_t Queue() const;
private:
bool suspended_ = true;
struct Storage;
std::unique_ptr<Storage> storage_;
};
} // namespace base::apple
#endif // BASE_APPLE_DISPATCH_SOURCE_H_

View file

@ -1,66 +0,0 @@
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/apple/dispatch_source_mach.h"
#include "base/apple/scoped_dispatch_object.h"
namespace base::apple {
struct DispatchSourceMach::Storage {
// The dispatch queue used to service the source_.
ScopedDispatchObject<dispatch_queue_t> queue;
// A MACH_RECV dispatch source.
ScopedDispatchObject<dispatch_source_t> source;
// Semaphore used to wait on the |source_|'s cancellation in the destructor.
ScopedDispatchObject<dispatch_semaphore_t> source_canceled;
};
DispatchSourceMach::DispatchSourceMach(const char* name,
mach_port_t port,
void (^event_handler)())
: DispatchSourceMach(dispatch_queue_create(name, DISPATCH_QUEUE_SERIAL),
port,
event_handler) {
// Since the queue was created above in the delegated constructor, and it was
// subsequently retained, release it here.
dispatch_release(storage_->queue.get());
}
DispatchSourceMach::DispatchSourceMach(dispatch_queue_t queue,
mach_port_t port,
void (^event_handler)())
: storage_(std::make_unique<Storage>()) {
storage_->queue.reset(queue, base::scoped_policy::RETAIN);
storage_->source.reset(dispatch_source_create(
DISPATCH_SOURCE_TYPE_MACH_RECV, port, 0, storage_->queue.get()));
storage_->source_canceled.reset(dispatch_semaphore_create(0));
dispatch_source_set_event_handler(storage_->source.get(), event_handler);
dispatch_source_set_cancel_handler(storage_->source.get(), ^{
dispatch_semaphore_signal(storage_->source_canceled.get());
});
}
DispatchSourceMach::~DispatchSourceMach() {
// Cancel the source and wait for the semaphore to be signaled. This will
// ensure the source managed by this class is not used after it is freed.
dispatch_source_cancel(storage_->source.get());
storage_->source.reset();
dispatch_semaphore_wait(storage_->source_canceled.get(),
DISPATCH_TIME_FOREVER);
}
void DispatchSourceMach::Resume() {
dispatch_resume(storage_->source.get());
}
dispatch_queue_t DispatchSourceMach::Queue() const {
return storage_->queue.get();
}
} // namespace base::apple

View file

@ -1,55 +0,0 @@
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_APPLE_DISPATCH_SOURCE_MACH_H_
#define BASE_APPLE_DISPATCH_SOURCE_MACH_H_
#include <dispatch/dispatch.h>
#include <memory>
#include "base/base_export.h"
namespace base::apple {
// This class encapsulates a MACH_RECV dispatch source. When this object is
// destroyed, the source will be cancelled and it will wait for the source
// to stop executing work. The source can run on either a user-supplied queue,
// or it can create its own for the source.
class BASE_EXPORT DispatchSourceMach {
public:
// Creates a new dispatch source for the |port| and schedules it on a new
// queue that will be created with |name|. When a Mach message is received,
// the |event_handler| will be called.
DispatchSourceMach(const char* name,
mach_port_t port,
void (^event_handler)());
// Creates a new dispatch source with the same semantics as above, but rather
// than creating a new queue, it schedules the source on |queue|.
DispatchSourceMach(dispatch_queue_t queue,
mach_port_t port,
void (^event_handler)());
DispatchSourceMach(const DispatchSourceMach&) = delete;
DispatchSourceMach& operator=(const DispatchSourceMach&) = delete;
// Cancels the source and waits for it to become fully cancelled before
// releasing the source.
~DispatchSourceMach();
// Resumes the source. This must be called before any Mach messages will
// be received.
void Resume();
dispatch_queue_t Queue() const;
private:
struct Storage;
std::unique_ptr<Storage> storage_;
};
} // namespace base::apple
#endif // BASE_APPLE_DISPATCH_SOURCE_MACH_H_

View file

@ -295,7 +295,7 @@ MachPortRendezvousServerIOS::MachPortRendezvousServerIOS(
DCHECK_LT(ports_.size(), kMaximumRendezvousPorts); DCHECK_LT(ports_.size(), kMaximumRendezvousPorts);
bool res = apple::CreateMachPort(&server_port_, &send_right_); bool res = apple::CreateMachPort(&server_port_, &send_right_);
CHECK(res) << "Failed to create mach server port"; CHECK(res) << "Failed to create mach server port";
dispatch_source_ = std::make_unique<apple::DispatchSourceMach>( dispatch_source_ = std::make_unique<apple::DispatchSource>(
"MachPortRendezvousServer", server_port_.get(), ^{ "MachPortRendezvousServer", server_port_.get(), ^{
HandleRequest(); HandleRequest();
}); });
@ -409,7 +409,7 @@ MachPortRendezvousServerMac::MachPortRendezvousServerMac() {
apple::ScopedMachReceiveRight::Receiver(server_port_).get()); apple::ScopedMachReceiveRight::Receiver(server_port_).get());
BOOTSTRAP_CHECK(kr == KERN_SUCCESS, kr) BOOTSTRAP_CHECK(kr == KERN_SUCCESS, kr)
<< "bootstrap_check_in " << bootstrap_name; << "bootstrap_check_in " << bootstrap_name;
dispatch_source_ = std::make_unique<apple::DispatchSourceMach>( dispatch_source_ = std::make_unique<apple::DispatchSource>(
bootstrap_name.c_str(), server_port_.get(), ^{ bootstrap_name.c_str(), server_port_.get(), ^{
HandleRequest(); HandleRequest();
}); });

View file

@ -15,7 +15,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "base/apple/dispatch_source_mach.h" #include "base/apple/dispatch_source.h"
#include "base/apple/scoped_mach_port.h" #include "base/apple/scoped_mach_port.h"
#include "base/base_export.h" #include "base/base_export.h"
#include "base/containers/buffer_iterator.h" #include "base/containers/buffer_iterator.h"
@ -99,7 +99,7 @@ class BASE_EXPORT MachPortRendezvousServerBase {
apple::ScopedMachReceiveRight server_port_; apple::ScopedMachReceiveRight server_port_;
// Mach message dispatch source for |server_port_|. // Mach message dispatch source for |server_port_|.
std::unique_ptr<apple::DispatchSourceMach> dispatch_source_; std::unique_ptr<apple::DispatchSource> dispatch_source_;
// Ask for the associated ports associated with `audit_token`. // Ask for the associated ports associated with `audit_token`.
// Return `std::nullopt` if the client is not authorized to // Return `std::nullopt` if the client is not authorized to

View file

@ -81,7 +81,10 @@ bool Base64Decode(std::string_view input,
// in-place, but it violates the API contract that `output` is only modified // in-place, but it violates the API contract that `output` is only modified
// on success. // on success.
std::string input_without_whitespace; std::string input_without_whitespace;
RemoveChars(input, kInfraAsciiWhitespace, &input_without_whitespace); RemoveChars(input,
std::string_view(std::begin(kInfraAsciiWhitespace),
std::end(kInfraAsciiWhitespace)),
&input_without_whitespace);
// This means that the required size to decode is at most what was needed // This means that the required size to decode is at most what was needed
// above, which means `decode_buf` will fit the decoded bytes at its current // above, which means `decode_buf` will fit the decoded bytes at its current
// size and we don't need to call `modp_b64_decode_len()` again. // size and we don't need to call `modp_b64_decode_len()` again.

View file

@ -238,6 +238,17 @@ bool PathProviderWin(int key, FilePath* result) {
return false; return false;
} }
break; break;
case base::DIR_ONE_DRIVE: {
base::win::ScopedCoMem<wchar_t> path_buf;
// FOLDERID_OneDrive points on the user OneDrive folder. The default path
// is %USERPROFILE%\OneDrive. It is formerly known as FOLDERID_SkyDrive.
if (FAILED(SHGetKnownFolderPath(FOLDERID_OneDrive, 0, NULL, &path_buf))) {
return false;
}
cur = FilePath(path_buf.get());
break;
}
default: default:
return false; return false;
} }

View file

@ -57,6 +57,7 @@ enum {
DIR_WINDOWS_FONTS, // Usually C:\Windows\Fonts. DIR_WINDOWS_FONTS, // Usually C:\Windows\Fonts.
DIR_SYSTEM_TEMP, // %SystemRoot%\SystemTemp or %ProgramFiles%; DIR_SYSTEM_TEMP, // %SystemRoot%\SystemTemp or %ProgramFiles%;
// only for admin processes. // only for admin processes.
DIR_ONE_DRIVE, // The synced personal OneDrive directory.
PATH_WIN_END PATH_WIN_END
}; };

View file

@ -5,7 +5,6 @@
#include "base/base_switches.h" #include "base/base_switches.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "build/chromeos_buildflags.h"
namespace switches { namespace switches {

View file

@ -8,7 +8,6 @@
#define BASE_BASE_SWITCHES_H_ #define BASE_BASE_SWITCHES_H_
#include "build/build_config.h" #include "build/build_config.h"
#include "build/chromeos_buildflags.h"
namespace switches { namespace switches {

View file

@ -216,6 +216,9 @@ class BASE_EXPORT NotReachedNoreturnError : public CheckError {
// The weird ternary is to still generate an "is not contextually convertible to // The weird ternary is to still generate an "is not contextually convertible to
// 'bool' when provided weird parameters (regardless of ANALYZER_ASSUME_TRUE's // 'bool' when provided weird parameters (regardless of ANALYZER_ASSUME_TRUE's
// implementation). See base/check_nocompile.nc. // implementation). See base/check_nocompile.nc.
//
// The lambda is here to here permit the compiler to out-of-line much of the
// CHECK-failure path and optimize better for the fast path.
#define LOGGING_CHECK_FUNCTION_IMPL(check_stream, condition) \ #define LOGGING_CHECK_FUNCTION_IMPL(check_stream, condition) \
switch (0) \ switch (0) \
case 0: \ case 0: \
@ -223,7 +226,7 @@ class BASE_EXPORT NotReachedNoreturnError : public CheckError {
if (ANALYZER_ASSUME_TRUE((condition) ? true : false)) \ if (ANALYZER_ASSUME_TRUE((condition) ? true : false)) \
[[likely]]; \ [[likely]]; \
else \ else \
(check_stream) [&]() { return (check_stream); }()
// A helper macro like LOGGING_CHECK_FUNCTION_IMPL above but discarding any // A helper macro like LOGGING_CHECK_FUNCTION_IMPL above but discarding any
// log-stream parameters rather than evaluate them on failure. // log-stream parameters rather than evaluate them on failure.

View file

@ -14,9 +14,9 @@
#include "base/check.h" #include "base/check.h"
#include "base/dcheck_is_on.h" #include "base/dcheck_is_on.h"
#include "base/memory/raw_ptr_exclusion.h" #include "base/memory/raw_ptr_exclusion.h"
#include "base/strings/to_string.h"
#include "base/types/is_arc_pointer.h" #include "base/types/is_arc_pointer.h"
#include "base/types/supports_ostream_operator.h" #include "base/types/supports_ostream_operator.h"
#include "base/types/supports_to_string.h"
// This header defines the (DP)CHECK_EQ etc. macros. // This header defines the (DP)CHECK_EQ etc. macros.
// //

View file

@ -2,11 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
#pragma allow_unsafe_buffers
#endif
#include "base/command_line.h" #include "base/command_line.h"
#include <algorithm> #include <algorithm>
@ -15,6 +10,7 @@
#include <string_view> #include <string_view>
#include "base/check_op.h" #include "base/check_op.h"
#include "base/compiler_specific.h"
#include "base/containers/contains.h" #include "base/containers/contains.h"
#include "base/containers/span.h" #include "base/containers/span.h"
#include "base/debug/debugging_buildflags.h" #include "base/debug/debugging_buildflags.h"
@ -197,7 +193,8 @@ CommandLine::CommandLine(const FilePath& program) : argv_(1), begin_args_(1) {
CommandLine::CommandLine(int argc, const CommandLine::CharType* const* argv) CommandLine::CommandLine(int argc, const CommandLine::CharType* const* argv)
: argv_(1), begin_args_(1) { : argv_(1), begin_args_(1) {
InitFromArgv(argc, argv); // SAFETY: required from caller.
UNSAFE_BUFFERS(InitFromArgv(argc, argv));
} }
CommandLine::CommandLine(const StringVector& argv) : argv_(1), begin_args_(1) { CommandLine::CommandLine(const StringVector& argv) : argv_(1), begin_args_(1) {
@ -254,7 +251,8 @@ void CommandLine::InitUsingArgvForTesting(int argc, const char* const* argv) {
// On Windows we need to convert the command line arguments to std::wstring. // On Windows we need to convert the command line arguments to std::wstring.
CommandLine::StringVector argv_vector; CommandLine::StringVector argv_vector;
for (int i = 0; i < argc; ++i) { for (int i = 0; i < argc; ++i) {
argv_vector.push_back(UTF8ToWide(argv[i])); // SAFETY: required from caller.
argv_vector.push_back(UTF8ToWide(UNSAFE_BUFFERS(argv[i])));
} }
current_process_commandline_->InitFromArgv(argv_vector); current_process_commandline_->InitFromArgv(argv_vector);
} }
@ -273,7 +271,8 @@ bool CommandLine::Init(int argc, const char* const* argv) {
#if BUILDFLAG(IS_WIN) #if BUILDFLAG(IS_WIN)
current_process_commandline_->ParseFromString(::GetCommandLineW()); current_process_commandline_->ParseFromString(::GetCommandLineW());
#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
current_process_commandline_->InitFromArgv(argc, argv); // SAFETY: required from caller.
UNSAFE_BUFFERS(current_process_commandline_->InitFromArgv(argc, argv));
#else #else
#error Unsupported platform #error Unsupported platform
#endif #endif
@ -319,7 +318,8 @@ void CommandLine::InitFromArgv(int argc,
const CommandLine::CharType* const* argv) { const CommandLine::CharType* const* argv) {
StringVector new_argv; StringVector new_argv;
for (int i = 0; i < argc; ++i) { for (int i = 0; i < argc; ++i) {
new_argv.push_back(argv[i]); // SAFETY: required from caller.
new_argv.push_back(UNSAFE_BUFFERS(argv[i]));
} }
InitFromArgv(new_argv); InitFromArgv(new_argv);
} }
@ -378,6 +378,23 @@ std::string CommandLine::GetSwitchValueASCII(
#endif #endif
} }
std::string CommandLine::GetSwitchValueUTF8(
std::string_view switch_string) const {
StringType value = GetSwitchValueNative(switch_string);
#if BUILDFLAG(IS_WIN)
const std::string maybe_utf8_value = WideToUTF8(value);
#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
const std::string maybe_utf8_value = value;
#endif
if (!IsStringUTF8(maybe_utf8_value)) {
DLOG(WARNING) << "Value of switch (" << switch_string << ") is not UTF8.";
return {};
}
return maybe_utf8_value;
}
FilePath CommandLine::GetSwitchValuePath(std::string_view switch_string) const { FilePath CommandLine::GetSwitchValuePath(std::string_view switch_string) const {
return FilePath(GetSwitchValueNative(switch_string)); return FilePath(GetSwitchValueNative(switch_string));
} }
@ -435,6 +452,14 @@ void CommandLine::AppendSwitchNative(std::string_view switch_string,
void CommandLine::AppendSwitchASCII(std::string_view switch_string, void CommandLine::AppendSwitchASCII(std::string_view switch_string,
std::string_view value_string) { std::string_view value_string) {
AppendSwitchUTF8(switch_string, value_string);
}
void CommandLine::AppendSwitchUTF8(std::string_view switch_string,
std::string_view value_string) {
DCHECK(IsStringUTF8(value_string))
<< "Switch (" << switch_string << ") value (" << value_string
<< ") is not UTF8.";
#if BUILDFLAG(IS_WIN) #if BUILDFLAG(IS_WIN)
AppendSwitchNative(switch_string, UTF8ToWide(value_string)); AppendSwitchNative(switch_string, UTF8ToWide(value_string));
#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
@ -587,7 +612,7 @@ void CommandLine::ParseFromString(StringViewType command_line) {
DPLOG_IF(FATAL, !args) << "CommandLineToArgvW failed on command line: " DPLOG_IF(FATAL, !args) << "CommandLineToArgvW failed on command line: "
<< command_line; << command_line;
StringVector argv(args, args + num_args); StringVector argv(args, UNSAFE_TODO(args + num_args));
InitFromArgv(argv); InitFromArgv(argv);
raw_command_line_string_ = StringViewType(); raw_command_line_string_ = StringViewType();
LocalFree(args); LocalFree(args);

View file

@ -71,6 +71,7 @@ class BASE_EXPORT CommandLine {
explicit CommandLine(const FilePath& program); explicit CommandLine(const FilePath& program);
// Construct a new command line from an argument list. // Construct a new command line from an argument list.
// TODO(tsepez): two-arg form should be UNSAFE_BUFFER_USAGE.
CommandLine(int argc, const CharType* const* argv); CommandLine(int argc, const CharType* const* argv);
explicit CommandLine(const StringVector& argv); explicit CommandLine(const StringVector& argv);
@ -101,6 +102,7 @@ class BASE_EXPORT CommandLine {
// CommandLineToArgvW to parse the command line and convert it back to // CommandLineToArgvW to parse the command line and convert it back to
// argc and argv. Tests who don't want this dependency on shell32 and need // argc and argv. Tests who don't want this dependency on shell32 and need
// to honor the arguments passed in should use this function. // to honor the arguments passed in should use this function.
// TODO(tsepez): should be UNSAFE_BUFFER_USAGE.
static void InitUsingArgvForTesting(int argc, const char* const* argv); static void InitUsingArgvForTesting(int argc, const char* const* argv);
#endif #endif
@ -109,7 +111,8 @@ class BASE_EXPORT CommandLine {
// don't trust the CRT's parsing of the command line, but it still must be // don't trust the CRT's parsing of the command line, but it still must be
// called to set up the command line. Returns false if initialization has // called to set up the command line. Returns false if initialization has
// already occurred, and true otherwise. Only the caller receiving a 'true' // already occurred, and true otherwise. Only the caller receiving a 'true'
// return value should take responsibility for calling Reset. // return value should take responsibility for calling Reset().
// TODO(tsepez): should be UNSAFE_BUFFER_USAGE.
static bool Init(int argc, const char* const* argv); static bool Init(int argc, const char* const* argv);
// Destroys the current process CommandLine singleton. This is necessary if // Destroys the current process CommandLine singleton. This is necessary if
@ -128,6 +131,7 @@ class BASE_EXPORT CommandLine {
static bool InitializedForCurrentProcess(); static bool InitializedForCurrentProcess();
// Initialize from an argv vector. // Initialize from an argv vector.
// TODO(tsepez): two-arg form should be UNSAFE_BUFFER_USAGE.
void InitFromArgv(int argc, const CharType* const* argv); void InitFromArgv(int argc, const CharType* const* argv);
void InitFromArgv(const StringVector& argv); void InitFromArgv(const StringVector& argv);
@ -197,6 +201,7 @@ class BASE_EXPORT CommandLine {
// value or isn't present, this method returns the empty string. // value or isn't present, this method returns the empty string.
// Switch names must be lowercase. // Switch names must be lowercase.
std::string GetSwitchValueASCII(std::string_view switch_string) const; std::string GetSwitchValueASCII(std::string_view switch_string) const;
std::string GetSwitchValueUTF8(std::string_view switch_string) const;
FilePath GetSwitchValuePath(std::string_view switch_string) const; FilePath GetSwitchValuePath(std::string_view switch_string) const;
StringType GetSwitchValueNative(std::string_view switch_string) const; StringType GetSwitchValueNative(std::string_view switch_string) const;
@ -210,6 +215,7 @@ class BASE_EXPORT CommandLine {
void AppendSwitchNative(std::string_view switch_string, StringViewType value); void AppendSwitchNative(std::string_view switch_string, StringViewType value);
void AppendSwitchASCII(std::string_view switch_string, void AppendSwitchASCII(std::string_view switch_string,
std::string_view value); std::string_view value);
void AppendSwitchUTF8(std::string_view switch_string, std::string_view value);
// Removes the switch that matches |switch_key_without_prefix|, regardless of // Removes the switch that matches |switch_key_without_prefix|, regardless of
// prefix and value. If no such switch is present, this has no effect. // prefix and value. If no such switch is present, this has no effect.

View file

@ -16,6 +16,7 @@
#include "base/check.h" #include "base/check.h"
#include "base/check_op.h" #include "base/check_op.h"
#include "base/memory/raw_ptr.h" #include "base/memory/raw_ptr.h"
#include "base/types/cxx23_to_underlying.h"
#include "build/build_config.h" #include "build/build_config.h"
namespace base { namespace base {
@ -25,16 +26,16 @@ template <typename E, E MinEnumValue, E MaxEnumValue>
class EnumSet; class EnumSet;
template <typename E, E Min, E Max> template <typename E, E Min, E Max>
constexpr EnumSet<E, Min, Max> Union(EnumSet<E, Min, Max> set1, EnumSet<E, Min, Max> Union(EnumSet<E, Min, Max> set1,
EnumSet<E, Min, Max> set2); EnumSet<E, Min, Max> set2);
template <typename E, E Min, E Max> template <typename E, E Min, E Max>
constexpr EnumSet<E, Min, Max> Intersection(EnumSet<E, Min, Max> set1, EnumSet<E, Min, Max> Intersection(EnumSet<E, Min, Max> set1,
EnumSet<E, Min, Max> set2); EnumSet<E, Min, Max> set2);
template <typename E, E Min, E Max> template <typename E, E Min, E Max>
constexpr EnumSet<E, Min, Max> Difference(EnumSet<E, Min, Max> set1, EnumSet<E, Min, Max> Difference(EnumSet<E, Min, Max> set1,
EnumSet<E, Min, Max> set2); EnumSet<E, Min, Max> set2);
// An EnumSet is a set that can hold enum values between a min and a // An EnumSet is a set that can hold enum values between a min and a
// max value (inclusive of both). It's essentially a wrapper around // max value (inclusive of both). It's essentially a wrapper around
@ -51,26 +52,24 @@ class EnumSet {
static_assert( static_assert(
std::is_enum_v<E>, std::is_enum_v<E>,
"First template parameter of EnumSet must be an enumeration type"); "First template parameter of EnumSet must be an enumeration type");
using enum_underlying_type = std::underlying_type_t<E>;
static constexpr bool InRange(E value) { static constexpr bool InRange(E value) {
return (value >= MinEnumValue) && (value <= MaxEnumValue); return (value >= MinEnumValue) && (value <= MaxEnumValue);
} }
static constexpr enum_underlying_type GetUnderlyingValue(E value) {
return static_cast<enum_underlying_type>(value);
}
public: public:
using EnumType = E; using EnumType = E;
static const E kMinValue = MinEnumValue; static const E kMinValue = MinEnumValue;
static const E kMaxValue = MaxEnumValue; static const E kMaxValue = MaxEnumValue;
static const size_t kValueCount = static const size_t kValueCount =
GetUnderlyingValue(kMaxValue) - GetUnderlyingValue(kMinValue) + 1; to_underlying(kMaxValue) - to_underlying(kMinValue) + 1;
static_assert(kMinValue <= kMaxValue, static_assert(kMinValue <= kMaxValue,
"min value must be no greater than max value"); "min value must be no greater than max value");
// Allow use with ::testing::ValuesIn, which expects a value_type defined.
using value_type = EnumType;
private: private:
// Declaration needed by Iterator. // Declaration needed by Iterator.
using EnumBitSet = std::bitset<kValueCount>; using EnumBitSet = std::bitset<kValueCount>;
@ -228,37 +227,37 @@ class EnumSet {
// Returns an EnumSet constructed from |bitmask|. // Returns an EnumSet constructed from |bitmask|.
static constexpr EnumSet FromEnumBitmask(const uint64_t bitmask) { static constexpr EnumSet FromEnumBitmask(const uint64_t bitmask) {
static_assert(GetUnderlyingValue(kMaxValue) < 64, static_assert(to_underlying(kMaxValue) < 64,
"The highest enum value must be < 64 for FromEnumBitmask "); "The highest enum value must be < 64 for FromEnumBitmask ");
static_assert(GetUnderlyingValue(kMinValue) >= 0, static_assert(to_underlying(kMinValue) >= 0,
"The lowest enum value must be >= 0 for FromEnumBitmask "); "The lowest enum value must be >= 0 for FromEnumBitmask ");
return EnumSet(EnumBitSet(bitmask >> GetUnderlyingValue(kMinValue))); return EnumSet(EnumBitSet(bitmask >> to_underlying(kMinValue)));
} }
// Returns a bitmask for the EnumSet. // Returns a bitmask for the EnumSet.
uint64_t ToEnumBitmask() const { uint64_t ToEnumBitmask() const {
static_assert(GetUnderlyingValue(kMaxValue) < 64, static_assert(to_underlying(kMaxValue) < 64,
"The highest enum value must be < 64 for ToEnumBitmask "); "The highest enum value must be < 64 for ToEnumBitmask ");
static_assert(GetUnderlyingValue(kMinValue) >= 0, static_assert(to_underlying(kMinValue) >= 0,
"The lowest enum value must be >= 0 for FromEnumBitmask "); "The lowest enum value must be >= 0 for FromEnumBitmask ");
return enums_.to_ullong() << GetUnderlyingValue(kMinValue); return enums_.to_ullong() << to_underlying(kMinValue);
} }
// Returns a uint64_t bit mask representing the values within the range // Returns a uint64_t bit mask representing the values within the range
// [64*n, 64*n + 63] of the EnumSet. // [64*n, 64*n + 63] of the EnumSet.
std::optional<uint64_t> GetNth64bitWordBitmask(size_t n) const { std::optional<uint64_t> GetNth64bitWordBitmask(size_t n) const {
// If the EnumSet contains less than n 64-bit masks, return std::nullopt. // If the EnumSet contains less than n 64-bit masks, return std::nullopt.
if (GetUnderlyingValue(kMaxValue) / 64 < n) { if (to_underlying(kMaxValue) / 64 < n) {
return std::nullopt; return std::nullopt;
} }
std::bitset<kValueCount> mask = ~uint64_t{0}; std::bitset<kValueCount> mask = ~uint64_t{0};
std::bitset<kValueCount> bits = enums_; std::bitset<kValueCount> bits = enums_;
if (GetUnderlyingValue(kMinValue) < n * 64) { if (to_underlying(kMinValue) < n * 64) {
bits >>= n * 64 - GetUnderlyingValue(kMinValue); bits >>= n * 64 - to_underlying(kMinValue);
} }
uint64_t result = (bits & mask).to_ullong(); uint64_t result = (bits & mask).to_ullong();
if (GetUnderlyingValue(kMinValue) > n * 64) { if (to_underlying(kMinValue) > n * 64) {
result <<= GetUnderlyingValue(kMinValue) - n * 64; result <<= to_underlying(kMinValue) - n * 64;
} }
return result; return result;
} }
@ -344,14 +343,12 @@ class EnumSet {
std::string ToString() const { return enums_.to_string(); } std::string ToString() const { return enums_.to_string(); }
private: private:
friend constexpr EnumSet Union<E, MinEnumValue, MaxEnumValue>(EnumSet set1, friend EnumSet Union<E, MinEnumValue, MaxEnumValue>(EnumSet set1,
EnumSet set2); EnumSet set2);
friend constexpr EnumSet Intersection<E, MinEnumValue, MaxEnumValue>( friend EnumSet Intersection<E, MinEnumValue, MaxEnumValue>(EnumSet set1,
EnumSet set1, EnumSet set2);
EnumSet set2); friend EnumSet Difference<E, MinEnumValue, MaxEnumValue>(EnumSet set1,
friend constexpr EnumSet Difference<E, MinEnumValue, MaxEnumValue>( EnumSet set2);
EnumSet set1,
EnumSet set2);
static constexpr uint64_t bitstring(const std::initializer_list<E>& values) { static constexpr uint64_t bitstring(const std::initializer_list<E>& values) {
uint64_t result = 0; uint64_t result = 0;
@ -382,13 +379,13 @@ class EnumSet {
// Converts a value to/from an index into |enums_|. // Converts a value to/from an index into |enums_|.
static constexpr size_t ToIndex(E value) { static constexpr size_t ToIndex(E value) {
CHECK(InRange(value)); CHECK(InRange(value));
return static_cast<size_t>(GetUnderlyingValue(value)) - return static_cast<size_t>(to_underlying(value)) -
static_cast<size_t>(GetUnderlyingValue(MinEnumValue)); static_cast<size_t>(to_underlying(MinEnumValue));
} }
static E FromIndex(size_t i) { static E FromIndex(size_t i) {
DCHECK_LT(i, kValueCount); DCHECK_LT(i, kValueCount);
return static_cast<E>(GetUnderlyingValue(MinEnumValue) + i); return static_cast<E>(to_underlying(MinEnumValue) + i);
} }
EnumBitSet enums_; EnumBitSet enums_;
@ -406,20 +403,20 @@ const size_t EnumSet<E, MinEnumValue, MaxEnumValue>::kValueCount;
// The usual set operations. // The usual set operations.
template <typename E, E Min, E Max> template <typename E, E Min, E Max>
constexpr EnumSet<E, Min, Max> Union(EnumSet<E, Min, Max> set1, EnumSet<E, Min, Max> Union(EnumSet<E, Min, Max> set1,
EnumSet<E, Min, Max> set2) { EnumSet<E, Min, Max> set2) {
return EnumSet<E, Min, Max>(set1.enums_ | set2.enums_); return EnumSet<E, Min, Max>(set1.enums_ | set2.enums_);
} }
template <typename E, E Min, E Max> template <typename E, E Min, E Max>
constexpr EnumSet<E, Min, Max> Intersection(EnumSet<E, Min, Max> set1, EnumSet<E, Min, Max> Intersection(EnumSet<E, Min, Max> set1,
EnumSet<E, Min, Max> set2) { EnumSet<E, Min, Max> set2) {
return EnumSet<E, Min, Max>(set1.enums_ & set2.enums_); return EnumSet<E, Min, Max>(set1.enums_ & set2.enums_);
} }
template <typename E, E Min, E Max> template <typename E, E Min, E Max>
constexpr EnumSet<E, Min, Max> Difference(EnumSet<E, Min, Max> set1, EnumSet<E, Min, Max> Difference(EnumSet<E, Min, Max> set1,
EnumSet<E, Min, Max> set2) { EnumSet<E, Min, Max> set2) {
return EnumSet<E, Min, Max>(set1.enums_ & ~set2.enums_); return EnumSet<E, Min, Max>(set1.enums_ & ~set2.enums_);
} }

View file

@ -169,13 +169,17 @@ class TRIVIAL_ABI GSL_OWNER HeapArray {
// If `count` is unspecified, all remaining elements are included. A CHECK() // If `count` is unspecified, all remaining elements are included. A CHECK()
// occurs if any of the parameters results in an out-of-range position in // occurs if any of the parameters results in an out-of-range position in
// the HeapArray. // the HeapArray.
base::span<T> subspan(size_t offset, base::span<T> subspan(size_t offset) LIFETIME_BOUND {
size_t count = base::dynamic_extent) LIFETIME_BOUND { return as_span().subspan(offset);
}
base::span<const T> subspan(size_t offset) const LIFETIME_BOUND {
return as_span().subspan(offset);
}
base::span<T> subspan(size_t offset, size_t count) LIFETIME_BOUND {
return as_span().subspan(offset, count); return as_span().subspan(offset, count);
} }
base::span<const T> subspan(size_t offset, base::span<const T> subspan(size_t offset,
size_t count = base::dynamic_extent) const size_t count) const LIFETIME_BOUND {
LIFETIME_BOUND {
return as_span().subspan(offset, count); return as_span().subspan(offset, count);
} }

View file

@ -66,6 +66,40 @@ constexpr MappedElementType* FindPtrOrNull(Map& map, const Key& key) {
return it != map.end() ? base::to_address(it->second) : nullptr; return it != map.end() ? base::to_address(it->second) : nullptr;
} }
// Insert or assign into a map type. This has semantics very similar to the
// following statements:
//
// map[key] = Element(params...)
// map[key] = element;
// map[key] = std::move(element);
// map.insert_or_assign(key, element);
//
// Where key can be any heterogeneous comparable overload of the key_type for
// map. In particular, there is no need to construct a temporary `key` of the
// type stored in the map as long as `key` is comparable with the
// `Map::key_type`.
//
// The `element` is copied or moved into the map, depending on whether it is
// passed by lvalue or rvalue reference.
//
// TODO(crbug.com/376532871): This can be removed once map::operator[] and
// map::insert_or_assign support heterogenous key overloads, in C++26.
template <typename Map,
typename Key,
typename MappedElementType =
std::pointer_traits<internal::MappedType<Map>>::element_type>
Map::iterator InsertOrAssign(Map& map,
const Key& key,
MappedElementType&& element) {
auto it = map.lower_bound(key);
if (it == map.end() || it->first != key) {
it = map.emplace_hint(it, key, std::forward<MappedElementType>(element));
} else {
it->second = std::forward<MappedElementType>(element);
}
return it;
}
} // namespace base } // namespace base
#endif // BASE_CONTAINERS_MAP_UTIL_H_ #endif // BASE_CONTAINERS_MAP_UTIL_H_

View file

@ -31,6 +31,7 @@
#include "base/numerics/integral_constant_like.h" #include "base/numerics/integral_constant_like.h"
#include "base/numerics/safe_conversions.h" #include "base/numerics/safe_conversions.h"
#include "base/strings/cstring_view.h" #include "base/strings/cstring_view.h"
#include "base/strings/to_string.h"
#include "base/types/to_address.h" #include "base/types/to_address.h"
// A span is a view of contiguous elements that can be accessed like an array, // A span is a view of contiguous elements that can be accessed like an array,
@ -226,6 +227,8 @@
// Differences from [span.sub]: // Differences from [span.sub]:
// - As in [span.cons], `size_t` parameters are changed to // - As in [span.cons], `size_t` parameters are changed to
// `StrictNumeric<size_type>`. // `StrictNumeric<size_type>`.
// - There are separate overloads for one-arg and two-arg forms of subspan,
// and the two-arg form does not accept dynamic_extent as a count.
// - For convenience, provides `span::split_at()` to split a single span into // - For convenience, provides `span::split_at()` to split a single span into
// two at a given offset. // two at a given offset.
// - For convenience, provides `span::take_first[_elem]()` to remove the first // - For convenience, provides `span::take_first[_elem]()` to remove the first
@ -718,19 +721,21 @@ class GSL_POINTER span {
return UNSAFE_BUFFERS(span<element_type, Count>(data() + Offset, Count)); return UNSAFE_BUFFERS(span<element_type, Count>(data() + Offset, Count));
} }
} }
constexpr auto subspan( constexpr auto subspan(StrictNumeric<size_type> offset) const {
StrictNumeric<size_type> offset,
StrictNumeric<size_type> count = dynamic_extent) const {
CHECK_LE(size_type{offset}, extent); CHECK_LE(size_type{offset}, extent);
const size_type remaining = extent - size_type{offset}; const size_type remaining = extent - size_type{offset};
if (count == dynamic_extent) { // SAFETY: `data()` points to at least `extent` elements, so `offset`
// SAFETY: `data()` points to at least `extent` elements, so `offset` // specifies a valid element index or the past-the-end index, and
// specifies a valid element index or the past-the-end index, and // `remaining` cannot index past-the-end elements.
// `remaining` cannot index past-the-end elements. return UNSAFE_BUFFERS(
return UNSAFE_BUFFERS( span<element_type>(data() + size_type{offset}, remaining));
span<element_type>(data() + size_type{offset}, remaining)); }
} constexpr auto subspan(StrictNumeric<size_type> offset,
CHECK_LE(size_type{count}, remaining); StrictNumeric<size_type> count) const {
DCHECK(size_type{count} != dynamic_extent)
<< "base does not allow dynamic_extent in two-arg subspan()";
CHECK(size_type{offset} <= size() &&
size_type{count} <= size() - size_type{offset});
// SAFETY: `data()` points to at least `extent` elements, so `offset` // SAFETY: `data()` points to at least `extent` elements, so `offset`
// specifies a valid element index or the past-the-end index, and `count` is // specifies a valid element index or the past-the-end index, and `count` is
// no larger than the number of remaining valid elements. // no larger than the number of remaining valid elements.
@ -1150,19 +1155,21 @@ class GSL_POINTER span<ElementType, dynamic_extent, InternalPtrType> {
// no larger than the number of remaining valid elements. // no larger than the number of remaining valid elements.
return UNSAFE_BUFFERS(span<element_type, Count>(data() + Offset, Count)); return UNSAFE_BUFFERS(span<element_type, Count>(data() + Offset, Count));
} }
constexpr auto subspan( constexpr auto subspan(StrictNumeric<size_type> offset) const {
StrictNumeric<size_type> offset,
StrictNumeric<size_type> count = dynamic_extent) const {
CHECK_LE(size_type{offset}, size()); CHECK_LE(size_type{offset}, size());
const size_type remaining = size() - size_type{offset}; const size_type remaining = size() - size_type{offset};
if (count == dynamic_extent) { // SAFETY: `data()` points to at least `size()` elements, so `offset`
// SAFETY: `data()` points to at least `size()` elements, so `offset` // specifies a valid element index or the past-the-end index, and
// specifies a valid element index or the past-the-end index, and // `remaining` cannot index past-the-end elements.
// `remaining` cannot index past-the-end elements. return UNSAFE_BUFFERS(
return UNSAFE_BUFFERS( span<element_type>(data() + size_type{offset}, remaining));
span<element_type>(data() + size_type{offset}, remaining)); }
} constexpr auto subspan(StrictNumeric<size_type> offset,
CHECK_LE(size_type{count}, remaining); StrictNumeric<size_type> count) const {
DCHECK(size_type{count} != dynamic_extent)
<< "base does not allow dynamic_extent in two-arg subspan()";
CHECK(size_type{offset} <= size() &&
size_type{count} <= size() - size_type{offset});
// SAFETY: `data()` points to at least `size()` elements, so `offset` // SAFETY: `data()` points to at least `size()` elements, so `offset`
// specifies a valid element index or the past-the-end index, and `count` is // specifies a valid element index or the past-the-end index, and `count` is
// no larger than the number of remaining valid elements. // no larger than the number of remaining valid elements.

View file

@ -1,78 +0,0 @@
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/cpu_reduction_experiment.h"
#include <atomic>
#include "base/check.h"
#include "base/dcheck_is_on.h"
#include "base/feature_list.h"
#include "base/rand_util.h"
namespace base {
namespace {
// Whether to enable a series of optimizations that reduce total CPU
// utilization.
BASE_FEATURE(kReduceCpuUtilization,
"ReduceCpuUtilization2",
FEATURE_ENABLED_BY_DEFAULT);
class CpuReductionExperimentSubSampler {
public:
CpuReductionExperimentSubSampler() : counter_(base::RandUint64()) {}
bool ShouldLogHistograms() {
// Relaxed memory order since there is no dependent memory access.
uint64_t val = counter_.fetch_add(1, std::memory_order_relaxed);
return val % 1000 == 0;
}
private:
std::atomic<uint64_t> counter_{0};
};
// Singleton instance of CpuReductionExperimentSubSampler. This is only set when
// the ReduceCpuUtilization experiment is enabled -- as a result, it's ok to
// assume that the experiment is disabled when this is not set.
CpuReductionExperimentSubSampler* g_subsampler = nullptr;
#if DCHECK_IS_ON()
// Atomic to support concurrent writes from IsRunningCpuReductionExperiment().
std::atomic_bool g_accessed_subsampler = false;
#endif
} // namespace
bool IsRunningCpuReductionExperiment() {
#if DCHECK_IS_ON()
// Relaxed memory order since there is no dependent memory access.
g_accessed_subsampler.store(true, std::memory_order_relaxed);
#endif
return !!g_subsampler;
}
void InitializeCpuReductionExperiment() {
#if DCHECK_IS_ON()
// TSAN should generate an error if InitializeCpuReductionExperiment() races
// with IsRunningCpuReductionExperiment().
//
// Relaxed memory order since there is no dependent memory access.
DCHECK(!g_accessed_subsampler.load(std::memory_order_relaxed));
#endif
if (FeatureList::IsEnabled(kReduceCpuUtilization)) {
g_subsampler = new CpuReductionExperimentSubSampler();
}
}
bool ShouldLogHistogramForCpuReductionExperiment() {
if (!IsRunningCpuReductionExperiment()) {
return true;
}
return g_subsampler->ShouldLogHistograms();
}
} // namespace base

View file

@ -1,29 +0,0 @@
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_CPU_REDUCTION_EXPERIMENT_H_
#define BASE_CPU_REDUCTION_EXPERIMENT_H_
#include "base/base_export.h"
namespace base {
// Returns whether the cpu cycle reduction experiment is running.
// The goal of this experiment is to better understand the relationship between
// total CPU cycles used across the fleet and top-line chrome metrics.
BASE_EXPORT bool IsRunningCpuReductionExperiment();
// Must be called after FeatureList initialization and while chrome is still
// single-threaded.
BASE_EXPORT void InitializeCpuReductionExperiment();
// Returns true if the next sample should be recorded to an histogram
// sub-sampled under the CPU reduction experiment. Returns true randomly for
// ~1/1000 calls when the experiment is enabled, or always returns true when the
// experiment is disabled.
BASE_EXPORT bool ShouldLogHistogramForCpuReductionExperiment();
} // namespace base
#endif // BASE_CPU_REDUCTION_EXPERIMENT_H_

View file

@ -46,16 +46,6 @@ std::map<base::Location, base::TimeTicks>& LocationToTimestampMap() {
return *location_to_timestamp; return *location_to_timestamp;
} }
// Map used to store the most recent time a pair of location and
// unique_identifier called ShouldDumpWithoutCrashWithLocationAndUniqueId.
std::map<std::pair<base::Location, size_t>, base::TimeTicks>&
LocationAndUniqueIdentifierToTimestampMap() {
static base::NoDestructor<
std::map<std::pair<base::Location, size_t>, base::TimeTicks>>
location_and_unique_identifier_to_timestamp;
return *location_and_unique_identifier_to_timestamp;
}
// This function takes `location` and `time_between_dumps` as an input // This function takes `location` and `time_between_dumps` as an input
// and checks if DumpWithoutCrashing() meets the requirements to take the dump // and checks if DumpWithoutCrashing() meets the requirements to take the dump
// or not. // or not.
@ -64,31 +54,10 @@ bool ShouldDumpWithoutCrashWithLocation(const base::Location& location,
return ShouldDump(LocationToTimestampMap(), location, time_between_dumps); return ShouldDump(LocationToTimestampMap(), location, time_between_dumps);
} }
// Pair of `location` and `unique_identifier` creates a unique key and checks
// if DumpWithoutCrashingWithUniqueId() meets the requirements to take dump or
// not.
bool ShouldDumpWithoutCrashWithLocationAndUniqueId(
size_t unique_identifier,
const base::Location& location,
base::TimeDelta time_between_dumps) {
std::pair<base::Location, size_t> key(location, unique_identifier);
return ShouldDump(LocationAndUniqueIdentifierToTimestampMap(), key,
time_between_dumps);
}
} // namespace } // namespace
namespace base::debug { namespace base::debug {
bool DumpWithoutCrashingUnthrottled() {
TRACE_EVENT0("base", "DumpWithoutCrashingUnthrottled");
if (dump_without_crashing_function_) {
(*dump_without_crashing_function_)();
return true;
}
return false;
}
bool DumpWithoutCrashing(const base::Location& location, bool DumpWithoutCrashing(const base::Location& location,
base::TimeDelta time_between_dumps) { base::TimeDelta time_between_dumps) {
TRACE_EVENT0("base", "DumpWithoutCrashing"); TRACE_EVENT0("base", "DumpWithoutCrashing");
@ -113,23 +82,6 @@ bool DumpWithoutCrashing(const base::Location& location,
return false; return false;
} }
bool DumpWithoutCrashingWithUniqueId(size_t unique_identifier,
const base::Location& location,
base::TimeDelta time_between_dumps) {
TRACE_EVENT0("base", "DumpWithoutCrashingWithUniqueId");
if (dump_without_crashing_function_ &&
ShouldDumpWithoutCrashWithLocationAndUniqueId(unique_identifier, location,
time_between_dumps)) {
(*dump_without_crashing_function_)();
base::UmaHistogramEnumeration("Stability.DumpWithoutCrashingStatus",
DumpWithoutCrashingStatus::kUploaded);
return true;
}
base::UmaHistogramEnumeration("Stability.DumpWithoutCrashingStatus",
DumpWithoutCrashingStatus::kThrottled);
return false;
}
void SetDumpWithoutCrashingFunction(void (*function)()) { void SetDumpWithoutCrashingFunction(void (*function)()) {
#if !defined(COMPONENT_BUILD) #if !defined(COMPONENT_BUILD)
// In component builds, the same base is shared between modules // In component builds, the same base is shared between modules
@ -140,9 +92,8 @@ void SetDumpWithoutCrashingFunction(void (*function)()) {
dump_without_crashing_function_ = function; dump_without_crashing_function_ = function;
} }
void ClearMapsForTesting() { void ResetDumpWithoutCrashingThrottlingForTesting() {
LocationToTimestampMap().clear(); LocationToTimestampMap().clear();
LocationAndUniqueIdentifierToTimestampMap().clear();
} }
} // namespace base::debug } // namespace base::debug

View file

@ -38,11 +38,6 @@ namespace debug {
// This function must not be called with a tail call because that would cause // This function must not be called with a tail call because that would cause
// the caller to be omitted from the call stack in the crash dump, and that is // the caller to be omitted from the call stack in the crash dump, and that is
// confusing and omits what is likely the most important context. // confusing and omits what is likely the most important context.
//
// Note: Calls to this function will not be throttled. To avoid performance
// problems if this is called many times in quick succession, prefer using one
// of the below variants.
NOT_TAIL_CALLED BASE_EXPORT bool DumpWithoutCrashingUnthrottled();
// Handler to silently dump the current process without crashing, that keeps // Handler to silently dump the current process without crashing, that keeps
// track of call location so some throttling can be applied to avoid very // track of call location so some throttling can be applied to avoid very
@ -53,35 +48,13 @@ NOT_TAIL_CALLED BASE_EXPORT bool DumpWithoutCrashing(
const base::Location& location = base::Location::Current(), const base::Location& location = base::Location::Current(),
base::TimeDelta time_between_dumps = base::Days(1)); base::TimeDelta time_between_dumps = base::Days(1));
// Handler to silently dump the current process without crashing that takes a
// location and unique id to keep a track and apply throttling. This function
// should be used when a domain wishes to capture dumps for multiple, unique
// reasons from a single location. An example would be unique bad mojo
// messages, or a value outside an expected range and the value should be
// considered interesting in the dump. The goal is to allow a single call to
// generate multiple dumps as needed and throttle future instances of the same
// identifiers for a short period of time.
// `unique_identifier` Hash to uniquely identify the function call. Consider
// using base::FastHash to generate the hash.
// `location` Location of the file from where the function is called.
// `time_between_dumps` Time until the next dump should be captured.
// Note:
// - The unique identifier, as of now, is not comparable across different
// runs or builds and is stable only for a process lifetime.
// - The unique identifier is not recorded in the crash report. See
// crash_logging.h for such a purpose.
NOT_TAIL_CALLED BASE_EXPORT bool DumpWithoutCrashingWithUniqueId(
size_t unique_identifier,
const base::Location& location = base::Location::Current(),
base::TimeDelta time_between_dumps = base::Days(1));
// Sets a function that'll be invoked to dump the current process when // Sets a function that'll be invoked to dump the current process when
// DumpWithoutCrashing* is called. May be called with null to remove a // DumpWithoutCrashing* is called. May be called with null to remove a
// previously set function. // previously set function.
BASE_EXPORT void SetDumpWithoutCrashingFunction(void (*function)()); BASE_EXPORT void SetDumpWithoutCrashingFunction(void (*function)());
// Clear both maps used to throttle calls to DumpWithoutCrashing for testing. // Reset DumpWithoutCrashing throttling for testing.
BASE_EXPORT void ClearMapsForTesting(); BASE_EXPORT void ResetDumpWithoutCrashingThrottlingForTesting();
} // namespace debug } // namespace debug
} // namespace base } // namespace base

View file

@ -206,7 +206,7 @@ uintptr_t GetStackEnd() {
// values from its pthread_t argument. // values from its pthread_t argument.
static uintptr_t main_stack_end = 0; static uintptr_t main_stack_end = 0;
bool is_main_thread = GetCurrentProcId() == PlatformThread::CurrentId(); bool is_main_thread = GetCurrentProcId() == PlatformThread::CurrentId().raw();
if (is_main_thread && main_stack_end) { if (is_main_thread && main_stack_end) {
return main_stack_end; return main_stack_end;
} }
@ -234,7 +234,8 @@ uintptr_t GetStackEnd() {
#else #else
#if (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)) && defined(__GLIBC__) #if (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)) && defined(__GLIBC__)
if (GetCurrentProcId() == PlatformThread::CurrentId()) { static_assert(std::is_same_v<ProcessId, PlatformThreadId::UnderlyingType>);
if (GetCurrentProcId() == PlatformThread::CurrentId().raw()) {
// For the main thread we have a shortcut. // For the main thread we have a shortcut.
return reinterpret_cast<uintptr_t>(__libc_stack_end); return reinterpret_cast<uintptr_t>(__libc_stack_end);
} }

View file

@ -38,7 +38,6 @@
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "build/chromeos_buildflags.h"
namespace base { namespace base {

View file

@ -100,9 +100,6 @@ enum FeatureState {
// `T` is a parameter type, one of bool, int, size_t, double, std::string, and // `T` is a parameter type, one of bool, int, size_t, double, std::string, and
// base::TimeDelta. Enum types are not supported for now. // base::TimeDelta. Enum types are not supported for now.
// //
// For now, ScopedFeatureList doesn't work to change the value dynamically when
// the cache is used with this macro.
//
// It should *not* be defined in header files; do not use this macro in header // It should *not* be defined in header files; do not use this macro in header
// files. // files.
#define BASE_FEATURE_PARAM(T, feature_object_name, feature, name, \ #define BASE_FEATURE_PARAM(T, feature_object_name, feature, name, \

View file

@ -4,9 +4,9 @@
#include "base/features.h" #include "base/features.h"
#include "base/cpu_reduction_experiment.h"
#include "base/task/sequence_manager/sequence_manager_impl.h" #include "base/task/sequence_manager/sequence_manager_impl.h"
#include "base/threading/platform_thread.h" #include "base/threading/platform_thread.h"
#include "build/blink_buildflags.h"
#include "build/buildflag.h" #include "build/buildflag.h"
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
@ -16,8 +16,12 @@
#if BUILDFLAG(IS_APPLE) #if BUILDFLAG(IS_APPLE)
#include "base/files/file.h" #include "base/files/file.h"
#include "base/message_loop/message_pump_apple.h" #include "base/message_loop/message_pump_apple.h"
#include "base/message_loop/message_pump_kqueue.h"
#include "base/synchronization/condition_variable.h" #include "base/synchronization/condition_variable.h"
#if !BUILDFLAG(IS_IOS) || !BUILDFLAG(USE_BLINK)
#include "base/message_loop/message_pump_kqueue.h"
#endif
#endif #endif
#if BUILDFLAG(IS_ANDROID) #if BUILDFLAG(IS_ANDROID)
@ -32,23 +36,16 @@ namespace base::features {
// Alphabetical: // Alphabetical:
// Activate base::FeatureParamWithCache internal cache. // Controls caching within BASE_FEATURE_PARAM(). This is feature-controlled
// TODO(https://crbug.com/340824113): Remove the feature flag below. // so that ScopedFeatureList can disable it to turn off caching.
BASE_FEATURE(kFeatureParamWithCache, BASE_FEATURE(kFeatureParamWithCache,
"FeatureParamWithCache", "FeatureParamWithCache",
FEATURE_ENABLED_BY_DEFAULT); FEATURE_ENABLED_BY_DEFAULT);
// Use the Rust JSON parser. Enabled everywhere except Android, where the switch // Use the Rust JSON parser. Enabled everywhere.
// from using the C++ parser in-thread to using the Rust parser in a thread-pool
// introduces too much latency.
BASE_FEATURE(kUseRustJsonParser, BASE_FEATURE(kUseRustJsonParser,
"UseRustJsonParser", "UseRustJsonParser",
#if BUILDFLAG(IS_ANDROID) FEATURE_ENABLED_BY_DEFAULT);
FEATURE_DISABLED_BY_DEFAULT
#else
FEATURE_ENABLED_BY_DEFAULT
#endif // BUILDFLAG(IS_ANDROID)
);
// If true, use the Rust JSON parser in-thread; otherwise, it runs in a thread // If true, use the Rust JSON parser in-thread; otherwise, it runs in a thread
// pool. // pool.
@ -56,7 +53,7 @@ BASE_FEATURE_PARAM(bool,
kUseRustJsonParserInCurrentSequence, kUseRustJsonParserInCurrentSequence,
&kUseRustJsonParser, &kUseRustJsonParser,
"UseRustJsonParserInCurrentSequence", "UseRustJsonParserInCurrentSequence",
false); true);
// Use non default low memory device threshold. // Use non default low memory device threshold.
// Value should be given via |LowMemoryDeviceThresholdMB|. // Value should be given via |LowMemoryDeviceThresholdMB|.
@ -125,7 +122,6 @@ BASE_FEATURE(kPostGetMyMemoryStateToBackground,
void Init(EmitThreadControllerProfilerMetadata void Init(EmitThreadControllerProfilerMetadata
emit_thread_controller_profiler_metadata) { emit_thread_controller_profiler_metadata) {
InitializeCpuReductionExperiment();
sequence_manager::internal::SequenceManagerImpl::InitializeFeatures(); sequence_manager::internal::SequenceManagerImpl::InitializeFeatures();
sequence_manager::internal::ThreadController::InitializeFeatures( sequence_manager::internal::ThreadController::InitializeFeatures(
emit_thread_controller_profiler_metadata); emit_thread_controller_profiler_metadata);
@ -141,9 +137,14 @@ void Init(EmitThreadControllerProfilerMetadata
#if BUILDFLAG(IS_APPLE) #if BUILDFLAG(IS_APPLE)
File::InitializeFeatures(); File::InitializeFeatures();
MessagePumpCFRunLoopBase::InitializeFeatures(); MessagePumpCFRunLoopBase::InitializeFeatures();
// Kqueue is not used for ios blink.
#if !BUILDFLAG(IS_IOS) || !BUILDFLAG(USE_BLINK)
MessagePumpKqueue::InitializeFeatures(); MessagePumpKqueue::InitializeFeatures();
#endif #endif
#endif
#if BUILDFLAG(IS_ANDROID) #if BUILDFLAG(IS_ANDROID)
android::InputHintChecker::InitializeFeatures(); android::InputHintChecker::InitializeFeatures();
#endif #endif

View file

@ -457,6 +457,11 @@ FilePath FilePath::InsertBeforeExtension(StringViewType suffix) const {
FilePath FilePath::InsertBeforeExtensionASCII(std::string_view suffix) const { FilePath FilePath::InsertBeforeExtensionASCII(std::string_view suffix) const {
DCHECK(IsStringASCII(suffix)); DCHECK(IsStringASCII(suffix));
return InsertBeforeExtensionUTF8(suffix);
}
FilePath FilePath::InsertBeforeExtensionUTF8(std::string_view suffix) const {
DCHECK(IsStringUTF8(suffix));
#if BUILDFLAG(IS_WIN) #if BUILDFLAG(IS_WIN)
return InsertBeforeExtension(UTF8ToWide(suffix)); return InsertBeforeExtension(UTF8ToWide(suffix));
#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
@ -486,6 +491,11 @@ FilePath FilePath::AddExtension(StringViewType extension) const {
FilePath FilePath::AddExtensionASCII(std::string_view extension) const { FilePath FilePath::AddExtensionASCII(std::string_view extension) const {
DCHECK(IsStringASCII(extension)); DCHECK(IsStringASCII(extension));
return AddExtensionUTF8(extension);
}
FilePath FilePath::AddExtensionUTF8(std::string_view extension) const {
DCHECK(IsStringUTF8(extension));
#if BUILDFLAG(IS_WIN) #if BUILDFLAG(IS_WIN)
return AddExtension(UTF8ToWide(extension)); return AddExtension(UTF8ToWide(extension));
#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
@ -591,6 +601,11 @@ FilePath FilePath::Append(const SafeBaseName& component) const {
FilePath FilePath::AppendASCII(std::string_view component) const { FilePath FilePath::AppendASCII(std::string_view component) const {
DCHECK(base::IsStringASCII(component)); DCHECK(base::IsStringASCII(component));
return AppendUTF8(component);
}
FilePath FilePath::AppendUTF8(std::string_view component) const {
DCHECK(base::IsStringUTF8(component));
#if BUILDFLAG(IS_WIN) #if BUILDFLAG(IS_WIN)
return Append(UTF8ToWide(component)); return Append(UTF8ToWide(component));
#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)

View file

@ -172,9 +172,6 @@ class BASE_EXPORT FilePath {
using CharType = StringType::value_type; using CharType = StringType::value_type;
using StringViewType = std::basic_string_view<CharType>; using StringViewType = std::basic_string_view<CharType>;
// DEPRECATED. Use `StringViewType` in new code.
// TODO(thestig): Remove.
using StringPieceType = StringViewType;
// Null-terminated array of separators used to separate components in paths. // Null-terminated array of separators used to separate components in paths.
// Each character in this array is a valid separator, but kSeparators[0] is // Each character in this array is a valid separator, but kSeparators[0] is
@ -332,6 +329,13 @@ class BASE_EXPORT FilePath {
[[nodiscard]] FilePath InsertBeforeExtensionASCII( [[nodiscard]] FilePath InsertBeforeExtensionASCII(
std::string_view suffix) const; std::string_view suffix) const;
// Like above, but takes the `suffix` as an UTF8 string.
// While all modern OSes support UTF-8, there is no requirement for the
// filenames to actually be UTF-8, e.g. on Linux. So inserting UTF-8 could
// result in Mojibake filenames.
[[nodiscard]] FilePath InsertBeforeExtensionUTF8(
std::string_view suffix) const;
// Adds |extension| to |file_name|. Returns the current FilePath if // Adds |extension| to |file_name|. Returns the current FilePath if
// |extension| is empty. Returns "" if BaseName() == "." or "..". // |extension| is empty. Returns "" if BaseName() == "." or "..".
[[nodiscard]] FilePath AddExtension(StringViewType extension) const; [[nodiscard]] FilePath AddExtension(StringViewType extension) const;
@ -340,6 +344,13 @@ class BASE_EXPORT FilePath {
// details on how this is handled. // details on how this is handled.
[[nodiscard]] FilePath AddExtensionASCII(std::string_view extension) const; [[nodiscard]] FilePath AddExtensionASCII(std::string_view extension) const;
// Like above, but takes the extension as an UTF8 string. See AppendUTF8 for
// details on how this is handled.
// While all modern OSes support UTF-8, there is no requirement for the
// filenames to actually be UTF-8, e.g. on Linux. So appending UTF-8 could
// result in Mojibake filenames.
[[nodiscard]] FilePath AddExtensionUTF8(std::string_view extension) const;
// Replaces the extension of |file_name| with |extension|. If |file_name| // Replaces the extension of |file_name| with |extension|. If |file_name|
// does not have an extension, then |extension| is added. If |extension| is // does not have an extension, then |extension| is added. If |extension| is
// empty, then the extension is removed from |file_name|. // empty, then the extension is removed from |file_name|.
@ -372,6 +383,12 @@ class BASE_EXPORT FilePath {
// system paths will always be ASCII. // system paths will always be ASCII.
[[nodiscard]] FilePath AppendASCII(std::string_view component) const; [[nodiscard]] FilePath AppendASCII(std::string_view component) const;
// Like above, but takes the `component` as an UTF8 string.
// While all modern OSes support UTF-8, there is no requirement for the
// filenames to actually be UTF-8, e.g. on Linux. So appending UTF-8 could
// result in Mojibake filenames.
[[nodiscard]] FilePath AppendUTF8(std::string_view component) const;
// Returns true if this FilePath contains an absolute path. On Windows, an // Returns true if this FilePath contains an absolute path. On Windows, an
// absolute path begins with either a drive letter specification followed by // absolute path begins with either a drive letter specification followed by
// a separator character, or with two separator characters. On POSIX // a separator character, or with two separator characters. On POSIX

View file

@ -428,7 +428,7 @@ BASE_EXPORT bool CreateTemporaryFileInDir(const FilePath& dir,
// Returns the file name for a temporary file by using a platform-specific // Returns the file name for a temporary file by using a platform-specific
// naming scheme that incorporates |identifier|. // naming scheme that incorporates |identifier|.
BASE_EXPORT FilePath BASE_EXPORT FilePath
FormatTemporaryFileName(FilePath::StringPieceType identifier); FormatTemporaryFileName(FilePath::StringViewType identifier);
// Create and open a temporary file stream for exclusive read, write, and delete // Create and open a temporary file stream for exclusive read, write, and delete
// access. The full path is placed in `path`. Returns the opened file stream, or // access. The full path is placed in `path`. Returns the opened file stream, or
@ -463,7 +463,7 @@ BASE_EXPORT bool CreateNewTempDirectory(const FilePath::StringType& prefix,
// Extra characters will be appended to |prefix| to ensure that the // Extra characters will be appended to |prefix| to ensure that the
// new directory does not have the same name as an existing directory. // new directory does not have the same name as an existing directory.
BASE_EXPORT bool CreateTemporaryDirInDir(const FilePath& base_dir, BASE_EXPORT bool CreateTemporaryDirInDir(const FilePath& base_dir,
FilePath::StringPieceType prefix, FilePath::StringViewType prefix,
FilePath* new_dir); FilePath* new_dir);
// Creates a directory, as well as creating any parent directories, if they // Creates a directory, as well as creating any parent directories, if they

View file

@ -832,7 +832,7 @@ bool CreateTemporaryFileInDir(const FilePath& dir, FilePath* temp_file) {
return fd.is_valid(); return fd.is_valid();
} }
FilePath FormatTemporaryFileName(FilePath::StringPieceType identifier) { FilePath FormatTemporaryFileName(FilePath::StringViewType identifier) {
#if BUILDFLAG(IS_APPLE) #if BUILDFLAG(IS_APPLE)
std::string_view prefix = base::apple::BaseBundleID(); std::string_view prefix = base::apple::BaseBundleID();
#elif BUILDFLAG(GOOGLE_CHROME_BRANDING) #elif BUILDFLAG(GOOGLE_CHROME_BRANDING)
@ -881,7 +881,7 @@ static bool CreateTemporaryDirInDirImpl(const FilePath& base_dir,
} }
bool CreateTemporaryDirInDir(const FilePath& base_dir, bool CreateTemporaryDirInDir(const FilePath& base_dir,
FilePath::StringPieceType prefix, FilePath::StringViewType prefix,
FilePath* new_dir) { FilePath* new_dir) {
FilePath::StringType mkdtemp_template(prefix); FilePath::StringType mkdtemp_template(prefix);
mkdtemp_template.append("XXXXXX"); mkdtemp_template.append("XXXXXX");
@ -902,22 +902,25 @@ bool CreateNewTempDirectory(const FilePath::StringType& prefix,
bool CreateDirectoryAndGetError(const FilePath& full_path, File::Error* error) { bool CreateDirectoryAndGetError(const FilePath& full_path, File::Error* error) {
ScopedBlockingCall scoped_blocking_call( ScopedBlockingCall scoped_blocking_call(
FROM_HERE, BlockingType::MAY_BLOCK); // For call to mkdir(). FROM_HERE, BlockingType::MAY_BLOCK); // For call to mkdir().
std::vector<FilePath> subpaths; // Avoid checking subdirs if directory already exists.
if (DirectoryExists(full_path)) {
return true;
}
// Collect a list of all parent directories. // Collect a list of all missing directories.
std::vector<FilePath> missing_subpaths({full_path});
FilePath last_path = full_path; FilePath last_path = full_path;
subpaths.push_back(full_path);
for (FilePath path = full_path.DirName(); path.value() != last_path.value(); for (FilePath path = full_path.DirName(); path.value() != last_path.value();
path = path.DirName()) { path = path.DirName()) {
subpaths.push_back(path); if (DirectoryExists(path)) {
break;
}
missing_subpaths.push_back(path);
last_path = path; last_path = path;
} }
// Iterate through the parents and create the missing ones. // Iterate through the missing directories and create.
for (const FilePath& subpath : base::Reversed(subpaths)) { for (const FilePath& subpath : base::Reversed(missing_subpaths)) {
if (DirectoryExists(subpath)) {
continue;
}
if (mkdir(subpath.value().c_str(), 0700) == 0) { if (mkdir(subpath.value().c_str(), 0700) == 0) {
continue; continue;
} }

View file

@ -651,7 +651,7 @@ File CreateAndOpenTemporaryFileInDir(const FilePath& dir, FilePath* temp_file) {
GetLongPathName(temp_name.value().c_str(), long_temp_name, MAX_PATH); GetLongPathName(temp_name.value().c_str(), long_temp_name, MAX_PATH);
if (long_name_len != 0 && long_name_len <= MAX_PATH) { if (long_name_len != 0 && long_name_len <= MAX_PATH) {
*temp_file = *temp_file =
FilePath(FilePath::StringPieceType(long_temp_name, long_name_len)); FilePath(FilePath::StringViewType(long_temp_name, long_name_len));
} else { } else {
// GetLongPathName() failed, but we still have a temporary file. // GetLongPathName() failed, but we still have a temporary file.
*temp_file = std::move(temp_name); *temp_file = std::move(temp_name);
@ -664,7 +664,7 @@ bool CreateTemporaryFileInDir(const FilePath& dir, FilePath* temp_file) {
return CreateAndOpenTemporaryFileInDir(dir, temp_file).IsValid(); return CreateAndOpenTemporaryFileInDir(dir, temp_file).IsValid();
} }
FilePath FormatTemporaryFileName(FilePath::StringPieceType identifier) { FilePath FormatTemporaryFileName(FilePath::StringViewType identifier) {
return FilePath(StrCat({identifier, FILE_PATH_LITERAL(".tmp")})); return FilePath(StrCat({identifier, FILE_PATH_LITERAL(".tmp")}));
} }
@ -678,7 +678,7 @@ ScopedFILE CreateAndOpenTemporaryStreamInDir(const FilePath& dir,
} }
bool CreateTemporaryDirInDir(const FilePath& base_dir, bool CreateTemporaryDirInDir(const FilePath& base_dir,
FilePath::StringPieceType prefix, FilePath::StringViewType prefix,
FilePath* new_dir) { FilePath* new_dir) {
ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK); ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
@ -820,7 +820,7 @@ bool NormalizeFilePath(const FilePath& path, FilePath* real_path) {
// with the volume device path and existing code expects we return a path // with the volume device path and existing code expects we return a path
// starting 'X:\' so we need to call DevicePathToDriveLetterPath. // starting 'X:\' so we need to call DevicePathToDriveLetterPath.
if (!DevicePathToDriveLetterPath( if (!DevicePathToDriveLetterPath(
FilePath(FilePath::StringPieceType(native_file_path, used_wchars)), FilePath(FilePath::StringViewType(native_file_path, used_wchars)),
real_path)) { real_path)) {
return false; return false;
} }
@ -1092,7 +1092,7 @@ bool GetCurrentDirectory(FilePath* dir) {
// TODO(evanm): the old behavior of this function was to always strip the // TODO(evanm): the old behavior of this function was to always strip the
// trailing slash. We duplicate this here, but it shouldn't be necessary // trailing slash. We duplicate this here, but it shouldn't be necessary
// when everyone is using the appropriate FilePath APIs. // when everyone is using the appropriate FilePath APIs.
*dir = FilePath(FilePath::StringPieceType(system_buffer)) *dir = FilePath(FilePath::StringViewType(system_buffer))
.StripTrailingSeparators(); .StripTrailingSeparators();
return true; return true;
} }

View file

@ -40,7 +40,6 @@
#include "base/threading/thread.h" #include "base/threading/thread.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "build/chromeos_buildflags.h"
namespace base { namespace base {
@ -230,7 +229,7 @@ bool ImportantFileWriter::WriteFileAtomicallyImpl(
base::debug::Alias(path_copy); base::debug::Alias(path_copy);
#endif // BUILDFLAG(IS_WIN) && DCHECK_IS_ON() #endif // BUILDFLAG(IS_WIN) && DCHECK_IS_ON()
#if BUILDFLAG(IS_CHROMEOS_ASH) #if BUILDFLAG(IS_CHROMEOS)
// On Chrome OS, chrome gets killed when it cannot finish shutdown quickly, // On Chrome OS, chrome gets killed when it cannot finish shutdown quickly,
// and this function seems to be one of the slowest shutdown steps. // and this function seems to be one of the slowest shutdown steps.
// Include some info to the report for investigation. crbug.com/418627 // Include some info to the report for investigation. crbug.com/418627

View file

@ -20,7 +20,7 @@ std::optional<SafeBaseName> SafeBaseName::Create(const FilePath& path) {
// static // static
std::optional<SafeBaseName> SafeBaseName::Create( std::optional<SafeBaseName> SafeBaseName::Create(
FilePath::StringPieceType path) { FilePath::StringViewType path) {
return Create(FilePath(path)); return Create(FilePath(path));
} }

View file

@ -29,8 +29,8 @@ class BASE_EXPORT SafeBaseName {
// Factory method that returns a valid SafeBaseName or std::nullopt. // Factory method that returns a valid SafeBaseName or std::nullopt.
static std::optional<SafeBaseName> Create(const FilePath&); static std::optional<SafeBaseName> Create(const FilePath&);
// Same as above, but takes a StringPieceType for convenience. // Same as above, but takes a StringViewType for convenience.
static std::optional<SafeBaseName> Create(FilePath::StringPieceType); static std::optional<SafeBaseName> Create(FilePath::StringViewType);
const FilePath& path() const LIFETIME_BOUND { return path_; } const FilePath& path() const LIFETIME_BOUND { return path_; }
// Convenience functions. // Convenience functions.

View file

@ -118,10 +118,11 @@ void ScopedFxLogger::LogMessage(std::string_view file,
// global logs to the system logger. // global logs to the system logger.
fuchsia_syslog::LogBuffer buffer; fuchsia_syslog::LogBuffer buffer;
buffer.BeginRecord( buffer.BeginRecord(fuchsia_severity,
fuchsia_severity, cpp17::string_view(file.data(), file.size()), cpp17::string_view(file.data(), file.size()), line_number,
line_number, cpp17::string_view(msg.data(), msg.size()), socket_.borrow(), cpp17::string_view(msg.data(), msg.size()),
0, base::Process::Current().Pid(), base::PlatformThread::CurrentId()); socket_.borrow(), 0, base::Process::Current().Pid(),
base::PlatformThread::CurrentId().raw());
for (const auto& tag : tags_) { for (const auto& tag : tags_) {
buffer.WriteKeyValue("tag", tag); buffer.WriteKeyValue("tag", tag);
} }

View file

@ -6,7 +6,6 @@
#define BASE_FUNCTIONAL_FUNCTION_REF_H_ #define BASE_FUNCTIONAL_FUNCTION_REF_H_
#include <concepts> #include <concepts>
#include <string_view>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>

View file

@ -23,7 +23,6 @@
#include "base/strings/sys_string_conversions.h" #include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "third_party/icu/source/common/unicode/uniset.h" #include "third_party/icu/source/common/unicode/uniset.h"
#include "third_party/icu/source/i18n/unicode/coll.h" #include "third_party/icu/source/i18n/unicode/coll.h"
@ -312,7 +311,7 @@ bool LocaleAwareCompareFilenames(const FilePath& a, const FilePath& b) {
} }
void NormalizeFileNameEncoding(FilePath* file_name) { void NormalizeFileNameEncoding(FilePath* file_name) {
#if BUILDFLAG(IS_CHROMEOS_ASH) #if BUILDFLAG(IS_CHROMEOS)
std::string normalized_str; std::string normalized_str;
if (ConvertToUtf8AndNormalize(file_name->BaseName().value(), kCodepageUTF8, if (ConvertToUtf8AndNormalize(file_name->BaseName().value(), kCodepageUTF8,
&normalized_str) && &normalized_str) &&

View file

@ -10,7 +10,6 @@
#include "base/files/memory_mapped_file.h" #include "base/files/memory_mapped_file.h"
#include "base/i18n/base_i18n_export.h" #include "base/i18n/base_i18n_export.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#define ICU_UTIL_DATA_FILE 0 #define ICU_UTIL_DATA_FILE 0
#define ICU_UTIL_DATA_STATIC 1 #define ICU_UTIL_DATA_STATIC 1

View file

@ -15,7 +15,7 @@
#include "base/numerics/safe_conversions.h" #include "base/numerics/safe_conversions.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "build/chromeos_buildflags.h" #include "build/build_config.h"
#include "third_party/icu/source/common/unicode/locid.h" #include "third_party/icu/source/common/unicode/locid.h"
#include "third_party/icu/source/common/unicode/utypes.h" #include "third_party/icu/source/common/unicode/utypes.h"
#include "third_party/icu/source/i18n/unicode/datefmt.h" #include "third_party/icu/source/i18n/unicode/datefmt.h"
@ -169,7 +169,7 @@ std::u16string TimeFormatShortDateAndTimeWithTimeZone(const Time& time) {
return TimeFormat(*formatter, time); return TimeFormat(*formatter, time);
} }
#if BUILDFLAG(IS_CHROMEOS_ASH) #if BUILDFLAG(IS_CHROMEOS)
std::u16string TimeFormatMonthAndYearForTimeZone( std::u16string TimeFormatMonthAndYearForTimeZone(
const Time& time, const Time& time,
const icu::TimeZone* time_zone) { const icu::TimeZone* time_zone) {

View file

@ -13,7 +13,6 @@
#include "base/i18n/base_i18n_export.h" #include "base/i18n/base_i18n_export.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "third_party/icu/source/common/unicode/uversion.h" #include "third_party/icu/source/common/unicode/uversion.h"
U_NAMESPACE_BEGIN U_NAMESPACE_BEGIN
@ -81,12 +80,12 @@ BASE_I18N_EXPORT std::u16string TimeFormatShortDateNumeric(const Time& time);
// Returns a numeric date and time such as "12/13/52 2:44:30 PM". // Returns a numeric date and time such as "12/13/52 2:44:30 PM".
BASE_I18N_EXPORT std::u16string TimeFormatShortDateAndTime(const Time& time); BASE_I18N_EXPORT std::u16string TimeFormatShortDateAndTime(const Time& time);
#if BUILDFLAG(IS_CHROMEOS_ASH) #if BUILDFLAG(IS_CHROMEOS)
// Returns a month and year, e.g. "November 2007" for the specified time zone. // Returns a month and year, e.g. "November 2007" for the specified time zone.
BASE_I18N_EXPORT std::u16string TimeFormatMonthAndYearForTimeZone( BASE_I18N_EXPORT std::u16string TimeFormatMonthAndYearForTimeZone(
const Time& time, const Time& time,
const icu::TimeZone* time_zone); const icu::TimeZone* time_zone);
#endif // BUILDFLAG(IS_CHROMEOS_ASH) #endif // BUILDFLAG(IS_CHROMEOS)
// Returns a month and year, e.g. "November 2007" // Returns a month and year, e.g. "November 2007"
BASE_I18N_EXPORT std::u16string TimeFormatMonthAndYear(const Time& time); BASE_I18N_EXPORT std::u16string TimeFormatMonthAndYear(const Time& time);

View file

@ -2,11 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
#pragma allow_unsafe_buffers
#endif
#include "base/json/json_parser.h" #include "base/json/json_parser.h"
#include <algorithm> #include <algorithm>
@ -17,6 +12,7 @@
#include <vector> #include <vector>
#include "base/check_op.h" #include "base/check_op.h"
#include "base/compiler_specific.h"
#include "base/feature_list.h" #include "base/feature_list.h"
#include "base/features.h" #include "base/features.h"
#include "base/json/json_reader.h" #include "base/json/json_reader.h"
@ -204,7 +200,7 @@ std::optional<std::string_view> JSONParser::PeekChars(size_t count) {
// restructured the code so that we only stored the remaining data, that // restructured the code so that we only stored the remaining data, that
// would avoid this, but it would prevent rewinding (the places in this file // would avoid this, but it would prevent rewinding (the places in this file
// which look at `input_[index_ - 1]`.) // which look at `input_[index_ - 1]`.)
return std::string_view(input_.data() + index_, count); return UNSAFE_BUFFERS(std::string_view(input_.data() + index_, count));
} }
std::optional<char> JSONParser::PeekChar() { std::optional<char> JSONParser::PeekChar() {
@ -233,7 +229,8 @@ std::optional<char> JSONParser::ConsumeChar() {
const char* JSONParser::pos() { const char* JSONParser::pos() {
CHECK_LE(index_, input_.length()); CHECK_LE(index_, input_.length());
return input_.data() + index_; // SAFETY: Checked above.
return UNSAFE_BUFFERS(input_.data() + index_);
} }
JSONParser::Token JSONParser::GetNextToken() { JSONParser::Token JSONParser::GetNextToken() {

View file

@ -164,6 +164,17 @@ std::optional<Value::Dict> JSONReader::ReadDict(std::string_view json,
return std::move(*value).TakeDict(); return std::move(*value).TakeDict();
} }
// static
std::optional<Value::List> JSONReader::ReadList(std::string_view json,
int options,
size_t max_depth) {
std::optional<Value> value = Read(json, options, max_depth);
if (!value || !value->is_list()) {
return std::nullopt;
}
return std::move(*value).TakeList();
}
// static // static
JSONReader::Result JSONReader::ReadAndReturnValueWithError( JSONReader::Result JSONReader::ReadAndReturnValueWithError(
std::string_view json, std::string_view json,

View file

@ -123,6 +123,13 @@ class BASE_EXPORT JSONReader {
int options = JSON_PARSE_CHROMIUM_EXTENSIONS, int options = JSON_PARSE_CHROMIUM_EXTENSIONS,
size_t max_depth = internal::kAbsoluteMaxDepth); size_t max_depth = internal::kAbsoluteMaxDepth);
// Reads and parses |json|, returning a Value::List.
// If |json| is not a properly formed JSON list string, returns std::nullopt.
static std::optional<Value::List> ReadList(
std::string_view json,
int options = JSON_PARSE_CHROMIUM_EXTENSIONS,
size_t max_depth = internal::kAbsoluteMaxDepth);
// Reads and parses |json| like Read(). On success returns a Value as the // Reads and parses |json| like Read(). On success returns a Value as the
// expected value. Otherwise, it returns an Error instance, populated with a // expected value. Otherwise, it returns an Error instance, populated with a
// formatted error message, an error code, and the error location if // formatted error message, an error code, and the error location if

View file

@ -131,12 +131,18 @@ bool EscapeJSONString(std::u16string_view str,
std::string GetQuotedJSONString(std::string_view str) { std::string GetQuotedJSONString(std::string_view str) {
std::string dest; std::string dest;
// The output will always be at least str.size() + 2 bytes for the quote
// characters.
dest.reserve(str.size() + 2);
EscapeJSONStringImpl(str, true, &dest); EscapeJSONStringImpl(str, true, &dest);
return dest; return dest;
} }
std::string GetQuotedJSONString(std::u16string_view str) { std::string GetQuotedJSONString(std::u16string_view str) {
std::string dest; std::string dest;
// The output will always be at least str.size() + 2 bytes for the quote
// characters.
dest.reserve(str.size() + 2);
EscapeJSONStringImpl(str, true, &dest); EscapeJSONStringImpl(str, true, &dest);
return dest; return dest;
} }

View file

@ -33,13 +33,12 @@
#include "base/strings/string_tokenizer.h" #include "base/strings/string_tokenizer.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "build/chromeos_buildflags.h"
namespace base { namespace base {
namespace { namespace {
#if !BUILDFLAG(IS_CHROMEOS_ASH) #if !BUILDFLAG(IS_CHROMEOS)
std::string GetKeyValueFromOSReleaseFile(const std::string& input, std::string GetKeyValueFromOSReleaseFile(const std::string& input,
const char* key) { const char* key) {
StringPairs key_value_pairs; StringPairs key_value_pairs;
@ -97,7 +96,7 @@ class DistroNameGetter {
} }
} }
}; };
#endif // !BUILDFLAG(IS_CHROMEOS_ASH) #endif // !BUILDFLAG(IS_CHROMEOS)
bool GetThreadsFromProcessDir(const char* dir_path, std::vector<pid_t>* tids) { bool GetThreadsFromProcessDir(const char* dir_path, std::vector<pid_t>* tids) {
DirReaderPosix dir_reader(dir_path); DirReaderPosix dir_reader(dir_path);
@ -125,7 +124,7 @@ constexpr int kDistroSize = 128 + 1;
// We use this static string to hold the Linux distro info. If we // We use this static string to hold the Linux distro info. If we
// crash, the crash handler code will send this in the crash dump. // crash, the crash handler code will send this in the crash dump.
char g_linux_distro[kDistroSize] = char g_linux_distro[kDistroSize] =
#if BUILDFLAG(IS_CHROMEOS_ASH) #if BUILDFLAG(IS_CHROMEOS)
"CrOS"; "CrOS";
#elif BUILDFLAG(IS_ANDROID) #elif BUILDFLAG(IS_ANDROID)
"Android"; "Android";
@ -141,15 +140,15 @@ char g_linux_distro[kDistroSize] =
BASE_EXPORT std::string GetKeyValueFromOSReleaseFileForTesting( BASE_EXPORT std::string GetKeyValueFromOSReleaseFileForTesting(
const std::string& input, const std::string& input,
const char* key) { const char* key) {
#if !BUILDFLAG(IS_CHROMEOS_ASH) #if !BUILDFLAG(IS_CHROMEOS)
return GetKeyValueFromOSReleaseFile(input, key); return GetKeyValueFromOSReleaseFile(input, key);
#else #else
return ""; return "";
#endif // !BUILDFLAG(IS_CHROMEOS_ASH) #endif // !BUILDFLAG(IS_CHROMEOS)
} }
std::string GetLinuxDistro() { std::string GetLinuxDistro() {
#if !BUILDFLAG(IS_CHROMEOS_ASH) #if !BUILDFLAG(IS_CHROMEOS)
// We do this check only once per process. If it fails, there's // We do this check only once per process. If it fails, there's
// little reason to believe it will work if we attempt to run it again. // little reason to believe it will work if we attempt to run it again.
static DistroNameGetter distro_name_getter; static DistroNameGetter distro_name_getter;

View file

@ -2,11 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
#pragma allow_unsafe_buffers
#endif
#include "base/location.h" #include "base/location.h"
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
@ -25,7 +20,7 @@ namespace {
// Returns the length of the given null terminated c-string. // Returns the length of the given null terminated c-string.
constexpr size_t StrLen(const char* str) { constexpr size_t StrLen(const char* str) {
size_t str_len = 0; size_t str_len = 0;
for (str_len = 0; str[str_len] != '\0'; ++str_len) for (str_len = 0; UNSAFE_TODO(str[str_len]) != '\0'; ++str_len)
; ;
return str_len; return str_len;
} }
@ -63,7 +58,7 @@ constexpr bool StrEndsWith(const char* name,
return false; return false;
} }
for (size_t i = 0; i < expected_len; ++i) { for (size_t i = 0; i < expected_len; ++i) {
if (name[i + prefix_len] != expected[i]) { if (UNSAFE_TODO(name[i + prefix_len] != expected[i])) {
return false; return false;
} }
} }
@ -135,15 +130,15 @@ void Location::WriteIntoTrace(perfetto::TracedValue context) const {
NOINLINE Location Location::Current(const char* function_name, NOINLINE Location Location::Current(const char* function_name,
const char* file_name, const char* file_name,
int line_number) { int line_number) {
return Location(function_name, file_name + kStrippedPrefixLength, line_number, return Location(function_name, UNSAFE_TODO(file_name + kStrippedPrefixLength),
RETURN_ADDRESS()); line_number, RETURN_ADDRESS());
} }
// static // static
NOINLINE Location Location::CurrentWithoutFunctionName(const char* file_name, NOINLINE Location Location::CurrentWithoutFunctionName(const char* file_name,
int line_number) { int line_number) {
return Location(nullptr, file_name + kStrippedPrefixLength, line_number, return Location(nullptr, UNSAFE_TODO(file_name + kStrippedPrefixLength),
RETURN_ADDRESS()); line_number, RETURN_ADDRESS());
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View file

@ -2,11 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
#pragma allow_unsafe_buffers
#endif
#include "base/logging.h" #include "base/logging.h"
#include <limits.h> #include <limits.h>
@ -28,6 +23,7 @@
#include "base/base_export.h" #include "base/base_export.h"
#include "base/base_switches.h" #include "base/base_switches.h"
#include "base/command_line.h" #include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/containers/stack.h" #include "base/containers/stack.h"
#include "base/debug/alias.h" #include "base/debug/alias.h"
#include "base/debug/crash_logging.h" #include "base/debug/crash_logging.h"
@ -55,7 +51,6 @@
#include "base/trace_event/base_tracing.h" #include "base/trace_event/base_tracing.h"
#include "base/vlog.h" #include "base/vlog.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "third_party/abseil-cpp/absl/base/internal/raw_logging.h" #include "third_party/abseil-cpp/absl/base/internal/raw_logging.h"
#include "third_party/abseil-cpp/absl/cleanup/cleanup.h" #include "third_party/abseil-cpp/absl/cleanup/cleanup.h"
@ -115,7 +110,7 @@ typedef FILE* FileHandle;
#include "base/android/jni_android.h" #include "base/android/jni_android.h"
#endif #endif
#if BUILDFLAG(IS_CHROMEOS_ASH) #if BUILDFLAG(IS_CHROMEOS)
#include "base/files/scoped_file.h" #include "base/files/scoped_file.h"
#endif #endif
@ -208,7 +203,7 @@ static_assert(LOGGING_NUM_SEVERITIES == std::size(log_severity_names),
const char* log_severity_name(int severity) { const char* log_severity_name(int severity) {
if (severity >= 0 && severity < LOGGING_NUM_SEVERITIES) { if (severity >= 0 && severity < LOGGING_NUM_SEVERITIES) {
return log_severity_names[severity]; return UNSAFE_TODO(log_severity_names[severity]);
} }
return "UNKNOWN"; return "UNKNOWN";
} }
@ -436,7 +431,8 @@ void WriteToFd(int fd, const char* data, size_t length) {
size_t bytes_written = 0; size_t bytes_written = 0;
long rv; long rv;
while (bytes_written < length) { while (bytes_written < length) {
rv = HANDLE_EINTR(write(fd, data + bytes_written, length - bytes_written)); rv = HANDLE_EINTR(
write(fd, UNSAFE_TODO(data + bytes_written), length - bytes_written));
if (rv < 0) { if (rv < 0) {
// Give up, nothing we can do now. // Give up, nothing we can do now.
break; break;
@ -480,7 +476,7 @@ std::string BuildCrashString(const char* file,
#endif // BUILDFLAG(IS_WIN) #endif // BUILDFLAG(IS_WIN)
); );
if (slash) { if (slash) {
file = slash + 1; file = UNSAFE_TODO(slash + 1);
} }
} }
@ -552,13 +548,13 @@ bool BaseInitLoggingImpl(const LoggingSettings& settings) {
// default log file will re-initialize to the new options. // default log file will re-initialize to the new options.
CloseLogFileUnlocked(); CloseLogFileUnlocked();
#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_WIN) #if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
if (settings.log_file) { if (settings.log_file) {
CHECK(settings.log_file_path.empty(), base::NotFatalUntil::M127); CHECK(settings.log_file_path.empty(), base::NotFatalUntil::M127);
g_log_file = settings.log_file; g_log_file = settings.log_file;
return true; return true;
} }
#endif // BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_WIN) #endif // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
CHECK(!settings.log_file_path.empty(), base::NotFatalUntil::M127) CHECK(!settings.log_file_path.empty(), base::NotFatalUntil::M127)
<< "LOG_TO_FILE set but no log_file_path!"; << "LOG_TO_FILE set but no log_file_path!";
@ -956,7 +952,7 @@ void LogMessage::Flush() {
std::string LogMessage::BuildCrashString() const { std::string LogMessage::BuildCrashString() const {
return logging::BuildCrashString(file(), line(), return logging::BuildCrashString(file(), line(),
str().c_str() + message_start_); UNSAFE_TODO(str().c_str() + message_start_));
} }
// writes the common header info to the stream // writes the common header info to the stream
@ -1175,7 +1171,7 @@ void CloseLogFile() {
CloseLogFileUnlocked(); CloseLogFileUnlocked();
} }
#if BUILDFLAG(IS_CHROMEOS_ASH) #if BUILDFLAG(IS_CHROMEOS)
FILE* DuplicateLogFILE() { FILE* DuplicateLogFILE() {
if ((g_logging_destination & LOG_TO_FILE) == 0 || if ((g_logging_destination & LOG_TO_FILE) == 0 ||
!InitializeLogFileHandle()) { !InitializeLogFileHandle()) {
@ -1223,7 +1219,7 @@ ScopedLoggingSettings::ScopedLoggingSettings()
logging_destination_(g_logging_destination), logging_destination_(g_logging_destination),
#if BUILDFLAG(IS_CHROMEOS) #if BUILDFLAG(IS_CHROMEOS)
log_format_(g_log_format), log_format_(g_log_format),
#endif // BUILDFLAG(IS_CHROMEOS_ASH) #endif // BUILDFLAG(IS_CHROMEOS)
enable_process_id_(g_log_process_id), enable_process_id_(g_log_process_id),
enable_thread_id_(g_log_thread_id), enable_thread_id_(g_log_thread_id),
enable_timestamp_(g_log_timestamp), enable_timestamp_(g_log_timestamp),
@ -1265,14 +1261,14 @@ ScopedLoggingSettings::~ScopedLoggingSettings() {
void ScopedLoggingSettings::SetLogFormat(LogFormat log_format) const { void ScopedLoggingSettings::SetLogFormat(LogFormat log_format) const {
g_log_format = log_format; g_log_format = log_format;
} }
#endif // BUILDFLAG(IS_CHROMEOS_ASH) #endif // BUILDFLAG(IS_CHROMEOS)
void RawLog(int level, const char* message) { void RawLog(int level, const char* message) {
if (level >= g_min_log_level && message) { if (level >= g_min_log_level && message) {
const size_t message_len = strlen(message); const size_t message_len = strlen(message);
WriteToFd(STDERR_FILENO, message, message_len); WriteToFd(STDERR_FILENO, message, message_len);
if (message_len > 0 && message[message_len - 1] != '\n') { if (message_len > 0 && UNSAFE_TODO(message[message_len - 1]) != '\n') {
long rv; long rv;
do { do {
rv = HANDLE_EINTR(write(STDERR_FILENO, "\n", 1)); rv = HANDLE_EINTR(write(STDERR_FILENO, "\n", 1));

View file

@ -21,6 +21,8 @@
#include "base/logging/log_severity.h" #include "base/logging/log_severity.h"
#include "base/strings/utf_ostream_operators.h" #include "base/strings/utf_ostream_operators.h"
#include "build/build_config.h" #include "build/build_config.h"
// TODO(crbug.com/354842935): Remove this include once other files don't
// accidentally (transitively) depend on it anymore.
#include "build/chromeos_buildflags.h" #include "build/chromeos_buildflags.h"
#if BUILDFLAG(IS_CHROMEOS) #if BUILDFLAG(IS_CHROMEOS)
@ -728,7 +730,7 @@ class BASE_EXPORT ErrnoLogMessageFatal final : public ErrnoLogMessage {
// after this call. // after this call.
BASE_EXPORT void CloseLogFile(); BASE_EXPORT void CloseLogFile();
#if BUILDFLAG(IS_CHROMEOS_ASH) #if BUILDFLAG(IS_CHROMEOS)
// Returns a new file handle that will write to the same destination as the // Returns a new file handle that will write to the same destination as the
// currently open log file. Returns nullptr if logging to a file is disabled, // currently open log file. Returns nullptr if logging to a file is disabled,
// or if opening the file failed. This is intended to be used to initialize // or if opening the file failed. This is intended to be used to initialize

View file

@ -1,5 +1,4 @@
arthursonzogni@chromium.org arthursonzogni@chromium.org
bartekn@chromium.org
dcheng@chromium.org dcheng@chromium.org
glazunov@google.com glazunov@google.com
keishi@chromium.org keishi@chromium.org

View file

@ -105,8 +105,7 @@ class OneShotDelayedBackgroundTimer::TaskImpl final
Stop(); Stop();
} }
DCHECK(GetTaskRunner()->RunsTasksInCurrentSequence()); DCHECK(GetTaskRunner()->RunsTasksInCurrentSequence());
base::AutoLock locker( base::AutoLock locker(android::PreFreezeBackgroundMemoryTrimmer::lock());
android::PreFreezeBackgroundMemoryTrimmer::Instance().lock_);
task_ = android::PreFreezeBackgroundMemoryTrimmer::Instance() task_ = android::PreFreezeBackgroundMemoryTrimmer::Instance()
.PostDelayedBackgroundTaskModernHelper( .PostDelayedBackgroundTaskModernHelper(
GetTaskRunner(), from_here, std::move(task), delay); GetTaskRunner(), from_here, std::move(task), delay);

View file

@ -57,7 +57,7 @@ remains an Undefined Behavior.
`raw_ptr<T>` protection is enabled by default in all non-Renderer processes, on: `raw_ptr<T>` protection is enabled by default in all non-Renderer processes, on:
- Android (incl. AndroidWebView, Android WebEngine, & Android ChromeCast) - Android (incl. AndroidWebView, Android WebEngine, & Android ChromeCast)
- Windows - Windows
- ChromeOS (incl. Ash & Lacros) - ChromeOS
- macOS - macOS
- Linux - Linux
- Fuchsia - Fuchsia

View file

@ -85,13 +85,6 @@
#include "base/sequence_checker.h" #include "base/sequence_checker.h"
#include "base/synchronization/atomic_flag.h" #include "base/synchronization/atomic_flag.h"
namespace performance_manager {
class FrameNodeImpl;
class PageNodeImpl;
class ProcessNodeImpl;
class WorkerNodeImpl;
} // namespace performance_manager
namespace base { namespace base {
namespace sequence_manager::internal { namespace sequence_manager::internal {
@ -348,10 +341,6 @@ class BASE_EXPORT BindWeakPtrFactoryPassKey {
BindWeakPtrFactoryPassKey() = default; BindWeakPtrFactoryPassKey() = default;
friend class BindWeakPtrFactoryForTesting; friend class BindWeakPtrFactoryForTesting;
friend class performance_manager::FrameNodeImpl;
friend class performance_manager::PageNodeImpl;
friend class performance_manager::ProcessNodeImpl;
friend class performance_manager::WorkerNodeImpl;
friend class sequence_manager::internal::TaskQueueImpl; friend class sequence_manager::internal::TaskQueueImpl;
}; };

View file

@ -9,12 +9,15 @@
// types representing MessagePumpForIO. // types representing MessagePumpForIO.
#include "base/message_loop/ios_cronet_buildflags.h" #include "base/message_loop/ios_cronet_buildflags.h"
#include "build/blink_buildflags.h"
#include "build/build_config.h" #include "build/build_config.h"
#if BUILDFLAG(IS_WIN) #if BUILDFLAG(IS_WIN)
#include "base/message_loop/message_pump_win.h" #include "base/message_loop/message_pump_win.h"
#elif BUILDFLAG(IS_IOS) && BUILDFLAG(CRONET_BUILD) #elif BUILDFLAG(IS_IOS) && BUILDFLAG(CRONET_BUILD)
#include "base/message_loop/message_pump_io_ios.h" #include "base/message_loop/message_pump_io_ios.h"
#elif BUILDFLAG(IS_IOS) && BUILDFLAG(USE_BLINK)
#include "base/message_loop/message_pump_io_ios_libdispatch.h"
#elif BUILDFLAG(IS_APPLE) #elif BUILDFLAG(IS_APPLE)
#include "base/message_loop/message_pump_kqueue.h" #include "base/message_loop/message_pump_kqueue.h"
#elif BUILDFLAG(IS_NACL) #elif BUILDFLAG(IS_NACL)
@ -32,6 +35,8 @@ namespace base {
using MessagePumpForIO = MessagePumpForIO; using MessagePumpForIO = MessagePumpForIO;
#elif BUILDFLAG(IS_IOS) && BUILDFLAG(CRONET_BUILD) #elif BUILDFLAG(IS_IOS) && BUILDFLAG(CRONET_BUILD)
using MessagePumpForIO = MessagePumpIOSForIO; using MessagePumpForIO = MessagePumpIOSForIO;
#elif BUILDFLAG(IS_IOS) && BUILDFLAG(USE_BLINK)
using MessagePumpForIO = MessagePumpIOSForIOLibdispatch;
#elif BUILDFLAG(IS_APPLE) #elif BUILDFLAG(IS_APPLE)
using MessagePumpForIO = MessagePumpKqueue; using MessagePumpForIO = MessagePumpKqueue;
#elif BUILDFLAG(IS_NACL) #elif BUILDFLAG(IS_NACL)

Some files were not shown because too many files have changed in this diff Show more