Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -3230,8 +3230,6 @@ ORIGIN: ../../../flutter/shell/platform/windows/windows_lifecycle_manager.cc + .
ORIGIN: ../../../flutter/shell/platform/windows/windows_lifecycle_manager.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/windows/windows_proc_table.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/windows/windows_proc_table.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/windows/windows_registry.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/windows/windows_registry.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/windows/windowsx_shim.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/profiling/sampling_profiler.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/profiling/sampling_profiler.h + ../../../flutter/LICENSE
Expand Down Expand Up @@ -5928,8 +5926,6 @@ FILE: ../../../flutter/shell/platform/windows/windows_lifecycle_manager.cc
FILE: ../../../flutter/shell/platform/windows/windows_lifecycle_manager.h
FILE: ../../../flutter/shell/platform/windows/windows_proc_table.cc
FILE: ../../../flutter/shell/platform/windows/windows_proc_table.h
FILE: ../../../flutter/shell/platform/windows/windows_registry.cc
FILE: ../../../flutter/shell/platform/windows/windows_registry.h
FILE: ../../../flutter/shell/platform/windows/windowsx_shim.h
FILE: ../../../flutter/shell/profiling/sampling_profiler.cc
FILE: ../../../flutter/shell/profiling/sampling_profiler.h
Expand Down
2 changes: 0 additions & 2 deletions shell/platform/windows/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,6 @@ source_set("flutter_windows_source") {
"windows_lifecycle_manager.h",
"windows_proc_table.cc",
"windows_proc_table.h",
"windows_registry.cc",
"windows_registry.h",
"windowsx_shim.h",
]

Expand Down
8 changes: 2 additions & 6 deletions shell/platform/windows/flutter_windows_engine.cc
Original file line number Diff line number Diff line change
Expand Up @@ -156,12 +156,9 @@ FlutterLocale CovertToFlutterLocale(const LanguageInfo& info) {

} // namespace

