未验证 提交 bd8c5b13 编写于 作者: C Chinmay Garde 提交者: GitHub

Only allow mappings for ICU initialization. (#8656)

If the mapping callback is not set or it the callback returns invalid data, ICU initialization will be embedder responsibility.

This affects all embedders and the following have been audited:
* Android: Via a symbol mapping.
* iOS: Via a file mapping.
* Embedder: Via a file mapping.
* Fuchsia: Via a VMO mapping
* Test shells and Flutter tester: Via file mapping with ICU data needing to be next to the executable.
上级 206cab6e
......@@ -10,7 +10,8 @@ namespace benchmarking {
int Main(int argc, char** argv) {
benchmark::Initialize(&argc, argv);
fml::icu::InitializeICU("icudtl.dat");
fml::icu::InitializeICU(fml::FileMapping::CreateReadOnly(
fml::OpenDirectoryOfExecutable(), "icudtl.dat"));
::benchmark::RunSpecifiedBenchmarks();
return 0;
}
......
......@@ -132,12 +132,6 @@ struct Settings {
bool verbose_logging = false;
std::string log_tag = "flutter";
// The icu_initialization_required setting does not have a corresponding
// switch because it is intended to be decided during build time, not runtime.
// Some companies apply source modification here because their build system
// brings its own ICU data files.
bool icu_initialization_required = true;
std::string icu_data_path;
MappingCallback icu_mapper;
// Assets settings
......
......@@ -5,6 +5,7 @@
#include "flutter/fml/file.h"
#include "flutter/fml/logging.h"
#include "flutter/fml/paths.h"
namespace fml {
......@@ -58,4 +59,14 @@ ScopedTemporaryDirectory::~ScopedTemporaryDirectory() {
}
}
fml::UniqueFD OpenDirectoryOfExecutable() {
auto result = paths::GetExecutableDirectoryPath();
if (!result.first) {
return {};
}
return OpenFile(result.second.c_str(), false, FilePermission::kRead);
}
} // namespace fml
......@@ -46,6 +46,8 @@ fml::UniqueFD OpenDirectory(const fml::UniqueFD& base_directory,
bool create_if_necessary,
FilePermission permission);
fml::UniqueFD OpenDirectoryOfExecutable();
fml::UniqueFD Duplicate(fml::UniqueFD::element_type descriptor);
bool IsDirectory(const fml::UniqueFD& directory);
......
......@@ -4,115 +4,24 @@
#include "flutter/fml/icu_util.h"
#include <memory>
#include <mutex>
#include "flutter/fml/build_config.h"
#include "flutter/fml/logging.h"
#include "flutter/fml/mapping.h"
#include "flutter/fml/native_library.h"
#include "flutter/fml/paths.h"
#include "third_party/icu/source/common/unicode/udata.h"
namespace fml {
namespace icu {
class ICUContext {
public:
ICUContext(const std::string& icu_data_path) : valid_(false) {
valid_ = SetupMapping(icu_data_path) && SetupICU();
void InitializeICU(std::unique_ptr<const Mapping> mapping) {
if (mapping == nullptr || mapping->GetSize() == 0) {
return;
}
ICUContext(std::unique_ptr<Mapping> mapping) : mapping_(std::move(mapping)) {
valid_ = SetupICU();
}
~ICUContext() = default;
bool SetupMapping(const std::string& icu_data_path) {
// Check if the path exists and it readable directly.
auto fd =
fml::OpenFile(icu_data_path.c_str(), false, fml::FilePermission::kRead);
// Check the path relative to the current executable.
if (!fd.is_valid()) {
auto directory = fml::paths::GetExecutableDirectoryPath();
if (!directory.first) {
return false;
}
std::string path_relative_to_executable =
paths::JoinPaths({directory.second, icu_data_path});
fd = fml::OpenFile(path_relative_to_executable.c_str(), false,
fml::FilePermission::kRead);
}
if (!fd.is_valid()) {
return false;
}
std::initializer_list<FileMapping::Protection> protection = {
fml::FileMapping::Protection::kRead};
auto file_mapping =
std::make_unique<FileMapping>(fd, std::move(protection));
if (file_mapping->GetSize() != 0) {
mapping_ = std::move(file_mapping);
return true;
}
return false;
}
bool SetupICU() {
if (GetSize() == 0) {
return false;
}
UErrorCode err_code = U_ZERO_ERROR;
udata_setCommonData(GetMapping(), &err_code);
return (err_code == U_ZERO_ERROR);
}
const uint8_t* GetMapping() const {
return mapping_ ? mapping_->GetMapping() : nullptr;
}
size_t GetSize() const { return mapping_ ? mapping_->GetSize() : 0; }
bool IsValid() const { return valid_; }
private:
bool valid_;
std::unique_ptr<Mapping> mapping_;
FML_DISALLOW_COPY_AND_ASSIGN(ICUContext);
};
void InitializeICUOnce(const std::string& icu_data_path) {
static ICUContext* context = new ICUContext(icu_data_path);
FML_CHECK(context->IsValid())
<< "Must be able to initialize the ICU context. Tried: " << icu_data_path;
}
std::once_flag g_icu_init_flag;
void InitializeICU(const std::string& icu_data_path) {
std::call_once(g_icu_init_flag,
[&icu_data_path]() { InitializeICUOnce(icu_data_path); });
}
void InitializeICUFromMappingOnce(std::unique_ptr<Mapping> mapping) {
static ICUContext* context = new ICUContext(std::move(mapping));
FML_CHECK(context->IsValid())
<< "Unable to initialize the ICU context from a mapping.";
}
void InitializeICUFromMapping(std::unique_ptr<Mapping> mapping) {
static std::once_flag g_icu_init_flag;
std::call_once(g_icu_init_flag, [mapping = std::move(mapping)]() mutable {
InitializeICUFromMappingOnce(std::move(mapping));
static auto icu_mapping = std::move(mapping);
UErrorCode err_code = U_ZERO_ERROR;
udata_setCommonData(icu_mapping->GetMapping(), &err_code);
FML_CHECK(err_code == U_ZERO_ERROR) << "Must be able to initialize ICU.";
});
}
......
......@@ -13,9 +13,7 @@
namespace fml {
namespace icu {
void InitializeICU(const std::string& icu_data_path = "");
void InitializeICUFromMapping(std::unique_ptr<Mapping> mapping);
void InitializeICU(std::unique_ptr<const Mapping> mapping);
} // namespace icu
} // namespace fml
......
......@@ -193,14 +193,8 @@ static void PerformInitializationTasks(const Settings& settings) {
FML_DLOG(INFO) << "Skia deterministic rendering is enabled.";
}
if (settings.icu_initialization_required) {
if (settings.icu_data_path.size() != 0) {
fml::icu::InitializeICU(settings.icu_data_path);
} else if (settings.icu_mapper) {
fml::icu::InitializeICUFromMapping(settings.icu_mapper());
} else {
FML_DLOG(WARNING) << "Skipping ICU initialization in the shell.";
}
if (settings.icu_mapper) {
fml::icu::InitializeICU(settings.icu_mapper());
}
});
}
......
......@@ -242,9 +242,20 @@ Settings SettingsFromCommandLine(const fml::CommandLine& command_line) {
command_line.GetOptionValue(FlagForSwitch(Switch::CacheDirPath),
&settings.temp_directory_path);
if (settings.icu_initialization_required) {
{
// ICU from a data file.
std::string icu_data_path;
command_line.GetOptionValue(FlagForSwitch(Switch::ICUDataFilePath),
&settings.icu_data_path);
&icu_data_path);
if (icu_data_path.size() > 0) {
settings.icu_mapper = [icu_data_path]() {
return fml::FileMapping::CreateReadOnly(icu_data_path);
};
}
}
{
// ICU from a symbol in a dynamic library
if (command_line.HasOption(FlagForSwitch(Switch::ICUSymbolPrefix))) {
std::string icu_symbol_prefix, native_lib_path;
command_line.GetOptionValue(FlagForSwitch(Switch::ICUSymbolPrefix),
......
......@@ -59,10 +59,13 @@ static flutter::Settings DefaultSettingsForProcess(NSBundle* bundle = nil) {
// defaults.
// Flutter ships the ICU data file in the the bundle of the engine. Look for it there.
if (settings.icu_data_path.size() == 0) {
if (!settings.icu_mapper) {
NSString* icuDataPath = [engineBundle pathForResource:@"icudtl" ofType:@"dat"];
if (icuDataPath.length > 0) {
settings.icu_data_path = icuDataPath.UTF8String;
auto icu_data_path = std::string{icuDataPath.UTF8String};
settings.icu_mapper = [icu_data_path]() {
return fml::FileMapping::CreateReadOnly(icu_data_path);
};
}
}
......
......@@ -370,7 +370,12 @@ FlutterEngineResult FlutterEngineRun(size_t version,
PopulateSnapshotMappingCallbacks(args, settings);
settings.icu_data_path = icu_data_path;
if (!settings.icu_mapper) {
settings.icu_mapper = [icu_data_path]() {
return fml::FileMapping::CreateReadOnly(icu_data_path);
};
}
settings.assets_path = args->assets_path;
if (!flutter::DartVM::IsRunningPrecompiledCode()) {
......
......@@ -251,8 +251,14 @@ int main(int argc, char* argv[]) {
return EXIT_FAILURE;
}
if (settings.icu_data_path.size() == 0) {
settings.icu_data_path = "icudtl.dat";
// Using command line arguments, the user can specify the ICU data as being
// present in either a file or a dynamic library. If no such specification has
// been, default to icudtl.dat.
if (!settings.icu_mapper) {
settings.icu_mapper = []() {
return fml::FileMapping::CreateReadOnly(fml::OpenDirectoryOfExecutable(),
"icudtl.dat");
};
}
// The tools that read logs get confused if there is a log tag specified.
......
......@@ -36,7 +36,9 @@ int main(int argc, char** argv) {
}
FML_DCHECK(txt::GetFontDir().length() > 0);
fml::icu::InitializeICU("icudtl.dat");
fml::icu::InitializeICU(fml::FileMapping::CreateReadOnly(
fml::OpenDirectoryOfExecutable(), "icudtl.dat"));
SkGraphics::Init();
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册