Commit 368afac8 authored by zpeng's avatar zpeng Committed by Commit Bot

Reland of Deduplicate Monochrome locale .paks

Instead of using system webview's resource whitelist, now uses a
generated list of resource IDs that are actually packed into
Webview's locale paks. This fixes the missing strings issue.

Original issue:
https://codereview.chromium.org/2980773002/

TBR=agrieve@chromium.org,dpranke@chromium.org,thestig@chromium.org,sadrul@chromium.org
# Not skipping CQ checks because original CL landed more than 1 days
ago.
BUG=724110, 742388

Review-Url: https://codereview.chromium.org/2977993002
Cr-Commit-Position: refs/heads/master@{#487176}
parent 7d1476b8
...@@ -41,6 +41,10 @@ app_hooks_impl = "java/src/org/chromium/chrome/browser/AppHooksImpl.java" ...@@ -41,6 +41,10 @@ app_hooks_impl = "java/src/org/chromium/chrome/browser/AppHooksImpl.java"
if (enable_resource_whitelist_generation) { if (enable_resource_whitelist_generation) {
monochrome_resource_whitelist = monochrome_resource_whitelist =
"$target_gen_dir/monochrome_resource_whitelist.txt" "$target_gen_dir/monochrome_resource_whitelist.txt"
system_webview_locale_resource_id_list =
"$target_gen_dir/system_webview_locale_resource_id_list.txt"
monochrome_locale_whitelist =
"$target_gen_dir/monochrome_locale_whitelist.txt"
} }
jinja_template("chrome_public_android_manifest") { jinja_template("chrome_public_android_manifest") {
...@@ -728,9 +732,66 @@ if (current_toolchain == default_toolchain) { ...@@ -728,9 +732,66 @@ if (current_toolchain == default_toolchain) {
"/libmonochrome$shlib_extension.whitelist" "/libmonochrome$shlib_extension.whitelist"
output = monochrome_resource_whitelist output = monochrome_resource_whitelist
} }
# Use custom resource ID list instead of android_webview's compiler
# resource whitelist because //android_webview: generate_webui_resources
# and //android_webview: generate_components_resources use hand-written
# resource whitelists.
action("system_webview_locale_resource_id_list") {
script = "//tools/grit/pak_util.py"
_system_webview_en_US_locale_pak =
"$root_out_dir/android_webview/locales/en-US.pak"
inputs = [
_system_webview_en_US_locale_pak,
]
outputs = [
system_webview_locale_resource_id_list,
]
deps = [
"//android_webview:repack_locales",
]
args = [
"list-id",
"--output",
rebase_path(system_webview_locale_resource_id_list, root_build_dir),
rebase_path(_system_webview_en_US_locale_pak, root_build_dir),
]
}
action("monochrome_locale_whitelist") {
script = "//tools/resources/filter_resource_whitelist.py"
inputs = [
monochrome_resource_whitelist,
system_webview_locale_resource_id_list,
]
outputs = [
monochrome_locale_whitelist,
]
deps = [
":monochrome_resource_whitelist",
":system_webview_locale_resource_id_list",
"//android_webview:system_webview_pak_whitelist",
]
args = [
"--input",
rebase_path(monochrome_resource_whitelist, root_build_dir),
"--filter",
rebase_path(system_webview_locale_resource_id_list, root_build_dir),
"--output",
rebase_path(monochrome_locale_whitelist, root_build_dir),
]
}
} }
# This target does not output locale paks.
chrome_paks("monochrome_paks") { chrome_paks("monochrome_paks") {
output_dir = "$target_gen_dir/$target_name" output_dir = "$target_gen_dir/$target_name"
...@@ -739,12 +800,25 @@ if (current_toolchain == default_toolchain) { ...@@ -739,12 +800,25 @@ if (current_toolchain == default_toolchain) {
"//android_webview:generate_aw_resources", "//android_webview:generate_aw_resources",
] ]
exclude_locale_paks = true
if (enable_resource_whitelist_generation) { if (enable_resource_whitelist_generation) {
repack_whitelist = monochrome_resource_whitelist repack_whitelist = monochrome_resource_whitelist
deps += [ ":monochrome_resource_whitelist" ] deps += [ ":monochrome_resource_whitelist" ]
locale_whitelist = monochrome_locale_whitelist
deps += [ ":monochrome_locale_whitelist" ]
}
}
# This target is separate from monochrome_pak_assets because it does not
# disable compression.
android_assets("monochrome_locale_pak_assets") {
sources = []
foreach(_locale, locales - android_chrome_omitted_locales) {
sources += [ "$target_gen_dir/monochrome_paks/locales/$_locale.pak" ]
} }
deps = [
":monochrome_paks",
]
} }
# This target explicitly includes locale paks via deps. # This target explicitly includes locale paks via deps.
...@@ -756,7 +830,7 @@ if (current_toolchain == default_toolchain) { ...@@ -756,7 +830,7 @@ if (current_toolchain == default_toolchain) {
disable_compression = true disable_compression = true
deps = [ deps = [
":chrome_public_locale_pak_assets", ":monochrome_locale_pak_assets",
":monochrome_paks", ":monochrome_paks",
"//android_webview:locale_pak_assets", "//android_webview:locale_pak_assets",
] ]
......
...@@ -877,6 +877,16 @@ void ChromeMainDelegate::PreSandboxStartup() { ...@@ -877,6 +877,16 @@ void ChromeMainDelegate::PreSandboxStartup() {
ResourceBundle::InitSharedInstanceWithPakFileRegion(base::File(pak_fd), ResourceBundle::InitSharedInstanceWithPakFileRegion(base::File(pak_fd),
pak_region); pak_region);
// Load secondary locale .pak file if it exists.
pak_fd = global_descriptors->MaybeGet(kAndroidSecondaryLocalePakDescriptor);
if (pak_fd != -1) {
pak_region = global_descriptors->GetRegion(
kAndroidSecondaryLocalePakDescriptor);
ResourceBundle::GetSharedInstance().
LoadSecondaryLocaleDataWithPakFileRegion(
base::File(pak_fd), pak_region);
}
int extra_pak_keys[] = { int extra_pak_keys[] = {
kAndroidChrome100PercentPakDescriptor, kAndroidChrome100PercentPakDescriptor,
kAndroidUIResourcesPakDescriptor, kAndroidUIResourcesPakDescriptor,
......
...@@ -80,6 +80,10 @@ int ChromeBrowserMainPartsAndroid::PreCreateThreads() { ...@@ -80,6 +80,10 @@ int ChromeBrowserMainPartsAndroid::PreCreateThreads() {
crash_dump_dir, kAndroidMinidumpDescriptor)); crash_dump_dir, kAndroidMinidumpDescriptor));
} }
// Auto-detect based on en-US whether secondary locale .pak files exist.
ui::SetLoadSecondaryLocalePaks(
!ui::GetPathForAndroidLocalePakWithinApk("en-US").empty());
return ChromeBrowserMainParts::PreCreateThreads(); return ChromeBrowserMainParts::PreCreateThreads();
} }
......
...@@ -2727,6 +2727,12 @@ void ChromeContentBrowserClient::GetAdditionalMappedFilesForChildProcess( ...@@ -2727,6 +2727,12 @@ void ChromeContentBrowserClient::GetAdditionalMappedFilesForChildProcess(
fd = ui::GetLocalePackFd(&region); fd = ui::GetLocalePackFd(&region);
mappings->ShareWithRegion(kAndroidLocalePakDescriptor, fd, region); mappings->ShareWithRegion(kAndroidLocalePakDescriptor, fd, region);
// Optional secondary locale .pak file.
fd = ui::GetSecondaryLocalePackFd(&region);
if (fd != -1) {
mappings->ShareWithRegion(kAndroidSecondaryLocalePakDescriptor, fd, region);
}
breakpad::CrashDumpObserver::GetInstance()->BrowserChildProcessStarted( breakpad::CrashDumpObserver::GetInstance()->BrowserChildProcessStarted(
child_process_id, mappings); child_process_id, mappings);
......
...@@ -184,7 +184,7 @@ template("chrome_extra_paks") { ...@@ -184,7 +184,7 @@ template("chrome_extra_paks") {
# output_dir [required]: Directory to output .pak files. Locale .pak files # output_dir [required]: Directory to output .pak files. Locale .pak files
# will always be place in $output_dir/locales # will always be place in $output_dir/locales
# additional_extra_paks: List of extra .pak sources for resources.pak. # additional_extra_paks: List of extra .pak sources for resources.pak.
# exclude_locale_paks: if set to true, skip chrome_repack_locales. # locale_whitelist: if set, override repack_whitelist for locale .pak files.
# copy_data_to_bundle: # copy_data_to_bundle:
# deps: # deps:
# output_dir: # output_dir:
...@@ -234,24 +234,26 @@ template("chrome_paks") { ...@@ -234,24 +234,26 @@ template("chrome_paks") {
} }
} }
if (!defined(invoker.exclude_locale_paks) || !invoker.exclude_locale_paks) { chrome_repack_locales("${target_name}_locales") {
chrome_repack_locales("${target_name}_locales") { forward_variables_from(invoker,
forward_variables_from(invoker, [
[ "copy_data_to_bundle",
"copy_data_to_bundle", "deps",
"deps", "visibility",
"repack_whitelist", ])
"visibility", if (defined(invoker.locale_whitelist)) {
]) repack_whitelist = invoker.locale_whitelist
} else if (defined(invoker.repack_whitelist)) {
repack_whitelist = invoker.repack_whitelist
}
input_locales = locales input_locales = locales
output_dir = "${invoker.output_dir}/locales" output_dir = "${invoker.output_dir}/locales"
if (is_mac) { if (is_mac) {
output_locales = locales_as_mac_outputs output_locales = locales_as_mac_outputs
} else { } else {
output_locales = locales output_locales = locales
}
} }
} }
...@@ -260,10 +262,8 @@ template("chrome_paks") { ...@@ -260,10 +262,8 @@ template("chrome_paks") {
public_deps = [ public_deps = [
":${target_name}_100_percent", ":${target_name}_100_percent",
":${target_name}_extra", ":${target_name}_extra",
":${target_name}_locales",
] ]
if (!defined(invoker.exclude_locale_paks) || !invoker.exclude_locale_paks) {
public_deps += [ ":${target_name}_locales" ]
}
if (enable_hidpi) { if (enable_hidpi) {
public_deps += [ ":${target_name}_200_percent" ] public_deps += [ ":${target_name}_200_percent" ]
} }
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
enum { enum {
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
kAndroidLocalePakDescriptor = kContentIPCDescriptorMax + 1, kAndroidLocalePakDescriptor = kContentIPCDescriptorMax + 1,
kAndroidSecondaryLocalePakDescriptor,
kAndroidChrome100PercentPakDescriptor, kAndroidChrome100PercentPakDescriptor,
kAndroidUIResourcesPakDescriptor, kAndroidUIResourcesPakDescriptor,
kAndroidMinidumpDescriptor, kAndroidMinidumpDescriptor,
......
...@@ -62,6 +62,12 @@ def _PrintMain(args): ...@@ -62,6 +62,12 @@ def _PrintMain(args):
print line.encode('utf-8') print line.encode('utf-8')
def _ListMain(args):
resources, _ = data_pack.ReadDataPack(args.pak_file)
for resource_id in sorted(resources.keys()):
args.output.write('%d\n' % resource_id)
def main(): def main():
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description=__doc__, formatter_class=argparse.RawTextHelpFormatter) description=__doc__, formatter_class=argparse.RawTextHelpFormatter)
...@@ -88,6 +94,14 @@ def main(): ...@@ -88,6 +94,14 @@ def main():
help='Prints all pak IDs and contents. Useful for diffing.') help='Prints all pak IDs and contents. Useful for diffing.')
sub_parser.add_argument('pak_file') sub_parser.add_argument('pak_file')
sub_parser.set_defaults(func=_PrintMain) sub_parser.set_defaults(func=_PrintMain)
sub_parser = sub_parsers.add_parser('list-id',
help='Outputs all resource IDs to a file.')
sub_parser.add_argument('pak_file')
sub_parser.add_argument('--output', type=argparse.FileType('w'),
default=sys.stdout,
help='The resource list path to write (default stdout)')
sub_parser.set_defaults(func=_ListMain)
if len(sys.argv) == 1: if len(sys.argv) == 1:
parser.print_help() parser.print_help()
......
per-file generate_resource_whitelist.*=agrieve@chromium.org per-file generate_resource_whitelist.*=agrieve@chromium.org
per-file generate_resource_whitelist.*=estevenson@chromium.org per-file generate_resource_whitelist.*=estevenson@chromium.org
per-file filter_resource_whitelist.*=agrieve@chromium.org
per-file filter_resource_whitelist.*=zpeng@chromium.org
#!/usr/bin/env python
# Copyright 2017 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""filter_resource_whitelist.py [-h] [--input INPUT] [--filter FILTER]
[--output OUTPUT]
INPUT specifies a resource whitelist file containing resource IDs that should
be whitelisted, where each line of INPUT contains a single resource ID.
FILTER specifies a resource whitelist file containing resource IDs that should
not be whitelisted, where each line of FILTER contains a single resource ID.
Filters a resource whitelist by removing resource IDs that are contained in a
another resource whitelist.
This script is used to generate Monochrome's locale paks.
"""
import argparse
import sys
def main():
parser = argparse.ArgumentParser(usage=__doc__)
parser.add_argument(
'--input', type=argparse.FileType('r'), required=True,
help='A resource whitelist where each line contains one resource ID. '
'These IDs, excluding the ones in FILTER, are to be included.')
parser.add_argument(
'--filter', type=argparse.FileType('r'), required=True,
help='A resource whitelist where each line contains one resource ID. '
'These IDs are to be excluded.')
parser.add_argument(
'--output', type=argparse.FileType('w'), default=sys.stdout,
help='The resource list path to write (default stdout)')
args = parser.parse_args()
input_resources = list(int(resource_id) for resource_id in args.input)
filter_resources = set(int(resource_id) for resource_id in args.filter)
output_resources = [resource_id for resource_id in input_resources
if resource_id not in filter_resources]
for resource_id in sorted(output_resources):
args.output.write('%d\n' % resource_id)
if __name__ == '__main__':
main()
...@@ -211,9 +211,10 @@ void ResourceBundle::InitSharedInstanceWithPakFileRegion( ...@@ -211,9 +211,10 @@ void ResourceBundle::InitSharedInstanceWithPakFileRegion(
base::File pak_file, base::File pak_file,
const base::MemoryMappedFile::Region& region) { const base::MemoryMappedFile::Region& region) {
InitSharedInstance(NULL); InitSharedInstance(NULL);
std::unique_ptr<DataPack> data_pack(new DataPack(SCALE_FACTOR_100P)); auto data_pack = base::MakeUnique<DataPack>(SCALE_FACTOR_100P);
if (!data_pack->LoadFromFileRegion(std::move(pak_file), region)) { if (!data_pack->LoadFromFileRegion(std::move(pak_file), region)) {
NOTREACHED() << "failed to load pak file"; LOG(WARNING) << "failed to load pak file";
NOTREACHED();
return; return;
} }
g_shared_instance_->locale_resources_data_ = std::move(data_pack); g_shared_instance_->locale_resources_data_ = std::move(data_pack);
...@@ -248,6 +249,18 @@ ResourceBundle& ResourceBundle::GetSharedInstance() { ...@@ -248,6 +249,18 @@ ResourceBundle& ResourceBundle::GetSharedInstance() {
return *g_shared_instance_; return *g_shared_instance_;
} }
void ResourceBundle::LoadSecondaryLocaleDataWithPakFileRegion(
base::File pak_file,
const base::MemoryMappedFile::Region& region) {
auto data_pack = base::MakeUnique<DataPack>(SCALE_FACTOR_100P);
if (!data_pack->LoadFromFileRegion(std::move(pak_file), region)) {
LOG(WARNING) << "failed to load secondary pak file";
NOTREACHED();
return;
}
secondary_locale_resources_data_ = std::move(data_pack);
}
#if !defined(OS_ANDROID) #if !defined(OS_ANDROID)
bool ResourceBundle::LocaleDataPakExists(const std::string& locale) { bool ResourceBundle::LocaleDataPakExists(const std::string& locale) {
return !GetLocaleFilePath(locale, true).empty(); return !GetLocaleFilePath(locale, true).empty();
...@@ -389,6 +402,7 @@ void ResourceBundle::LoadTestResources(const base::FilePath& path, ...@@ -389,6 +402,7 @@ void ResourceBundle::LoadTestResources(const base::FilePath& path,
void ResourceBundle::UnloadLocaleResources() { void ResourceBundle::UnloadLocaleResources() {
locale_resources_data_.reset(); locale_resources_data_.reset();
secondary_locale_resources_data_.reset();
} }
void ResourceBundle::OverrideLocalePakForTest(const base::FilePath& pak_path) { void ResourceBundle::OverrideLocalePakForTest(const base::FilePath& pak_path) {
...@@ -551,20 +565,28 @@ base::string16 ResourceBundle::GetLocalizedString(int message_id) { ...@@ -551,20 +565,28 @@ base::string16 ResourceBundle::GetLocalizedString(int message_id) {
} }
base::StringPiece data; base::StringPiece data;
ResourceHandle::TextEncodingType encoding =
locale_resources_data_->GetTextEncodingType();
if (!locale_resources_data_->GetStringPiece(static_cast<uint16_t>(message_id), if (!locale_resources_data_->GetStringPiece(static_cast<uint16_t>(message_id),
&data)) { &data)) {
// Fall back on the main data pack (shouldn't be any strings here except in if (secondary_locale_resources_data_.get() &&
// unittests). secondary_locale_resources_data_->GetStringPiece(
data = GetRawDataResource(message_id); static_cast<uint16_t>(message_id), &data)) {
if (data.empty()) { // Fall back on the secondary locale pak if it exists.
NOTREACHED() << "unable to find resource: " << message_id; encoding = secondary_locale_resources_data_->GetTextEncodingType();
return base::string16(); } else {
// Fall back on the main data pack (shouldn't be any strings here except
// in unittests).
data = GetRawDataResource(message_id);
if (data.empty()) {
LOG(WARNING) << "unable to find resource: " << message_id;
NOTREACHED();
return base::string16();
}
} }
} }
// Strings should not be loaded from a data pack that contains binary data. // Strings should not be loaded from a data pack that contains binary data.
ResourceHandle::TextEncodingType encoding =
locale_resources_data_->GetTextEncodingType();
DCHECK(encoding == ResourceHandle::UTF16 || encoding == ResourceHandle::UTF8) DCHECK(encoding == ResourceHandle::UTF16 || encoding == ResourceHandle::UTF8)
<< "requested localized string from binary pack file"; << "requested localized string from binary pack file";
...@@ -584,12 +606,20 @@ base::RefCountedMemory* ResourceBundle::LoadLocalizedResourceBytes( ...@@ -584,12 +606,20 @@ base::RefCountedMemory* ResourceBundle::LoadLocalizedResourceBytes(
{ {
base::AutoLock lock_scope(*locale_resources_data_lock_); base::AutoLock lock_scope(*locale_resources_data_lock_);
base::StringPiece data; base::StringPiece data;
if (locale_resources_data_.get() && if (locale_resources_data_.get() &&
locale_resources_data_->GetStringPiece( locale_resources_data_->GetStringPiece(
static_cast<uint16_t>(resource_id), &data) && static_cast<uint16_t>(resource_id), &data) &&
!data.empty()) { !data.empty()) {
return new base::RefCountedStaticMemory(data.data(), data.length()); return new base::RefCountedStaticMemory(data.data(), data.length());
} }
if (secondary_locale_resources_data_.get() &&
secondary_locale_resources_data_->GetStringPiece(
static_cast<uint16_t>(resource_id), &data) &&
!data.empty()) {
return new base::RefCountedStaticMemory(data.data(), data.length());
}
} }
// Release lock_scope and fall back to main data pack. // Release lock_scope and fall back to main data pack.
return LoadDataResourceBytes(resource_id); return LoadDataResourceBytes(resource_id);
......
...@@ -151,6 +151,11 @@ class UI_BASE_EXPORT ResourceBundle { ...@@ -151,6 +151,11 @@ class UI_BASE_EXPORT ResourceBundle {
// Return the global resource loader instance. // Return the global resource loader instance.
static ResourceBundle& GetSharedInstance(); static ResourceBundle& GetSharedInstance();
// Loads a secondary locale data pack using the given file region.
void LoadSecondaryLocaleDataWithPakFileRegion(
base::File pak_file,
const base::MemoryMappedFile::Region& region);
// Check if the .pak for the given locale exists. // Check if the .pak for the given locale exists.
bool LocaleDataPakExists(const std::string& locale); bool LocaleDataPakExists(const std::string& locale);
...@@ -399,6 +404,7 @@ class UI_BASE_EXPORT ResourceBundle { ...@@ -399,6 +404,7 @@ class UI_BASE_EXPORT ResourceBundle {
// Handles for data sources. // Handles for data sources.
std::unique_ptr<ResourceHandle> locale_resources_data_; std::unique_ptr<ResourceHandle> locale_resources_data_;
std::unique_ptr<ResourceHandle> secondary_locale_resources_data_;
std::vector<std::unique_ptr<ResourceHandle>> data_packs_; std::vector<std::unique_ptr<ResourceHandle>> data_packs_;
// The maximum scale factor currently loaded. // The maximum scale factor currently loaded.
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "base/android/jni_android.h" #include "base/android/jni_android.h"
#include "base/android/jni_string.h" #include "base/android/jni_string.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/path_service.h" #include "base/path_service.h"
#include "jni/ResourceBundle_jni.h" #include "jni/ResourceBundle_jni.h"
#include "ui/base/l10n/l10n_util.h" #include "ui/base/l10n/l10n_util.h"
...@@ -20,36 +21,63 @@ namespace ui { ...@@ -20,36 +21,63 @@ namespace ui {
namespace { namespace {
bool g_locale_paks_in_apk = false; bool g_locale_paks_in_apk = false;
bool g_load_secondary_locale_paks = false;
// It is okay to cache and share these file descriptors since the // It is okay to cache and share these file descriptors since the
// ResourceBundle singleton never closes the handles. // ResourceBundle singleton never closes the handles.
int g_chrome_100_percent_fd = -1; int g_chrome_100_percent_fd = -1;
int g_resources_pack_fd = -1; int g_resources_pack_fd = -1;
int g_locale_pack_fd = -1; int g_locale_pack_fd = -1;
int g_secondary_locale_pack_fd = -1;
base::MemoryMappedFile::Region g_chrome_100_percent_region; base::MemoryMappedFile::Region g_chrome_100_percent_region;
base::MemoryMappedFile::Region g_resources_pack_region; base::MemoryMappedFile::Region g_resources_pack_region;
base::MemoryMappedFile::Region g_locale_pack_region; base::MemoryMappedFile::Region g_locale_pack_region;
base::MemoryMappedFile::Region g_secondary_locale_pack_region;
bool LoadFromApkOrFile(const char* apk_path, bool LoadFromApkOrFile(const char* apk_path,
const base::FilePath* disk_path, const base::FilePath* disk_path,
int* fd_out, int* out_fd,
base::MemoryMappedFile::Region* region_out) { base::MemoryMappedFile::Region* out_region) {
DCHECK_EQ(*fd_out, -1) << "Attempt to load " << apk_path << " twice."; DCHECK_EQ(*out_fd, -1) << "Attempt to load " << apk_path << " twice.";
if (apk_path != nullptr) { if (apk_path != nullptr) {
*fd_out = base::android::OpenApkAsset(apk_path, region_out); *out_fd = base::android::OpenApkAsset(apk_path, out_region);
} }
// For unit tests, the file exists on disk. // For unit tests, the file exists on disk.
if (*fd_out < 0 && disk_path != nullptr) { if (*out_fd < 0 && disk_path != nullptr) {
int flags = base::File::FLAG_OPEN | base::File::FLAG_READ; int flags = base::File::FLAG_OPEN | base::File::FLAG_READ;
*fd_out = base::File(*disk_path, flags).TakePlatformFile(); *out_fd = base::File(*disk_path, flags).TakePlatformFile();
*region_out = base::MemoryMappedFile::Region::kWholeFile; *out_region = base::MemoryMappedFile::Region::kWholeFile;
} }
bool success = *fd_out >= 0; bool success = *out_fd >= 0;
if (!success) { if (!success) {
LOG(ERROR) << "Failed to open pak file: " << apk_path; LOG(ERROR) << "Failed to open pak file: " << apk_path;
} }
return success; return success;
} }
int LoadLocalePakFromApk(const std::string& app_locale,
base::MemoryMappedFile::Region* out_region) {
std::string locale_path_within_apk =
GetPathForAndroidLocalePakWithinApk(app_locale);
if (locale_path_within_apk.empty()) {
LOG(WARNING) << "locale_path_within_apk.empty() for locale "
<< app_locale;
return -1;
}
return base::android::OpenApkAsset(locale_path_within_apk, out_region);
}
std::unique_ptr<DataPack> LoadDataPackFromLocalePak(
int locale_pack_fd,
const base::MemoryMappedFile::Region& region) {
auto data_pack = base::MakeUnique<DataPack>(SCALE_FACTOR_100P);
if (!data_pack->LoadFromFileRegion(base::File(locale_pack_fd), region)) {
LOG(WARNING) << "failed to load locale.pak";
NOTREACHED();
return nullptr;
}
return data_pack;
}
} // namespace } // namespace
void ResourceBundle::LoadCommonResources() { void ResourceBundle::LoadCommonResources() {
...@@ -74,22 +102,18 @@ bool ResourceBundle::LocaleDataPakExists(const std::string& locale) { ...@@ -74,22 +102,18 @@ bool ResourceBundle::LocaleDataPakExists(const std::string& locale) {
std::string ResourceBundle::LoadLocaleResources( std::string ResourceBundle::LoadLocaleResources(
const std::string& pref_locale) { const std::string& pref_locale) {
DCHECK(!locale_resources_data_.get()) << "locale.pak already loaded"; DCHECK(!locale_resources_data_.get() &&
!secondary_locale_resources_data_.get())
<< "locale.pak already loaded";
if (g_locale_pack_fd != -1) { if (g_locale_pack_fd != -1) {
LOG(WARNING) LOG(WARNING)
<< "Unexpected (outside of tests): Loading a second locale pak file."; << "Unexpected (outside of tests): Loading a second locale pak file.";
} }
std::string app_locale = l10n_util::GetApplicationLocale(pref_locale); std::string app_locale = l10n_util::GetApplicationLocale(pref_locale);
// Load primary locale .pak file.
if (g_locale_paks_in_apk) { if (g_locale_paks_in_apk) {
std::string locale_path_within_apk = g_locale_pack_fd = LoadLocalePakFromApk(app_locale, &g_locale_pack_region);
GetPathForAndroidLocalePakWithinApk(app_locale);
if (locale_path_within_apk.empty()) {
LOG(WARNING) << "locale_path_within_apk.empty() for locale "
<< app_locale;
return std::string();
}
g_locale_pack_fd = base::android::OpenApkAsset(locale_path_within_apk,
&g_locale_pack_region);
} else { } else {
base::FilePath locale_file_path = GetOverriddenPakPath(); base::FilePath locale_file_path = GetOverriddenPakPath();
if (locale_file_path.empty()) if (locale_file_path.empty())
...@@ -105,15 +129,27 @@ std::string ResourceBundle::LoadLocaleResources( ...@@ -105,15 +129,27 @@ std::string ResourceBundle::LoadLocaleResources(
g_locale_pack_region = base::MemoryMappedFile::Region::kWholeFile; g_locale_pack_region = base::MemoryMappedFile::Region::kWholeFile;
} }
std::unique_ptr<DataPack> data_pack(new DataPack(SCALE_FACTOR_100P)); locale_resources_data_ = LoadDataPackFromLocalePak(
if (!data_pack->LoadFromFileRegion(base::File(g_locale_pack_fd), g_locale_pack_fd, g_locale_pack_region);
g_locale_pack_region)) {
LOG(ERROR) << "failed to load locale.pak"; if (!locale_resources_data_.get())
NOTREACHED();
return std::string(); return std::string();
// Load secondary locale .pak file if it exists. For debug build monochrome,
// a secondary locale pak will always be loaded; however, it should be
// unnecessary for loading locale resources because the primary locale pak
// would have a copy of all the resources in the secondary locale pak.
if (g_load_secondary_locale_paks) {
g_secondary_locale_pack_fd = LoadLocalePakFromApk(
app_locale, &g_secondary_locale_pack_region);
secondary_locale_resources_data_ = LoadDataPackFromLocalePak(
g_secondary_locale_pack_fd, g_secondary_locale_pack_region);
if (!secondary_locale_resources_data_.get())
return std::string();
} }
locale_resources_data_ = std::move(data_pack);
return app_locale; return app_locale;
} }
...@@ -125,6 +161,10 @@ void SetLocalePaksStoredInApk(bool value) { ...@@ -125,6 +161,10 @@ void SetLocalePaksStoredInApk(bool value) {
g_locale_paks_in_apk = value; g_locale_paks_in_apk = value;
} }
void SetLoadSecondaryLocalePaks(bool value) {
g_load_secondary_locale_paks = value;
}
void LoadMainAndroidPackFile(const char* path_within_apk, void LoadMainAndroidPackFile(const char* path_within_apk,
const base::FilePath& disk_file_path) { const base::FilePath& disk_file_path) {
if (LoadFromApkOrFile(path_within_apk, if (LoadFromApkOrFile(path_within_apk,
...@@ -155,6 +195,11 @@ int GetLocalePackFd(base::MemoryMappedFile::Region* out_region) { ...@@ -155,6 +195,11 @@ int GetLocalePackFd(base::MemoryMappedFile::Region* out_region) {
return g_locale_pack_fd; return g_locale_pack_fd;
} }
int GetSecondaryLocalePackFd(base::MemoryMappedFile::Region* out_region) {
*out_region = g_secondary_locale_pack_region;
return g_secondary_locale_pack_fd;
}
std::string GetPathForAndroidLocalePakWithinApk(const std::string& locale) { std::string GetPathForAndroidLocalePakWithinApk(const std::string& locale) {
JNIEnv* env = base::android::AttachCurrentThread(); JNIEnv* env = base::android::AttachCurrentThread();
base::android::ScopedJavaLocalRef<jstring> ret = base::android::ScopedJavaLocalRef<jstring> ret =
......
...@@ -31,10 +31,17 @@ UI_BASE_EXPORT int GetCommonResourcesPackFd( ...@@ -31,10 +31,17 @@ UI_BASE_EXPORT int GetCommonResourcesPackFd(
UI_BASE_EXPORT int GetLocalePackFd( UI_BASE_EXPORT int GetLocalePackFd(
base::MemoryMappedFile::Region* out_region); base::MemoryMappedFile::Region* out_region);
// Returns the file descriptor and region for the secondary locale .pak file.
UI_BASE_EXPORT int GetSecondaryLocalePackFd(
base::MemoryMappedFile::Region* out_region);
// Tell ResourceBundle to locate locale pak files via // Tell ResourceBundle to locate locale pak files via
// GetPathForAndroidLocalePakWithinApk rather than looking for them on disk. // GetPathForAndroidLocalePakWithinApk rather than looking for them on disk.
UI_BASE_EXPORT void SetLocalePaksStoredInApk(bool value); UI_BASE_EXPORT void SetLocalePaksStoredInApk(bool value);
// Tell ResourceBundle to load secondary locale .pak files.
UI_BASE_EXPORT void SetLoadSecondaryLocalePaks(bool value);
// Returns the path within the apk for the given locale's .pak file, or an // Returns the path within the apk for the given locale's .pak file, or an
// empty string if it doesn't exist. // empty string if it doesn't exist.
// Only locale paks for the active Android language can be retrieved. // Only locale paks for the active Android language can be retrieved.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment