mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Embed ICU data inside libflutter.so on Android (#7588)
Prior to this the Android embedder code would extract the icudtl.dat asset out of the APK and write it to local disk during the first startup of the app. This change will make that work unnecessary and eliminate the risk of ICU failures due to errors in the extraction process.
This commit is contained in:
parent
c92df428ef
commit
050dcaad60
2
DEPS
2
DEPS
@ -116,7 +116,7 @@ allowed_hosts = [
|
||||
]
|
||||
|
||||
deps = {
|
||||
'src': 'https://github.com/flutter/buildroot.git' + '@' + '19317704cfb7be72c7d81953f634674ea8bee5ea',
|
||||
'src': 'https://github.com/flutter/buildroot.git' + '@' + '13ca742ec8b3d7761877197d74b003d3e646d805',
|
||||
|
||||
# Fuchsia compatibility
|
||||
#
|
||||
|
||||
@ -391,6 +391,7 @@ FILE: ../../../flutter/shell/platform/android/android_context_gl.cc
|
||||
FILE: ../../../flutter/shell/platform/android/android_context_gl.h
|
||||
FILE: ../../../flutter/shell/platform/android/android_environment_gl.cc
|
||||
FILE: ../../../flutter/shell/platform/android/android_environment_gl.h
|
||||
FILE: ../../../flutter/shell/platform/android/android_exports.lst
|
||||
FILE: ../../../flutter/shell/platform/android/android_external_texture_gl.cc
|
||||
FILE: ../../../flutter/shell/platform/android/android_external_texture_gl.h
|
||||
FILE: ../../../flutter/shell/platform/android/android_native_window.cc
|
||||
|
||||
@ -105,6 +105,7 @@ struct Settings {
|
||||
bool verbose_logging = false;
|
||||
std::string log_tag = "flutter";
|
||||
std::string icu_data_path;
|
||||
MappingCallback icu_mapper;
|
||||
|
||||
// Assets settings
|
||||
fml::UniqueFD::element_type assets_dir =
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
#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"
|
||||
|
||||
@ -22,6 +23,10 @@ class ICUContext {
|
||||
valid_ = SetupMapping(icu_data_path) && SetupICU();
|
||||
}
|
||||
|
||||
ICUContext(std::unique_ptr<Mapping> mapping) : mapping_(std::move(mapping)) {
|
||||
valid_ = SetupICU();
|
||||
}
|
||||
|
||||
~ICUContext() = default;
|
||||
|
||||
bool SetupMapping(const std::string& icu_data_path) {
|
||||
@ -99,5 +104,17 @@ void InitializeICU(const std::string& icu_data_path) {
|
||||
[&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) {
|
||||
std::call_once(g_icu_init_flag, [mapping = std::move(mapping)]() mutable {
|
||||
InitializeICUFromMappingOnce(std::move(mapping));
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace icu
|
||||
} // namespace fml
|
||||
|
||||
@ -8,12 +8,15 @@
|
||||
#include <string>
|
||||
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "flutter/fml/mapping.h"
|
||||
|
||||
namespace fml {
|
||||
namespace icu {
|
||||
|
||||
void InitializeICU(const std::string& icu_data_path = "");
|
||||
|
||||
void InitializeICUFromMapping(std::unique_ptr<Mapping> mapping);
|
||||
|
||||
} // namespace icu
|
||||
} // namespace fml
|
||||
|
||||
|
||||
@ -189,6 +189,8 @@ static void PerformInitializationTasks(const blink::Settings& settings) {
|
||||
|
||||
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.";
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "flutter/fml/native_library.h"
|
||||
#include "flutter/fml/paths.h"
|
||||
#include "flutter/fml/string_view.h"
|
||||
#include "flutter/shell/version/version.h"
|
||||
@ -121,6 +122,17 @@ static bool GetSwitchValue(const fml::CommandLine& command_line,
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_ptr<fml::Mapping> GetSymbolMapping(std::string symbol_prefix) {
|
||||
fml::RefPtr<fml::NativeLibrary> proc_library =
|
||||
fml::NativeLibrary::CreateForCurrentProcess();
|
||||
const uint8_t* mapping =
|
||||
proc_library->ResolveSymbol((symbol_prefix + "_start").c_str());
|
||||
const intptr_t size = reinterpret_cast<intptr_t>(
|
||||
proc_library->ResolveSymbol((symbol_prefix + "_size").c_str()));
|
||||
FML_CHECK(mapping && size) << "Unable to resolve symbols: " << symbol_prefix;
|
||||
return std::make_unique<fml::NonOwnedMapping>(mapping, size);
|
||||
}
|
||||
|
||||
blink::Settings SettingsFromCommandLine(const fml::CommandLine& command_line) {
|
||||
blink::Settings settings = {};
|
||||
|
||||
@ -213,6 +225,14 @@ blink::Settings SettingsFromCommandLine(const fml::CommandLine& command_line) {
|
||||
|
||||
command_line.GetOptionValue(FlagForSwitch(Switch::ICUDataFilePath),
|
||||
&settings.icu_data_path);
|
||||
if (command_line.HasOption(FlagForSwitch(Switch::ICUSymbolPrefix))) {
|
||||
std::string icu_symbol_prefix;
|
||||
command_line.GetOptionValue(FlagForSwitch(Switch::ICUSymbolPrefix),
|
||||
&icu_symbol_prefix);
|
||||
settings.icu_mapper = [icu_symbol_prefix] {
|
||||
return GetSymbolMapping(icu_symbol_prefix);
|
||||
};
|
||||
}
|
||||
|
||||
settings.use_test_fonts =
|
||||
command_line.HasOption(FlagForSwitch(Switch::UseTestFonts));
|
||||
|
||||
@ -48,6 +48,10 @@ DEF_SWITCH(AotIsolateSnapshotInstructions,
|
||||
"read and executable. AotSnapshotPath must be present.")
|
||||
DEF_SWITCH(CacheDirPath, "cache-dir-path", "Path to the cache directory.")
|
||||
DEF_SWITCH(ICUDataFilePath, "icu-data-file-path", "Path to the ICU data file.")
|
||||
DEF_SWITCH(ICUSymbolPrefix,
|
||||
"icu-symbol-prefix",
|
||||
"Prefix for the symbols representing ICU data linked into the "
|
||||
"Flutter library.")
|
||||
DEF_SWITCH(DartFlags,
|
||||
"dart-flags",
|
||||
"Flags passed directly to the Dart VM without being interpreted "
|
||||
|
||||
@ -49,10 +49,12 @@ shared_library("flutter_shell_native") {
|
||||
"platform_view_android_jni.h",
|
||||
"vsync_waiter_android.cc",
|
||||
"vsync_waiter_android.h",
|
||||
"$root_build_dir/flutter_icu/icudtl.o",
|
||||
]
|
||||
|
||||
deps = [
|
||||
":android_gpu_configuration",
|
||||
":icudtl_object",
|
||||
"$flutter_root/assets",
|
||||
"$flutter_root/common",
|
||||
"$flutter_root/flow",
|
||||
@ -90,6 +92,8 @@ shared_library("flutter_shell_native") {
|
||||
"EGL",
|
||||
"GLESv2",
|
||||
]
|
||||
|
||||
ldflags = ["-Wl,--version-script=" + rebase_path("android_exports.lst")]
|
||||
}
|
||||
|
||||
java_library("flutter_shell_java") {
|
||||
@ -200,19 +204,25 @@ java_prebuilt("android_arch_lifecycle_viewmodel") {
|
||||
jar_path = "//third_party/android_support/android_arch_lifecycle_viewmodel.jar"
|
||||
}
|
||||
|
||||
copy("flutter_shell_assets") {
|
||||
visibility = [ ":*" ]
|
||||
action("icudtl_object") {
|
||||
script = "$flutter_root/sky/tools/objcopy.py"
|
||||
|
||||
sources = [
|
||||
"//third_party/icu/flutter/icudtl.dat",
|
||||
icudtl_input = "//third_party/icu/flutter/icudtl.dat"
|
||||
icudtl_output = "$root_build_dir/flutter_icu/icudtl.o"
|
||||
|
||||
inputs = [
|
||||
"$icudtl_input",
|
||||
]
|
||||
|
||||
outputs = [
|
||||
"$root_build_dir/flutter_shell_assets/{{source_file_part}}",
|
||||
"$icudtl_output",
|
||||
]
|
||||
|
||||
deps = [
|
||||
"//third_party/icu:icudata",
|
||||
args = [
|
||||
"--objcopy", rebase_path(android_objcopy),
|
||||
"--input", rebase_path(icudtl_input),
|
||||
"--output", rebase_path(icudtl_output),
|
||||
"--arch", current_cpu,
|
||||
]
|
||||
}
|
||||
|
||||
@ -222,7 +232,6 @@ action("android") {
|
||||
inputs = [
|
||||
"$root_build_dir/flutter_java.jar",
|
||||
"$root_build_dir/lib.stripped/libflutter.so",
|
||||
"$root_build_dir/flutter_shell_assets/icudtl.dat",
|
||||
]
|
||||
|
||||
outputs = [
|
||||
@ -234,8 +243,6 @@ action("android") {
|
||||
rebase_path("flutter.jar", root_build_dir, root_build_dir),
|
||||
"--dist_jar",
|
||||
rebase_path("flutter_java.jar", root_build_dir, root_build_dir),
|
||||
"--asset_dir",
|
||||
rebase_path("flutter_shell_assets", root_build_dir, root_build_dir),
|
||||
"--native_lib",
|
||||
rebase_path("lib.stripped/libflutter.so", root_build_dir, root_build_dir),
|
||||
"--android_abi",
|
||||
@ -243,7 +250,6 @@ action("android") {
|
||||
]
|
||||
|
||||
deps = [
|
||||
":flutter_shell_assets",
|
||||
":flutter_shell_java",
|
||||
":flutter_shell_native",
|
||||
]
|
||||
|
||||
14
shell/platform/android/android_exports.lst
Normal file
14
shell/platform/android/android_exports.lst
Normal file
@ -0,0 +1,14 @@
|
||||
# Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
# Linker script that exports the minimal symbols required for libflutter.so
|
||||
|
||||
{
|
||||
global:
|
||||
JNI_OnLoad;
|
||||
_binary_icudtl_dat_start;
|
||||
_binary_icudtl_dat_size;
|
||||
local:
|
||||
*;
|
||||
};
|
||||
@ -62,10 +62,6 @@ public class FlutterMain {
|
||||
private static final String DEFAULT_KERNEL_BLOB = "kernel_blob.bin";
|
||||
private static final String DEFAULT_FLUTTER_ASSETS_DIR = "flutter_assets";
|
||||
|
||||
// Assets that are shared among all Flutter apps within an APK.
|
||||
private static final String SHARED_ASSET_DIR = "flutter_shared";
|
||||
private static final String SHARED_ASSET_ICU_DATA = "icudtl.dat";
|
||||
|
||||
private static String fromFlutterAssets(String filePath) {
|
||||
return sFlutterAssetsDir + File.separator + filePath;
|
||||
}
|
||||
@ -85,7 +81,6 @@ public class FlutterMain {
|
||||
private static boolean sIsPrecompiledAsBlobs;
|
||||
private static boolean sIsPrecompiledAsSharedLibrary;
|
||||
private static Settings sSettings;
|
||||
private static String sIcuDataPath;
|
||||
|
||||
private static final class ImmutableSetBuilder<T> {
|
||||
static <T> ImmutableSetBuilder<T> newInstance() {
|
||||
@ -188,7 +183,7 @@ public class FlutterMain {
|
||||
sResourceExtractor.waitForCompletion();
|
||||
|
||||
List<String> shellArgs = new ArrayList<>();
|
||||
shellArgs.add("--icu-data-file-path=" + sIcuDataPath);
|
||||
shellArgs.add("--icu-symbol-prefix=_binary_icudtl_dat");
|
||||
if (args != null) {
|
||||
Collections.addAll(shellArgs, args);
|
||||
}
|
||||
@ -284,10 +279,6 @@ public class FlutterMain {
|
||||
|
||||
sResourceExtractor = new ResourceExtractor(context);
|
||||
|
||||
String icuAssetPath = SHARED_ASSET_DIR + File.separator + SHARED_ASSET_ICU_DATA;
|
||||
sResourceExtractor.addResource(icuAssetPath);
|
||||
sIcuDataPath = PathUtils.getDataDirectory(applicationContext) + File.separator + icuAssetPath;
|
||||
|
||||
sResourceExtractor
|
||||
.addResource(fromFlutterAssets(sFlx))
|
||||
.addResource(fromFlutterAssets(sAotVmSnapshotData))
|
||||
|
||||
49
sky/tools/objcopy.py
Normal file
49
sky/tools/objcopy.py
Normal file
@ -0,0 +1,49 @@
|
||||
#!/usr/bin/env python
|
||||
# Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
# BFD architecture names recognized by objcopy.
|
||||
BFD_ARCH = {
|
||||
'arm': 'arm',
|
||||
'arm64': 'aarch64',
|
||||
'x86': 'i386',
|
||||
'x64': 'i386:x86-64',
|
||||
}
|
||||
|
||||
# BFD target names recognized by objcopy.
|
||||
BFD_TARGET = {
|
||||
'arm': 'elf32-littlearm',
|
||||
'arm64': 'elf64-littleaarch64',
|
||||
'x86': 'elf32-i386',
|
||||
'x64': 'elf64-x86-64',
|
||||
}
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Convert a data file to an object file')
|
||||
parser.add_argument('--objcopy', type=str, required=True)
|
||||
parser.add_argument('--input', type=str, required=True)
|
||||
parser.add_argument('--output', type=str, required=True)
|
||||
parser.add_argument('--arch', type=str, required=True)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
input_dir, input_file = os.path.split(args.input)
|
||||
output_path = os.path.abspath(args.output)
|
||||
|
||||
subprocess.check_call([
|
||||
args.objcopy,
|
||||
'-I', 'binary',
|
||||
'-O', BFD_TARGET[args.arch],
|
||||
'-B', BFD_ARCH[args.arch],
|
||||
input_file,
|
||||
output_path,
|
||||
], cwd=input_dir)
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
Loading…
x
Reference in New Issue
Block a user