Skip to content

Make MacStatsConfigUtilImpl stateless#1496

Open
yukawa wants to merge 1 commit intogoogle:masterfrom
ciceroaware:remove_singleton_from_stats_config_util_prep
Open

Make MacStatsConfigUtilImpl stateless#1496
yukawa wants to merge 1 commit intogoogle:masterfrom
ciceroaware:remove_singleton_from_stats_config_util_prep

Conversation

@yukawa
Copy link
Copy Markdown
Collaborator

@yukawa yukawa commented Apr 29, 2026

Description

This is a preparation step for removing the Singleton<T> dependency in config/stats_config_util.cc. The two member fields of MacStatsConfigUtilImpl were process-global state expressed as instance state (only one instance has ever existed, courtesy of Singleton):

  • config_file_ cached "${user_profile_dir}/.usagestats.db". SystemUtil::GetUserProfileDirectory() is already called from many places, so caching its result inside this one class does not buy much. If profiling shows the call is hot, the right fix is to memoize it inside SystemUtil so every caller benefits.
  • mutex_ serialized the multi-step file read/write sequence in SetEnabled against concurrent callers. Process-global protection is what we have had so far, so it is now a constinit absl::Mutex at namespace scope, matching the established pattern in base/android_util.cc and renderer/win32/win32_renderer_client.cc.

The class now holds no state, which makes the subsequent Singleton<T> removal mechanical. There is no observable behavioral change in production.

Note that we have had zero test coverage of MacStatsConfigUtilImpl for a long time. Filling the gap has been actually difficult in practice because a naive test would write to "${HOME}/.usagestats.db" and chmod it, clobbering the developer's real opt-in/out state.

Now that SystemUtil::SetUserProfileDirectory() takes effect immediately inside the implementation, the standard TestWithTempUserProfile fixture is sufficient to redirect the file into a per-test temp dir.

The new tests cover both branches of the CHANNEL_DEV switch for MacStatsConfigUtilImpl:

  • Stable (!CHANNEL_DEV): default-false when no file exists, the set/get round-trip for both true and false, and that SetEnabled can overwrite a previously-written value. The last one is load-bearing because SetEnabled chmods the file to read-only after writing, so a subsequent SetEnabled must chmod it back to writable before truncating; this test exercises that round-trip.
  • Dev channel: IsEnabled returns true regardless of file state, and SetEnabled is a no-op that never creates the file on disk.

Issue IDs

N/A

Steps to test new behaviors (if any)

  • Should be covered with CI for GOOGLE_JAPANESE_INPUT_BUILD.

@yukawa yukawa force-pushed the remove_singleton_from_stats_config_util_prep branch 2 times, most recently from 3b303d7 to 14d0291 Compare April 29, 2026 16:58
This is a preparation step for removing the Singleton<T> dependency in
config/stats_config_util.cc. The two member fields of
MacStatsConfigUtilImpl were process-global state expressed as instance
state (only one instance has ever existed, courtesy of Singleton<T>):

  * config_file_ cached "${user_profile_dir}/.usagestats.db".
    SystemUtil::GetUserProfileDirectory() is already called from many
    places, so caching its result inside this one class does not buy
    much. If profiling shows the call is hot, the right fix is to
    memoize it inside SystemUtil so every caller benefits.
  * "mutex_" serialized the multi-step file read/write sequence in
    "SetEnabled" against concurrent callers. Process-global protection
    is what we have had so far, so it is now a "constinit absl::Mutex"
    at namespace scope, matching the established pattern in
    "base/android_util.cc" and
    "renderer/win32/win32_renderer_client.cc".

The class now holds no state, which makes the subsequent "Singleton<T>"
removal mechanical. There is no observable behavioral change in
production.

Note that we have had zero test coverage of MacStatsConfigUtilImpl for
a long time. Filling the gap has been actually difficult in practice
because a naive test would write to "${HOME}/.usagestats.db" and chmod
it, clobbering the developer's real opt-in/out state.

Now that "SystemUtil::SetUserProfileDirectory()" takes effect
immediately inside the implementation, the standard
"TestWithTempUserProfile" fixture is sufficient to redirect the file
into a per-test temp dir.

The new tests cover both branches of the CHANNEL_DEV switch for
MacStatsConfigUtilImpl:

  * Stable (!CHANNEL_DEV): default-false when no file exists, the
    set/get round-trip for both "true" and "false", and that
    "SetEnabled" can overwrite a previously-written value. The last one
    is load-bearing because "SetEnabled" chmods the file to read-only
    after writing, so a subsequent "SetEnabled" must chmod it back to
    writable before truncating; this test exercises that round-trip.
  * Dev channel: "IsEnabled" returns "true" regardless of file state,
    and "SetEnabled" is a no-op that never creates the file on disk.
@yukawa yukawa force-pushed the remove_singleton_from_stats_config_util_prep branch from 14d0291 to c08b197 Compare April 29, 2026 16:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant