Commit 5bbf191c authored by Clark DuVall's avatar Clark DuVall Committed by Commit Bot

Hardcode package ID of dynamic attributes in shared libraries

This hardcodes the package IDs of dynamic attributes to 0x2 and throws
an error in WebLayer if the package ID does not end up being 0x2. This
should not affect WebView, since WebView does not depend on any dynamic
attributes.

The *_pb2.py files were generated from the Resources.proto and
Configuration.proto files in the Android frameworks/base repo.

Bug: 1045262
Change-Id: Ic04c150c5c8709f59f738a84068c0b738f0c4643
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2018493Reviewed-by: default avatarRichard Coles <torne@chromium.org>
Reviewed-by: default avatarAndrew Grieve <agrieve@chromium.org>
Commit-Queue: Clark DuVall <cduvall@chromium.org>
Cr-Commit-Position: refs/heads/master@{#736458}
parent 5367d59c
...@@ -48,6 +48,9 @@ def CommonChecks(input_api, output_api): ...@@ -48,6 +48,9 @@ def CommonChecks(input_api, output_api):
input_api, input_api,
output_api, output_api,
white_list=build_pys, white_list=build_pys,
black_list=[
r'.*_pb2\.py',
],
extra_paths_list=[J('gyp'), J('gn')])) extra_paths_list=[J('gyp'), J('gn')]))
# Disabled due to http://crbug.com/410936 # Disabled due to http://crbug.com/410936
......
...@@ -38,6 +38,13 @@ from util import resource_utils ...@@ -38,6 +38,13 @@ from util import resource_utils
sys.path.insert(1, os.path.join(build_utils.DIR_SOURCE_ROOT, 'third_party')) sys.path.insert(1, os.path.join(build_utils.DIR_SOURCE_ROOT, 'third_party'))
from jinja2 import Template # pylint: disable=F0401 from jinja2 import Template # pylint: disable=F0401
# Make sure the pb2 files are able to import google.protobuf
sys.path.insert(
1,
os.path.join(build_utils.DIR_SOURCE_ROOT, 'third_party', 'protobuf',
'python'))
from proto import Resources_pb2
_JETIFY_SCRIPT_PATH = os.path.join(build_utils.DIR_SOURCE_ROOT, 'third_party', _JETIFY_SCRIPT_PATH = os.path.join(build_utils.DIR_SOURCE_ROOT, 'third_party',
'jetifier_standalone', 'bin', 'jetifier_standalone', 'bin',
'jetifier-standalone') 'jetifier-standalone')
...@@ -610,6 +617,86 @@ def _CompileDeps(aapt2_path, dep_subdirs, temp_dir): ...@@ -610,6 +617,86 @@ def _CompileDeps(aapt2_path, dep_subdirs, temp_dir):
return partials return partials
def _ProcessProtoItem(item):
if not item.HasField('ref'):
return
# If this is a dynamic attribute (type ATTRIBUTE, package ID 0), hardcode
# the package to 0x02.
if item.ref.type == Resources_pb2.Reference.ATTRIBUTE and not (
item.ref.id & 0xff000000):
item.ref.id |= 0x02000000
item.ref.ClearField('is_dynamic')
def _ProcessProtoValue(value):
if value.HasField('item'):
_ProcessProtoItem(value.item)
else:
compound_value = value.compound_value
if compound_value.HasField('style'):
for entry in compound_value.style.entry:
_ProcessProtoItem(entry.item)
elif compound_value.HasField('array'):
for element in compound_value.array.element:
_ProcessProtoItem(element.item)
elif compound_value.HasField('plural'):
for entry in compound_value.plural.entry:
_ProcessProtoItem(entry.item)
def _ProcessProtoXmlNode(xml_node):
if not xml_node.HasField('element'):
return
for attribute in xml_node.element.attribute:
_ProcessProtoItem(attribute.compiled_item)
for child in xml_node.element.child:
_ProcessProtoXmlNode(child)
def _HardcodeSharedLibraryDynamicAttributes(zip_path):
"""Hardcodes the package IDs of dynamic attributes to 0x02.
This is a workaround for b/147674078, which affects Android versions pre-N.
Args:
zip_path: Path to proto APK file.
"""
with build_utils.TempDir() as tmp_dir:
build_utils.ExtractAll(zip_path, path=tmp_dir)
# First process the resources file.
table = Resources_pb2.ResourceTable()
with open(os.path.join(tmp_dir, 'resources.pb')) as f:
table.ParseFromString(f.read())
for package in table.package:
for _type in package.type:
for entry in _type.entry:
for config_value in entry.config_value:
_ProcessProtoValue(config_value.value)
with open(os.path.join(tmp_dir, 'resources.pb'), 'w') as f:
f.write(table.SerializeToString())
# Next process all the XML files.
xml_files = build_utils.FindInDirectory(tmp_dir, '*.xml')
for xml_file in xml_files:
xml_node = Resources_pb2.XmlNode()
with open(xml_file) as f:
xml_node.ParseFromString(f.read())
_ProcessProtoXmlNode(xml_node)
with open(xml_file, 'w') as f:
f.write(xml_node.SerializeToString())
# Overwrite the original zip file.
build_utils.ZipDir(zip_path, tmp_dir)
def _CreateResourceInfoFile(path_info, info_path, dependencies_res_zips): def _CreateResourceInfoFile(path_info, info_path, dependencies_res_zips):
for zip_file in dependencies_res_zips: for zip_file in dependencies_res_zips:
zip_info_file_path = zip_file + '.info' zip_info_file_path = zip_file + '.info'
...@@ -833,6 +920,16 @@ def _PackageApk(options, build): ...@@ -833,6 +920,16 @@ def _PackageApk(options, build):
build.proto_path, build.arsc_path build.proto_path, build.arsc_path
]) ])
# Workaround for b/147674078. This is only needed for WebLayer and does not
# affect WebView usage, since WebView does not used dynamic attributes.
if options.shared_resources:
logging.debug('Hardcoding dynamic attributes')
_HardcodeSharedLibraryDynamicAttributes(build.proto_path)
build_utils.CheckOutput([
options.aapt2_path, 'convert', '--output-format', 'binary', '-o',
build.arsc_path, build.proto_path
])
if build.arsc_path is None: if build.arsc_path is None:
os.remove(arsc_path) os.remove(arsc_path)
......
...@@ -21,8 +21,34 @@ ...@@ -21,8 +21,34 @@
../../../third_party/markupsafe/__init__.py ../../../third_party/markupsafe/__init__.py
../../../third_party/markupsafe/_compat.py ../../../third_party/markupsafe/_compat.py
../../../third_party/markupsafe/_native.py ../../../third_party/markupsafe/_native.py
../../../third_party/protobuf/python/google/__init__.py
../../../third_party/protobuf/python/google/protobuf/__init__.py
../../../third_party/protobuf/python/google/protobuf/descriptor.py
../../../third_party/protobuf/python/google/protobuf/descriptor_database.py
../../../third_party/protobuf/python/google/protobuf/descriptor_pool.py
../../../third_party/protobuf/python/google/protobuf/internal/__init__.py
../../../third_party/protobuf/python/google/protobuf/internal/api_implementation.py
../../../third_party/protobuf/python/google/protobuf/internal/containers.py
../../../third_party/protobuf/python/google/protobuf/internal/decoder.py
../../../third_party/protobuf/python/google/protobuf/internal/encoder.py
../../../third_party/protobuf/python/google/protobuf/internal/enum_type_wrapper.py
../../../third_party/protobuf/python/google/protobuf/internal/extension_dict.py
../../../third_party/protobuf/python/google/protobuf/internal/message_listener.py
../../../third_party/protobuf/python/google/protobuf/internal/python_message.py
../../../third_party/protobuf/python/google/protobuf/internal/type_checkers.py
../../../third_party/protobuf/python/google/protobuf/internal/well_known_types.py
../../../third_party/protobuf/python/google/protobuf/internal/wire_format.py
../../../third_party/protobuf/python/google/protobuf/message.py
../../../third_party/protobuf/python/google/protobuf/message_factory.py
../../../third_party/protobuf/python/google/protobuf/reflection.py
../../../third_party/protobuf/python/google/protobuf/symbol_database.py
../../../third_party/protobuf/python/google/protobuf/text_encoding.py
../../../third_party/protobuf/python/google/protobuf/text_format.py
../../gn_helpers.py ../../gn_helpers.py
compile_resources.py compile_resources.py
proto/Configuration_pb2.py
proto/Resources_pb2.py
proto/__init__.py
util/__init__.py util/__init__.py
util/build_utils.py util/build_utils.py
util/diff_utils.py util/diff_utils.py
......
This diff is collapsed.
# Protos
These protos are generated from Resources.proto and Configuration.proto from the
Android repo. They are found in the frameworks/base/tools/aapt2/ directory. To
regenerate these if there are changes, run this command from the root of an
Android checkout:
protoc --python_out=some_dir frameworks/base/tools/aapt2/Resources.proto \
frameworks/base/tools/aapt2/Configuration.proto
Then copy the resulting \*pb2.py files from some_dir here. To make sure
Resources_pb2.py is able to import Configuration_pb2.py, remove the
"from frameworks.base.tools.aapt2" portion of the import statement so it will
instead be imported from the current directory.
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -55,6 +55,7 @@ android_library("weblayer_private_java_tests") { ...@@ -55,6 +55,7 @@ android_library("weblayer_private_java_tests") {
"src/org/chromium/weblayer/test/InstrumentationActivityTestRule.java", "src/org/chromium/weblayer/test/InstrumentationActivityTestRule.java",
"src/org/chromium/weblayer/test/NavigationWaiter.java", "src/org/chromium/weblayer/test/NavigationWaiter.java",
"src/org/chromium/weblayer/test/NetworkChangeNotifierTest.java", "src/org/chromium/weblayer/test/NetworkChangeNotifierTest.java",
"src/org/chromium/weblayer/test/ResourceLoadingTest.java",
"src/org/chromium/weblayer/test/WebLayerJUnit4ClassRunner.java", "src/org/chromium/weblayer/test/WebLayerJUnit4ClassRunner.java",
] ]
deps = [ deps = [
......
// Copyright 2020 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.
package org.chromium.weblayer.test;
import android.content.Context;
import android.graphics.drawable.ColorDrawable;
import android.support.test.filters.SmallTest;
import android.util.TypedValue;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.chromium.weblayer.TestWebLayer;
import org.chromium.weblayer.shell.InstrumentationActivity;
/** Tests that resources are loaded correctly. */
@RunWith(WebLayerJUnit4ClassRunner.class)
public final class ResourceLoadingTest {
@Rule
public InstrumentationActivityTestRule mActivityTestRule =
new InstrumentationActivityTestRule();
private Context mRemoteContext;
@Before
public void setUp() throws Exception {
InstrumentationActivity activity = mActivityTestRule.launchShellWithUrl("about:blank");
mRemoteContext = TestWebLayer.getRemoteContext(activity);
}
@Test
@SmallTest
public void testLayout() throws Exception {
Context themedContext =
new ContextThemeWrapper(mRemoteContext, getIdentifier("style/TestStyle"));
View view = LayoutInflater.from(themedContext)
.inflate(getIdentifier("layout/test_layout"), null);
Assert.assertEquals(((ColorDrawable) view.getBackground()).getColor(), 0xff010101);
}
@Test
@SmallTest
public void testStyle() throws Exception {
Context themedContext =
new ContextThemeWrapper(mRemoteContext, getIdentifier("style/TestStyle"));
TypedValue tv = new TypedValue();
Assert.assertTrue(themedContext.getTheme().resolveAttribute(
getIdentifier("attr/testAttrColor"), tv, true));
Assert.assertEquals(tv.type, TypedValue.TYPE_INT_COLOR_RGB8);
Assert.assertEquals(tv.data, 0xff010101);
}
private int getIdentifier(String name) {
return mRemoteContext.getResources().getIdentifier(
name, null, mRemoteContext.getPackageName());
}
}
...@@ -91,10 +91,18 @@ android_library("java") { ...@@ -91,10 +91,18 @@ android_library("java") {
"//third_party/android_sdk:public_framework_system_java" "//third_party/android_sdk:public_framework_system_java"
} }
android_resources("weblayer_test_resources") {
resource_dirs = [ "res_test" ]
custom_package = "org.chromium.weblayer_private.test"
}
android_library("test_java") { android_library("test_java") {
testonly = true testonly = true
sources = [ "org/chromium/weblayer_private/test/TestWebLayerImpl.java" ] sources = [ "org/chromium/weblayer_private/test/TestWebLayerImpl.java" ]
deps = [ "//net/android:net_java" ] deps = [
":weblayer_test_resources",
"//net/android:net_java",
]
srcjar_deps = [ ":test_aidl" ] srcjar_deps = [ ":test_aidl" ]
} }
......
...@@ -171,6 +171,9 @@ public final class WebLayerImpl extends IWebLayer.Stub { ...@@ -171,6 +171,9 @@ public final class WebLayerImpl extends IWebLayer.Stub {
BuildInfo.setBrowserPackageInfo(packageInfo); BuildInfo.setBrowserPackageInfo(packageInfo);
int resourcesPackageId = getPackageId(appContext, packageInfo.packageName); int resourcesPackageId = getPackageId(appContext, packageInfo.packageName);
if (resourcesPackageId < 0x7f && resourcesPackageId != 2) {
throw new AndroidRuntimeException("WebLayer can't be used with another shared library");
}
// TODO: The call to onResourcesLoaded() can be slow, we may need to parallelize this with // TODO: The call to onResourcesLoaded() can be slow, we may need to parallelize this with
// other expensive startup tasks. // other expensive startup tasks.
R.onResourcesLoaded(resourcesPackageId); R.onResourcesLoaded(resourcesPackageId);
......
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2020 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. -->
<View
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="UnusedResources"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/testBasicColor"/>
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2020 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. -->
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="UnusedResources">
<attr name="testBasicColor" format="color"/>
<attr name="testAttrColor" format="color"/>
<style name="TestStyle">
<item name="testBasicColor">#010101</item>
<item name="testAttrColor">?attr/testBasicColor</item>
</style>
</resources>
...@@ -47,4 +47,12 @@ public final class TestWebLayer { ...@@ -47,4 +47,12 @@ public final class TestWebLayer {
public boolean isNetworkChangeAutoDetectOn() throws RemoteException { public boolean isNetworkChangeAutoDetectOn() throws RemoteException {
return mITestWebLayer.isNetworkChangeAutoDetectOn(); return mITestWebLayer.isNetworkChangeAutoDetectOn();
} }
}
\ No newline at end of file public static Context getRemoteContext(@NonNull Context appContext) {
try {
return WebLayer.getOrCreateRemoteContext(appContext);
} catch (PackageManager.NameNotFoundException | ReflectiveOperationException e) {
throw new AndroidRuntimeException(e);
}
}
}
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