FlutterWindowsEngine::FlutterWindowsEngine(
const FlutterProjectBundle& project,
std::unique_ptr<WindowsRegistry> registry)
FlutterWindowsEngine::FlutterWindowsEngine(const FlutterProjectBundle& project)
: project_(std::make_unique<FlutterProjectBundle>(project)),
aot_data_(nullptr, nullptr),
windows_registry_(std::move(registry)),
lifecycle_manager_(std::make_unique<WindowsLifecycleManager>(this)) {
embedder_api_.struct_size = sizeof(FlutterEngineProcTable);
FlutterEngineGetProcAddresses(&embedder_api_);
Expand Down Expand Up @@ -571,8 +568,7 @@ void FlutterWindowsEngine::SetLifecycleState(flutter::AppLifecycleState state) {
}

void FlutterWindowsEngine::SendSystemLocales() {
std::vector<LanguageInfo> languages =
GetPreferredLanguageInfo(*windows_registry_);
std::vector<LanguageInfo> languages = GetPreferredLanguageInfo();
std::vector<FlutterLocale> flutter_locales;
flutter_locales.reserve(languages.size());
for (const auto& info : languages) {
Expand Down
11 changes: 1 addition & 10 deletions shell/platform/windows/flutter_windows_engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
#include "flutter/shell/platform/windows/window_proc_delegate_manager.h"
#include "flutter/shell/platform/windows/window_state.h"
#include "flutter/shell/platform/windows/windows_lifecycle_manager.h"
#include "flutter/shell/platform/windows/windows_registry.h"
#include "third_party/rapidjson/include/rapidjson/document.h"

namespace flutter {
Expand Down Expand Up @@ -77,13 +76,8 @@ static void WindowsPlatformThreadPrioritySetter(
// run in headless mode.
class FlutterWindowsEngine {
public:
// Creates a new Flutter engine with an injectible windows registry.
FlutterWindowsEngine(const FlutterProjectBundle& project,
std::unique_ptr<WindowsRegistry> windows_registry);

// Creates a new Flutter engine object configured to run |project|.
explicit FlutterWindowsEngine(const FlutterProjectBundle& project)
: FlutterWindowsEngine(project, std::make_unique<WindowsRegistry>()) {}
explicit FlutterWindowsEngine(const FlutterProjectBundle& project);

virtual ~FlutterWindowsEngine();

Expand Down Expand Up @@ -405,9 +399,6 @@ class FlutterWindowsEngine {
// The on frame drawn callback.
fml::closure next_frame_callback_;

// Wrapper providing Windows registry access.
std::unique_ptr<WindowsRegistry> windows_registry_;

// Handler for top level window messages.
std::unique_ptr<WindowsLifecycleManager> lifecycle_manager_;

Expand Down
56 changes: 14 additions & 42 deletions shell/platform/windows/system_utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,79 +8,48 @@

#include <sstream>

#include "flutter/fml/logging.h"
#include "flutter/fml/platform/win/wstring_conversion.h"

namespace flutter {

std::vector<LanguageInfo> GetPreferredLanguageInfo(
const WindowsRegistry& registry) {
std::vector<std::wstring> languages = GetPreferredLanguages(registry);
std::vector<LanguageInfo> GetPreferredLanguageInfo() {
std::vector<std::wstring> languages = GetPreferredLanguages();
std::vector<LanguageInfo> language_info;
language_info.reserve(languages.size());

for (auto language : languages) {
FML_LOG(ERROR) << "Pushing " << fml::WideStringToUtf8(language);
language_info.push_back(ParseLanguageName(language));
}
FML_LOG(ERROR) << "Got " << language_info.size() << "langs";
return language_info;
}

std::wstring GetPreferredLanguagesFromRegistry(const WindowsRegistry& registry,
ULONG buffer_size) {
std::wstring buffer(buffer_size, '\0');
if (registry.GetRegistryValue(HKEY_CURRENT_USER, kGetPreferredLanguageRegKey,
kGetPreferredLanguageRegValue,
RRF_RT_REG_MULTI_SZ, NULL, buffer.data(),
&buffer_size) != ERROR_SUCCESS) {
return std::wstring();
}
return buffer;
}

std::wstring GetPreferredLanguagesFromMUI() {
ULONG buffer_size;
ULONG count = 0;
DWORD flags = MUI_LANGUAGE_NAME | MUI_UI_FALLBACK;
if (!GetThreadPreferredUILanguages(flags, &count, nullptr, &buffer_size)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is GetThreadPreferredUILanguages or GetPreferredUILanguages preferable? Should we use one as a fallback for the other?

Our partner team switch to GetPreferredUILanguages, but comments indicate this might have been unintended. We should make sure we align to prevent inconsistencies. See: http://cl/544490185

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like they are using the same method as here, there. And re: your comment on WindowsProcTable, this shouldn't be necessary. Looks like I missed a nuance of the parameters to the function that didn't make a difference locally but did on devicelab

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like they are using the same method as here, there

Ah you're right, I got confused by their helper's name.

And re: your comment on WindowsProcTable, this shouldn't be necessary.

The current tests depend on the machines environment. For example, the tests would fail if somehow a machine was configured such that GetThreadPreferredUILanguages returns no languages.

In my mind, the ideal test would be an integration test that mocks GetThreadPreferredUILanguages and then checks that the Windows embedder sends the expected FlutterLocale to the embedder API at startup. Through our mocks we can guarantee that the machine's language configuration can't cause unexpected test flakes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we sure that:
a) This is a concern, e.g. that the environment can return no preferred languages? The test already in place always expected at least one valid language, and I do not know if a windows env can have zero preferred languages between the thread, process, user, and system. And,
b) Doing so will not obscure the purpose of this test?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we sure that:
This is a concern, e.g. that the environment can return no preferred languages?

This is a hypothetical scenario, yes. Another hypothetical scenario would be that GetThreadPreferredUILanguages fails and returns false. These hypothetical scenarios would cause flakes. To reduce this likelihood, our tests should be deterministic and we should control their inputs.

Doing so will not obscure the purpose of this test?

My only concern is using the real GetThreadPreferredUILanguages implementation in the test. I'm flexible on the test itself, I'd be happy with your current test too if GetThreadPreferredUILanguages was mocked out :)

FML_LOG(ERROR) << "Failure on first call " << GetLastError();
return std::wstring();
}
std::wstring buffer(buffer_size, '\0');
if (!GetThreadPreferredUILanguages(flags, &count, buffer.data(),
&buffer_size)) {
FML_LOG(ERROR) << "Failure on second call " << GetLastError();
return std::wstring();
}
FML_LOG(ERROR) << "Succeeded and buffer=" << fml::WideStringToUtf8(buffer);
return buffer;
}

std::vector<std::wstring> GetPreferredLanguages(
const WindowsRegistry& registry) {
std::vector<std::wstring> GetPreferredLanguages() {
std::vector<std::wstring> languages;
BOOL languages_from_registry = TRUE;
ULONG buffer_size = 0;
ULONG count = 0;
DWORD flags = MUI_LANGUAGE_NAME | MUI_UI_FALLBACK;

// Determine where languages are defined and get buffer length
if (registry.GetRegistryValue(HKEY_CURRENT_USER, kGetPreferredLanguageRegKey,
kGetPreferredLanguageRegValue,
RRF_RT_REG_MULTI_SZ, NULL, NULL,
&buffer_size) != ERROR_SUCCESS) {
languages_from_registry = FALSE;
}

// Multi-string must be at least 3-long if non-empty,
// as a multi-string is terminated with 2 nulls.
//
// See:
// https://learn.microsoft.com/windows/win32/sysinfo/registry-value-types
if (languages_from_registry && buffer_size < 3) {
languages_from_registry = FALSE;
}

// Initialize the buffer
std::wstring buffer =
languages_from_registry
? GetPreferredLanguagesFromRegistry(registry, buffer_size)
: GetPreferredLanguagesFromMUI();
std::wstring buffer = GetPreferredLanguagesFromMUI();
FML_LOG(ERROR) << "Got buffer " << fml::WideStringToUtf8(buffer);

// Extract the individual languages from the buffer.
size_t start = 0;
Expand All @@ -91,6 +60,9 @@ std::vector<std::wstring> GetPreferredLanguages(
}
// Read the next null-terminated language.
std::wstring language(buffer.c_str() + start);
// TODO(schectman): Using for debugging on the devlab machine
FML_LOG(ERROR) << "GETTING LANGAUGES FROM MUI RETURNED: "
<< fml::WideStringToUtf8(language);
if (language.empty()) {
break;
}
Expand Down
12 changes: 2 additions & 10 deletions shell/platform/windows/system_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@
#include <string>
#include <vector>

#include "flutter/shell/platform/windows/windows_registry.h"

namespace flutter {

// Registry key for user-preferred languages.
Expand All @@ -28,21 +26,15 @@ struct LanguageInfo {

// Returns the list of user-preferred languages, in preference order,
// parsed into LanguageInfo structures.
std::vector<LanguageInfo> GetPreferredLanguageInfo(
const WindowsRegistry& registry);

// Retrieve the preferred languages from the registry.
std::wstring GetPreferredLanguagesFromRegistry(const WindowsRegistry& registry,
ULONG buffer_size);
std::vector<LanguageInfo> GetPreferredLanguageInfo();

// Retrieve the preferred languages from the MUI API.
std::wstring GetPreferredLanguagesFromMUI();

// Returns the list of user-preferred languages, in preference order.
// The language names are as described at:
// https://docs.microsoft.com/en-us/windows/win32/intl/language-names
std::vector<std::wstring> GetPreferredLanguages(
const WindowsRegistry& registry);
std::vector<std::wstring> GetPreferredLanguages();

// Parses a Windows language name into its components.
LanguageInfo ParseLanguageName(std::wstring language_name);
Expand Down
59 changes: 14 additions & 45 deletions shell/platform/windows/system_utils_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,66 +12,35 @@
namespace flutter {
namespace testing {

class MockWindowsRegistry : public WindowsRegistry {
public:
MockWindowsRegistry() = default;
virtual ~MockWindowsRegistry() = default;

virtual LSTATUS GetRegistryValue(HKEY hkey,
LPCWSTR key,
LPCWSTR value,
DWORD flags,
LPDWORD type,
PVOID data,
LPDWORD data_size) const {
using namespace std::string_literals;
static const std::wstring locales =
L"en-US\0zh-Hans-CN\0ja\0zh-Hant-TW\0he\0\0"s;
static DWORD locales_len = locales.size() * sizeof(wchar_t);
if (data != nullptr) {
if (*data_size < locales_len) {
return ERROR_MORE_DATA;
}
std::memcpy(data, locales.data(), locales_len);
*data_size = locales_len;
} else if (data_size != NULL) {
*data_size = locales_len;
}
return ERROR_SUCCESS;
}

private:
FML_DISALLOW_COPY_AND_ASSIGN(MockWindowsRegistry);
};

TEST(SystemUtils, GetPreferredLanguageInfo) {
WindowsRegistry registry;
std::vector<LanguageInfo> languages = GetPreferredLanguageInfo(registry);
std::vector<LanguageInfo> languages = GetPreferredLanguageInfo();
// There should be at least one language.
ASSERT_GE(languages.size(), 1);
// The info should have a valid languge.
EXPECT_GE(languages[0].language.size(), 2);
}

TEST(SystemUtils, GetPreferredLanguages) {
WindowsRegistry registry;
std::vector<std::wstring> languages = GetPreferredLanguages(registry);
std::vector<std::wstring> languages = GetPreferredLanguages();
// There should be at least one language.
ASSERT_GE(languages.size(), 1);
// The language should be non-empty.
EXPECT_FALSE(languages[0].empty());
// There should not be a trailing null from the parsing step.
EXPECT_EQ(languages[0].size(), wcslen(languages[0].c_str()));

// Test mock results
MockWindowsRegistry mock_registry;
languages = GetPreferredLanguages(mock_registry);
ASSERT_EQ(languages.size(), 5);
ASSERT_EQ(languages[0], std::wstring(L"en-US"));
ASSERT_EQ(languages[1], std::wstring(L"zh-Hans-CN"));
ASSERT_EQ(languages[2], std::wstring(L"ja"));
ASSERT_EQ(languages[3], std::wstring(L"zh-Hant-TW"));
ASSERT_EQ(languages[4], std::wstring(L"he"));
// Get actual system language.
std::wstring wdl_msz = GetPreferredLanguagesFromMUI();
auto wdl_itr = wdl_msz.begin();
for (auto languages_itr = languages.begin(); languages_itr != languages.end();
languages_itr++) {
for (auto lang_itr = languages_itr->begin();
lang_itr != languages_itr->end(); lang_itr++) {
EXPECT_EQ(*lang_itr, *wdl_itr++);
}
EXPECT_EQ(*wdl_itr++, 0);
}
EXPECT_EQ(*wdl_itr, 0);
}

TEST(SystemUtils, ParseLanguageNameGeneric) {
Expand Down
19 changes: 0 additions & 19 deletions shell/platform/windows/windows_registry.cc

This file was deleted.

39 changes: 0 additions & 39 deletions shell/platform/windows/windows_registry.h

This file was deleted.