android: Remove the linker tests.
The linker tests don't run on bots (and likely not locally either) and do not support the latest library loading patterns. This is the first step to remove them, as they add non-trivial complexity in the codebase. More specifically, this removes the build rules and the test APK. Bug: 1059707 Change-Id: I12102d59116ad1f0a152d3110cf3346471c8f390 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2093606 Reviewed-by: Andrew Grieve <agrieve@chromium.org> Reviewed-by: Ross McIlroy <rmcilroy@chromium.org> Reviewed-by: Egor Pasko <pasko@chromium.org> Commit-Queue: Benoit L <lizeb@chromium.org> Cr-Commit-Position: refs/heads/master@{#749238}
This commit is contained in:
BUILD.gn
build/android
content/shell/android
BUILD.gn
linker_test_apk
docs
third_party/android_crazy_linker/src
tools/android/eclipse
4
BUILD.gn
4
BUILD.gn
@ -389,10 +389,6 @@ group("gn_all") {
|
||||
]
|
||||
}
|
||||
|
||||
if (target_cpu != "x64") {
|
||||
deps += [ "//content/shell/android:chromium_linker_test_apk" ]
|
||||
}
|
||||
|
||||
if (enable_chrome_android_internal) {
|
||||
deps += [ "//clank" ]
|
||||
}
|
||||
|
@ -5,7 +5,6 @@
|
||||
from pylib.gtest import gtest_test_instance
|
||||
from pylib.instrumentation import instrumentation_test_instance
|
||||
from pylib.junit import junit_test_instance
|
||||
from pylib.linker import linker_test_instance
|
||||
from pylib.monkey import monkey_test_instance
|
||||
from pylib.utils import device_dependencies
|
||||
|
||||
@ -20,8 +19,6 @@ def CreateTestInstance(args, error_func):
|
||||
args, device_dependencies.GetDataDependencies, error_func)
|
||||
elif args.command == 'junit':
|
||||
return junit_test_instance.JunitTestInstance(args, error_func)
|
||||
elif args.command == 'linker':
|
||||
return linker_test_instance.LinkerTestInstance(args)
|
||||
elif args.command == 'monkey':
|
||||
return monkey_test_instance.MonkeyTestInstance(args, error_func)
|
||||
|
||||
|
@ -5,12 +5,10 @@
|
||||
from pylib.gtest import gtest_test_instance
|
||||
from pylib.instrumentation import instrumentation_test_instance
|
||||
from pylib.junit import junit_test_instance
|
||||
from pylib.linker import linker_test_instance
|
||||
from pylib.monkey import monkey_test_instance
|
||||
from pylib.local.device import local_device_environment
|
||||
from pylib.local.device import local_device_gtest_run
|
||||
from pylib.local.device import local_device_instrumentation_test_run
|
||||
from pylib.local.device import local_device_linker_test_run
|
||||
from pylib.local.device import local_device_monkey_test_run
|
||||
from pylib.local.machine import local_machine_environment
|
||||
from pylib.local.machine import local_machine_junit_test_run
|
||||
@ -24,9 +22,6 @@ def CreateTestRun(env, test_instance, error_func):
|
||||
instrumentation_test_instance.InstrumentationTestInstance):
|
||||
return (local_device_instrumentation_test_run
|
||||
.LocalDeviceInstrumentationTestRun(env, test_instance))
|
||||
if isinstance(test_instance, linker_test_instance.LinkerTestInstance):
|
||||
return (local_device_linker_test_run
|
||||
.LocalDeviceLinkerTestRun(env, test_instance))
|
||||
if isinstance(test_instance, monkey_test_instance.MonkeyTestInstance):
|
||||
return (local_device_monkey_test_run
|
||||
.LocalDeviceMonkeyTestRun(env, test_instance))
|
||||
|
@ -1,3 +0,0 @@
|
||||
# Copyright 2013 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.
|
@ -1,48 +0,0 @@
|
||||
# Copyright 2016 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.
|
||||
|
||||
from pylib.base import test_instance
|
||||
from pylib.constants import host_paths
|
||||
from pylib.linker import test_case
|
||||
from pylib.utils import test_filter
|
||||
|
||||
with host_paths.SysPath(host_paths.BUILD_COMMON_PATH):
|
||||
import unittest_util
|
||||
|
||||
|
||||
class LinkerTestInstance(test_instance.TestInstance):
|
||||
|
||||
def __init__(self, args):
|
||||
super(LinkerTestInstance, self).__init__()
|
||||
self._test_apk = args.test_apk
|
||||
self._test_filter = test_filter.InitializeFilterFromArgs(args)
|
||||
|
||||
@property
|
||||
def test_apk(self):
|
||||
return self._test_apk
|
||||
|
||||
@property
|
||||
def test_filter(self):
|
||||
return self._test_filter
|
||||
|
||||
def GetTests(self):
|
||||
tests = [test_case.LinkerSharedRelroTest()]
|
||||
|
||||
if self._test_filter:
|
||||
filtered_names = unittest_util.FilterTestNames(
|
||||
(t.qualified_name for t in tests), self._test_filter)
|
||||
tests = [
|
||||
t for t in tests
|
||||
if t.qualified_name in filtered_names]
|
||||
|
||||
return tests
|
||||
|
||||
def SetUp(self):
|
||||
pass
|
||||
|
||||
def TearDown(self):
|
||||
pass
|
||||
|
||||
def TestType(self):
|
||||
return 'linker'
|
@ -1,199 +0,0 @@
|
||||
# Copyright 2013 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.
|
||||
|
||||
"""Base class for linker-specific test cases.
|
||||
|
||||
The custom dynamic linker can only be tested through a custom test case
|
||||
for various technical reasons:
|
||||
|
||||
- It's an 'invisible feature', i.e. it doesn't expose a new API or
|
||||
behaviour, all it does is save RAM when loading native libraries.
|
||||
|
||||
- Checking that it works correctly requires several things that do not
|
||||
fit the existing GTest-based and instrumentation-based tests:
|
||||
|
||||
- Native test code needs to be run in both the browser and renderer
|
||||
process at the same time just after loading native libraries, in
|
||||
a completely asynchronous way.
|
||||
|
||||
- Each test case requires restarting a whole new application process
|
||||
with a different command-line.
|
||||
|
||||
- Enabling test support in the Linker code requires building a special
|
||||
APK with a flag to activate special test-only support code in the
|
||||
Linker code itself.
|
||||
|
||||
Host-driven tests have also been tried, but since they're really
|
||||
sub-classes of instrumentation tests, they didn't work well either.
|
||||
|
||||
To build and run, refer to android_linker_testing.md.
|
||||
"""
|
||||
# pylint: disable=R0201
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import logging
|
||||
import re
|
||||
|
||||
from devil.android import device_errors
|
||||
from devil.android.sdk import intent
|
||||
from pylib.base import base_test_result
|
||||
|
||||
|
||||
ResultType = base_test_result.ResultType
|
||||
|
||||
_PACKAGE_NAME = 'org.chromium.chromium_linker_test_apk'
|
||||
_ACTIVITY_NAME = '.ChromiumLinkerTestActivity'
|
||||
|
||||
# Logcat filters used during each test. Only the 'chromium' one is really
|
||||
# needed, but the logs are added to the TestResult in case of error, and
|
||||
# it is handy to have others as well when troubleshooting.
|
||||
_LOGCAT_FILTERS = ['*:s', 'chromium:v', 'cr_chromium:v',
|
||||
'cr_ChromiumAndroidLinker:v', 'cr_LibraryLoader:v',
|
||||
'cr_LinkerTest:v']
|
||||
#_LOGCAT_FILTERS = ['*:v'] ## DEBUG
|
||||
|
||||
# Regular expression used to match status lines in logcat.
|
||||
_RE_BROWSER_STATUS_LINE = re.compile(r' BROWSER_LINKER_TEST: (FAIL|SUCCESS)$')
|
||||
_RE_RENDERER_STATUS_LINE = re.compile(r' RENDERER_LINKER_TEST: (FAIL|SUCCESS)$')
|
||||
|
||||
def _StartActivityAndWaitForLinkerTestStatus(device, timeout):
|
||||
"""Force-start an activity and wait up to |timeout| seconds until the full
|
||||
linker test status lines appear in the logcat, recorded through |device|.
|
||||
Args:
|
||||
device: A DeviceUtils instance.
|
||||
timeout: Timeout in seconds
|
||||
Returns:
|
||||
A (status, logs) tuple, where status is a ResultType constant, and logs
|
||||
if the final logcat output as a string.
|
||||
"""
|
||||
|
||||
# 1. Start recording logcat with appropriate filters.
|
||||
with device.GetLogcatMonitor(filter_specs=_LOGCAT_FILTERS) as logmon:
|
||||
|
||||
# 2. Force-start activity.
|
||||
device.StartActivity(
|
||||
intent.Intent(package=_PACKAGE_NAME, activity=_ACTIVITY_NAME),
|
||||
force_stop=True)
|
||||
|
||||
# 3. Wait up to |timeout| seconds until the test status is in the logcat.
|
||||
result = ResultType.PASS
|
||||
try:
|
||||
browser_match = logmon.WaitFor(_RE_BROWSER_STATUS_LINE, timeout=timeout)
|
||||
logging.debug('Found browser match: %s', browser_match.group(0))
|
||||
renderer_match = logmon.WaitFor(_RE_RENDERER_STATUS_LINE,
|
||||
timeout=timeout)
|
||||
logging.debug('Found renderer match: %s', renderer_match.group(0))
|
||||
if (browser_match.group(1) != 'SUCCESS'
|
||||
or renderer_match.group(1) != 'SUCCESS'):
|
||||
result = ResultType.FAIL
|
||||
except device_errors.CommandTimeoutError:
|
||||
result = ResultType.TIMEOUT
|
||||
|
||||
logcat = device.adb.Logcat(dump=True)
|
||||
|
||||
logmon.Close()
|
||||
return result, '\n'.join(logcat)
|
||||
|
||||
|
||||
class LibraryLoadMap(dict):
|
||||
"""A helper class to pretty-print a map of library names to load addresses."""
|
||||
def __str__(self):
|
||||
items = ['\'%s\': 0x%x' % (name, address) for \
|
||||
(name, address) in self.iteritems()]
|
||||
return '{%s}' % (', '.join(items))
|
||||
|
||||
def __repr__(self):
|
||||
return 'LibraryLoadMap(%s)' % self.__str__()
|
||||
|
||||
|
||||
class AddressList(list):
|
||||
"""A helper class to pretty-print a list of load addresses."""
|
||||
def __str__(self):
|
||||
items = ['0x%x' % address for address in self]
|
||||
return '[%s]' % (', '.join(items))
|
||||
|
||||
def __repr__(self):
|
||||
return 'AddressList(%s)' % self.__str__()
|
||||
|
||||
|
||||
class LinkerTestCaseBase(object):
|
||||
"""Base class for linker test cases."""
|
||||
|
||||
def __init__(self):
|
||||
"""Creates a test case."""
|
||||
test_suffix = 'ForLegacyLinker'
|
||||
class_name = self.__class__.__name__
|
||||
self.qualified_name = '%s.%s' % (class_name, test_suffix)
|
||||
self.tagged_name = self.qualified_name
|
||||
|
||||
def _RunTest(self, _device):
|
||||
"""Runs the test, must be overridden.
|
||||
Args:
|
||||
_device: A DeviceUtils interface.
|
||||
Returns:
|
||||
A (status, log) tuple, where <status> is a ResultType constant, and <log>
|
||||
is the logcat output captured during the test in case of error, or None
|
||||
in case of success.
|
||||
"""
|
||||
return ResultType.FAIL, 'Unimplemented _RunTest() method!'
|
||||
|
||||
def Run(self, device):
|
||||
"""Runs the test on a given device.
|
||||
Args:
|
||||
device: Name of target device where to run the test.
|
||||
Returns:
|
||||
A base_test_result.TestRunResult() instance.
|
||||
"""
|
||||
margin = 8
|
||||
print('[ %-*s ] %s' % (margin, 'RUN', self.tagged_name))
|
||||
logging.info('Running linker test: %s', self.tagged_name)
|
||||
|
||||
# Run the test.
|
||||
status, logs = self._RunTest(device)
|
||||
|
||||
result_text = 'OK'
|
||||
if status == ResultType.FAIL:
|
||||
result_text = 'FAILED'
|
||||
elif status == ResultType.TIMEOUT:
|
||||
result_text = 'TIMEOUT'
|
||||
print('[ %*s ] %s' % (margin, result_text, self.tagged_name))
|
||||
|
||||
return base_test_result.BaseTestResult(self.tagged_name, status, log=logs)
|
||||
|
||||
|
||||
def __str__(self):
|
||||
return self.tagged_name
|
||||
|
||||
def __repr__(self):
|
||||
return self.tagged_name
|
||||
|
||||
|
||||
class LinkerSharedRelroTest(LinkerTestCaseBase):
|
||||
"""A linker test case to check the status of shared RELRO sections.
|
||||
|
||||
The core of the checks performed here are pretty simple:
|
||||
|
||||
- Clear the logcat and start recording with an appropriate set of filters.
|
||||
- Create the command-line appropriate for the test-case.
|
||||
- Start the activity (always forcing a cold start).
|
||||
- Every second, look at the current content of the filtered logcat lines
|
||||
and look for instances of the following:
|
||||
|
||||
BROWSER_LINKER_TEST: <status>
|
||||
RENDERER_LINKER_TEST: <status>
|
||||
|
||||
where <status> can be either FAIL or SUCCESS. These lines can appear
|
||||
in any order in the logcat. Once both browser and renderer status are
|
||||
found, stop the loop. Otherwise timeout after 30 seconds.
|
||||
|
||||
Note that there can be other lines beginning with BROWSER_LINKER_TEST:
|
||||
and RENDERER_LINKER_TEST:, but are not followed by a <status> code.
|
||||
|
||||
- The test case passes if the <status> for both the browser and renderer
|
||||
process are SUCCESS. Otherwise its a fail.
|
||||
"""
|
||||
def _RunTest(self, device):
|
||||
# Wait up to 30 seconds until the linker test status is in the logcat.
|
||||
return _StartActivityAndWaitForLinkerTestStatus(device, timeout=30)
|
@ -1,75 +0,0 @@
|
||||
# Copyright 2016 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.
|
||||
|
||||
import logging
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
from pylib.base import base_test_result
|
||||
from pylib.linker import test_case
|
||||
from pylib.local.device import local_device_environment
|
||||
from pylib.local.device import local_device_test_run
|
||||
|
||||
|
||||
class LinkerExceptionTestResult(base_test_result.BaseTestResult):
|
||||
"""Test result corresponding to a python exception in a host-custom test."""
|
||||
|
||||
def __init__(self, test_name, exc_info):
|
||||
"""Constructs a LinkerExceptionTestResult object.
|
||||
|
||||
Args:
|
||||
test_name: name of the test which raised an exception.
|
||||
exc_info: exception info, ostensibly from sys.exc_info().
|
||||
"""
|
||||
exc_type, exc_value, exc_traceback = exc_info
|
||||
trace_info = ''.join(traceback.format_exception(exc_type, exc_value,
|
||||
exc_traceback))
|
||||
log_msg = 'Exception:\n' + trace_info
|
||||
|
||||
super(LinkerExceptionTestResult, self).__init__(
|
||||
test_name,
|
||||
base_test_result.ResultType.FAIL,
|
||||
log="%s %s" % (exc_type, log_msg))
|
||||
|
||||
|
||||
class LocalDeviceLinkerTestRun(local_device_test_run.LocalDeviceTestRun):
|
||||
|
||||
def _CreateShards(self, tests):
|
||||
return tests
|
||||
|
||||
def _GetTests(self):
|
||||
return self._test_instance.GetTests()
|
||||
|
||||
def _GetUniqueTestName(self, test):
|
||||
return test.qualified_name
|
||||
|
||||
def _RunTest(self, device, test):
|
||||
assert isinstance(test, test_case.LinkerTestCaseBase)
|
||||
|
||||
try:
|
||||
result = test.Run(device)
|
||||
except Exception: # pylint: disable=broad-except
|
||||
logging.exception('Caught exception while trying to run test: ' +
|
||||
test.tagged_name)
|
||||
exc_info = sys.exc_info()
|
||||
result = LinkerExceptionTestResult(test.tagged_name, exc_info)
|
||||
|
||||
return result, None
|
||||
|
||||
def SetUp(self):
|
||||
@local_device_environment.handle_shard_failures_with(
|
||||
on_failure=self._env.BlacklistDevice)
|
||||
def individual_device_set_up(dev):
|
||||
dev.Install(self._test_instance.test_apk)
|
||||
|
||||
self._env.parallel_devices.pMap(individual_device_set_up)
|
||||
|
||||
def _ShouldShard(self):
|
||||
return True
|
||||
|
||||
def TearDown(self):
|
||||
pass
|
||||
|
||||
def TestPackage(self):
|
||||
pass
|
@ -160,15 +160,11 @@ pylib/instrumentation/instrumentation_test_instance.py
|
||||
pylib/instrumentation/test_result.py
|
||||
pylib/junit/__init__.py
|
||||
pylib/junit/junit_test_instance.py
|
||||
pylib/linker/__init__.py
|
||||
pylib/linker/linker_test_instance.py
|
||||
pylib/linker/test_case.py
|
||||
pylib/local/__init__.py
|
||||
pylib/local/device/__init__.py
|
||||
pylib/local/device/local_device_environment.py
|
||||
pylib/local/device/local_device_gtest_run.py
|
||||
pylib/local/device/local_device_instrumentation_test_run.py
|
||||
pylib/local/device/local_device_linker_test_run.py
|
||||
pylib/local/device/local_device_monkey_test_run.py
|
||||
pylib/local/device/local_device_test_run.py
|
||||
pylib/local/emulator/__init__.py
|
||||
|
@ -245,106 +245,6 @@ android_library("content_shell_test_java") {
|
||||
]
|
||||
}
|
||||
|
||||
if (current_cpu != "x64") {
|
||||
chromium_linker_test_manifest =
|
||||
"$target_gen_dir/linker_test_apk/AndroidManifest.xml"
|
||||
|
||||
jinja_template("chromium_linker_test_manifest") {
|
||||
testonly = true
|
||||
input = "linker_test_apk/AndroidManifest.xml.jinja2"
|
||||
output = chromium_linker_test_manifest
|
||||
}
|
||||
|
||||
android_resources("linker_resources") {
|
||||
testonly = true
|
||||
resource_dirs = [ "linker_test_apk/res" ]
|
||||
android_manifest = chromium_linker_test_manifest
|
||||
android_manifest_dep = ":chromium_linker_test_manifest"
|
||||
}
|
||||
|
||||
_linker_test_apk_target_name = "chromium_linker_test_apk__apk"
|
||||
_linker_test_apk_test_runner_target_name =
|
||||
"chromium_linker_test_apk__test_runner_script"
|
||||
_linker_test_jni_registration_header =
|
||||
"$target_gen_dir/linker_test_apk/linker_test_jni_registration.h"
|
||||
|
||||
android_apk(_linker_test_apk_target_name) {
|
||||
testonly = true
|
||||
deps = [
|
||||
":content_shell_assets",
|
||||
":content_shell_java",
|
||||
":linker_resources",
|
||||
"//base:base_java",
|
||||
"//base:jni_java",
|
||||
"//content/public/android:content_java",
|
||||
"//ui/android:ui_java",
|
||||
]
|
||||
android_manifest = chromium_linker_test_manifest
|
||||
android_manifest_dep = ":chromium_linker_test_manifest"
|
||||
apk_name = "ChromiumLinkerTest"
|
||||
shared_libraries = [ ":linker_test" ]
|
||||
use_chromium_linker = true
|
||||
enable_chromium_linker_tests = true
|
||||
jni_registration_header = _linker_test_jni_registration_header
|
||||
sources = [
|
||||
"linker_test_apk/src/org/chromium/chromium_linker_test_apk/ChromiumLinkerTestActivity.java",
|
||||
"linker_test_apk/src/org/chromium/chromium_linker_test_apk/ChromiumLinkerTestApplication.java",
|
||||
"linker_test_apk/src/org/chromium/chromium_linker_test_apk/LinkerTests.java",
|
||||
]
|
||||
annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
|
||||
processor_args_javac = [ skip_gen_jni_arg ]
|
||||
}
|
||||
|
||||
test_runner_script(_linker_test_apk_test_runner_target_name) {
|
||||
test_name = "chromium_linker_test_apk"
|
||||
test_type = "linker"
|
||||
apk_target = ":$_linker_test_apk_target_name"
|
||||
ignore_all_data_deps = true
|
||||
}
|
||||
|
||||
group("chromium_linker_test_apk") {
|
||||
testonly = true
|
||||
deps = [
|
||||
":$_linker_test_apk_target_name",
|
||||
":$_linker_test_apk_test_runner_target_name",
|
||||
]
|
||||
}
|
||||
|
||||
shared_library("linker_test") {
|
||||
testonly = true
|
||||
sources = [
|
||||
"linker_test_apk/chromium_linker_test_android.cc",
|
||||
"linker_test_apk/chromium_linker_test_linker_tests.cc",
|
||||
_linker_test_jni_registration_header,
|
||||
]
|
||||
|
||||
deps = [
|
||||
":${_linker_test_apk_target_name}__final_jni",
|
||||
":linker_test_jni_headers",
|
||||
"//content/shell:content_shell_lib",
|
||||
|
||||
# Required to include "content/public/browser/android/compositor.h"
|
||||
# in chromium_linker_test_android.cc :-(
|
||||
"//skia",
|
||||
"//third_party/re2",
|
||||
]
|
||||
|
||||
# Explicit dependency required for JNI registration to be able to
|
||||
# find the native side functions.
|
||||
if (is_component_build) {
|
||||
deps += [
|
||||
"//device/gamepad",
|
||||
"//media/midi",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
generate_jni("linker_test_jni_headers") {
|
||||
testonly = true
|
||||
sources = [ "linker_test_apk/src/org/chromium/chromium_linker_test_apk/LinkerTests.java" ]
|
||||
}
|
||||
}
|
||||
|
||||
android_library("content_shell_browsertests_java") {
|
||||
testonly = true
|
||||
deps = [
|
||||
|
@ -1,59 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!-- Copyright 2013 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.
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.chromium.chromium_linker_test_apk">
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
|
||||
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
|
||||
<application android:name="ChromiumLinkerTestApplication"
|
||||
android:label="ChromiumLinkerTest">
|
||||
<activity android:name="ChromiumLinkerTestActivity"
|
||||
android:launchMode="singleTask"
|
||||
android:theme="@android:style/Theme.Holo.Light.NoActionBar"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize"
|
||||
android:hardwareAccelerated="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<!-- The following service entries exist in order to allow us to
|
||||
start more than one sandboxed process. -->
|
||||
|
||||
<!-- NOTE: If you change the values of "android:process" for any of the below services,
|
||||
you also need to update kHelperProcessExecutableName in chrome_constants.cc. -->
|
||||
{% set num_sandboxed_services = 40 %}
|
||||
<meta-data android:name="org.chromium.content.browser.NUM_SANDBOXED_SERVICES"
|
||||
android:value="{{ num_sandboxed_services }}"/>
|
||||
{% for i in range(num_sandboxed_services) %}
|
||||
<service android:name="org.chromium.content.app.SandboxedProcessService{{ i }}"
|
||||
android:process=":sandboxed_process{{ i }}"
|
||||
android:isolatedProcess="true"
|
||||
android:exported="false" />
|
||||
{% endfor %}
|
||||
|
||||
{% set num_privileged_services = 5 %}
|
||||
<meta-data android:name="org.chromium.content.browser.NUM_PRIVILEGED_SERVICES"
|
||||
android:value="{{ num_privileged_services }}"/>
|
||||
{% for i in range(num_privileged_services) %}
|
||||
<service android:name="org.chromium.content.app.PrivilegedProcessService{{ i }}"
|
||||
android:process=":privileged_process{{ i }}"
|
||||
android:isolatedProcess="false"
|
||||
android:exported="false" />
|
||||
{% endfor %}
|
||||
</application>
|
||||
</manifest>
|
@ -1,23 +0,0 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
#include "base/android/jni_android.h"
|
||||
#include "base/android/library_loader/library_loader_hooks.h"
|
||||
#include "base/bind.h"
|
||||
#include "content/public/app/content_jni_onload.h"
|
||||
#include "content/public/app/content_main.h"
|
||||
#include "content/shell/android/linker_test_apk/linker_test_jni_registration.h"
|
||||
#include "content/shell/app/shell_main_delegate.h"
|
||||
|
||||
// This is called by the VM when the shared library is first loaded.
|
||||
JNI_EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
|
||||
base::android::InitVM(vm);
|
||||
JNIEnv* env = base::android::AttachCurrentThread();
|
||||
if (!RegisterMainDexNatives(env) || !RegisterNonMainDexNatives(env) ||
|
||||
!content::android::OnJNIOnLoadInit()) {
|
||||
return -1;
|
||||
}
|
||||
content::SetContentMainDelegate(new content::ShellMainDelegate());
|
||||
return JNI_VERSION_1_4;
|
||||
}
|
@ -1,195 +0,0 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
// This file implements the native methods of
|
||||
// org.content.chromium.app.LinkerTests
|
||||
// Unlike the content of linker_jni.cc, it is part of the content library and
|
||||
// can thus use base/ and the C++ STL.
|
||||
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/mman.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/debug/proc_maps_linux.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "content/shell/android/linker_test_jni_headers/LinkerTests_jni.h"
|
||||
#include "third_party/re2/src/re2/re2.h"
|
||||
|
||||
using base::android::JavaParamRef;
|
||||
|
||||
namespace content {
|
||||
|
||||
namespace {
|
||||
|
||||
using base::debug::MappedMemoryRegion;
|
||||
|
||||
jboolean RunChecks(bool in_browser_process) {
|
||||
// IMPORTANT NOTE: The Python test control script reads the logcat for
|
||||
// lines like:
|
||||
// BROWSER_LINKER_TEST: <status>
|
||||
// RENDERER_LINKER_TEST: <status>
|
||||
//
|
||||
// Where <status> can be either SUCCESS or FAIL. Other lines starting
|
||||
// with the same prefixes, but not using SUCCESS or FAIL are ignored.
|
||||
const char* prefix =
|
||||
in_browser_process ? "BROWSER_LINKER_TEST: " : "RENDERER_LINKER_TEST: ";
|
||||
|
||||
// The RELRO section(s) will appear in /proc/self/maps as a mapped memory
|
||||
// region for a file with a recognizable name. For the LegacyLinker the
|
||||
// full name will be something like:
|
||||
//
|
||||
// "/dev/ashmem/RELRO:<libname> (deleted)"
|
||||
//
|
||||
// and for the ModernLinker, something like:
|
||||
//
|
||||
// "/data/data/org.chromium.chromium_linker_test_apk/
|
||||
// app_chromium_linker_test/RELRO:<libname> (deleted)"
|
||||
//
|
||||
// Where <libname> is the library name and '(deleted)' is actually
|
||||
// added by the kernel to indicate there is no corresponding file
|
||||
// on the filesystem.
|
||||
//
|
||||
// For regular builds, there is only one library, and thus one RELRO
|
||||
// section, but for the component build, there are several libraries,
|
||||
// each one with its own RELRO.
|
||||
static const char kLegacyRelroSectionPattern[] = "/dev/ashmem/RELRO:.*";
|
||||
static const char kModernRelroSectionPattern[] = "/data/.*/RELRO:.*";
|
||||
|
||||
// Parse /proc/self/maps and builds a list of region mappings in this
|
||||
// process.
|
||||
std::string maps;
|
||||
base::debug::ReadProcMaps(&maps);
|
||||
if (maps.empty()) {
|
||||
LOG(ERROR) << prefix << "FAIL Cannot parse /proc/self/maps";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<MappedMemoryRegion> regions;
|
||||
base::debug::ParseProcMaps(maps, ®ions);
|
||||
if (regions.empty()) {
|
||||
LOG(ERROR) << prefix << "FAIL Cannot read memory mappings in this process";
|
||||
return false;
|
||||
}
|
||||
|
||||
const RE2 legacy_linker_re(kLegacyRelroSectionPattern);
|
||||
const RE2 modern_linker_re(kModernRelroSectionPattern);
|
||||
|
||||
int num_shared_relros = 0;
|
||||
int num_bad_shared_relros = 0;
|
||||
|
||||
for (size_t n = 0; n < regions.size(); ++n) {
|
||||
MappedMemoryRegion& region = regions[n];
|
||||
|
||||
const std::string path = region.path;
|
||||
const bool is_legacy_relro = re2::RE2::FullMatch(path, legacy_linker_re);
|
||||
const bool is_modern_relro = re2::RE2::FullMatch(path, modern_linker_re);
|
||||
|
||||
if (is_legacy_relro && is_modern_relro) {
|
||||
LOG(ERROR) << prefix
|
||||
<< "FAIL RELRO cannot be both Legacy and Modern (test error)";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!is_legacy_relro && !is_modern_relro) {
|
||||
// Ignore any mapping that isn't a shared RELRO.
|
||||
continue;
|
||||
}
|
||||
|
||||
num_shared_relros++;
|
||||
|
||||
void* region_start = reinterpret_cast<void*>(region.start);
|
||||
void* region_end = reinterpret_cast<void*>(region.end);
|
||||
|
||||
// Check that it is mapped read-only.
|
||||
const uint8_t expected_flags = MappedMemoryRegion::READ;
|
||||
const uint8_t expected_mask = MappedMemoryRegion::READ |
|
||||
MappedMemoryRegion::WRITE |
|
||||
MappedMemoryRegion::EXECUTE;
|
||||
|
||||
uint8_t region_flags = region.permissions & expected_mask;
|
||||
if (region_flags != expected_flags) {
|
||||
LOG(ERROR)
|
||||
<< prefix
|
||||
<< base::StringPrintf(
|
||||
"Shared RELRO section at %p-%p is not mapped read-only. "
|
||||
"Protection flags are %d (%d expected)!",
|
||||
region_start,
|
||||
region_end,
|
||||
region_flags,
|
||||
expected_flags);
|
||||
num_bad_shared_relros++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Shared RELROs implemented by ModernLinker are not in ashmem. ModernLinker
|
||||
// (via android_dlopen_ext()) maps everything with MAP_PRIVATE rather than
|
||||
// MAP_SHARED. Remapping such a RELRO section read-write will therefore
|
||||
// succeed, but it is not a problem. The memory copy-on-writes, and updates
|
||||
// are not visible to either the mapped file or other processes mapping the
|
||||
// same file. So... we skip the remap test for ModernLinker.
|
||||
if (is_modern_relro) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check that trying to remap it read-write fails with EACCES
|
||||
size_t region_size = region.end - region.start;
|
||||
int ret = ::mprotect(region_start, region_size, PROT_READ | PROT_WRITE);
|
||||
if (ret != -1) {
|
||||
LOG(ERROR)
|
||||
<< prefix
|
||||
<< base::StringPrintf(
|
||||
"Shared RELRO section at %p-%p could be remapped read-write!?",
|
||||
region_start,
|
||||
region_end);
|
||||
num_bad_shared_relros++;
|
||||
// Just in case.
|
||||
::mprotect(region_start, region_size, PROT_READ);
|
||||
} else if (errno != EACCES) {
|
||||
LOG(ERROR) << prefix << base::StringPrintf(
|
||||
"Shared RELRO section at %p-%p failed "
|
||||
"read-write mprotect with "
|
||||
"unexpected error %d (EACCES:%d wanted): %s",
|
||||
region_start,
|
||||
region_end,
|
||||
errno,
|
||||
EACCES,
|
||||
strerror(errno));
|
||||
num_bad_shared_relros++;
|
||||
}
|
||||
}
|
||||
|
||||
VLOG(0) << prefix
|
||||
<< base::StringPrintf(
|
||||
"There are %d shared RELRO sections in this process, of which "
|
||||
"%d are bad",
|
||||
num_shared_relros, num_bad_shared_relros);
|
||||
|
||||
if (num_bad_shared_relros > 0) {
|
||||
LOG(ERROR) << prefix << "FAIL Bad RELROs sections in this process";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (num_shared_relros == 0) {
|
||||
LOG(ERROR) << prefix
|
||||
<< "FAIL Missing shared RELRO sections in this process!";
|
||||
return false;
|
||||
}
|
||||
|
||||
VLOG(0) << prefix << "SUCCESS";
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
jboolean JNI_LinkerTests_CheckForSharedRelros(JNIEnv* env,
|
||||
jboolean in_browser_process) {
|
||||
return RunChecks(in_browser_process);
|
||||
}
|
||||
|
||||
} // namespace content
|
@ -1,16 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!-- Copyright 2013 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.
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent" android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
<org.chromium.content_shell.ShellManager
|
||||
android:id="@+id/shell_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
</LinearLayout>
|
@ -1,122 +0,0 @@
|
||||
// Copyright 2014 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.chromium_linker_test_apk;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
||||
import org.chromium.base.Log;
|
||||
import org.chromium.base.library_loader.LibraryLoader;
|
||||
import org.chromium.base.library_loader.LibraryProcessType;
|
||||
import org.chromium.base.library_loader.Linker;
|
||||
import org.chromium.content_public.browser.BrowserStartupController;
|
||||
import org.chromium.content_public.browser.WebContents;
|
||||
import org.chromium.content_shell.Shell;
|
||||
import org.chromium.content_shell.ShellManager;
|
||||
import org.chromium.ui.base.ActivityWindowAndroid;
|
||||
|
||||
/**
|
||||
* Test activity used for verifying the different configuration options for the ContentLinker.
|
||||
*/
|
||||
public class ChromiumLinkerTestActivity extends Activity {
|
||||
private static final String TAG = "LinkerTest";
|
||||
|
||||
private ShellManager mShellManager;
|
||||
private ActivityWindowAndroid mWindowAndroid;
|
||||
|
||||
@Override
|
||||
public void onCreate(final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// Setup the TestRunner class name.
|
||||
Linker.setupForTesting(Linker.LINKER_IMPLEMENTATION_LEGACY,
|
||||
"org.chromium.chromium_linker_test_apk.LinkerTests");
|
||||
|
||||
// Load the library in the browser process, this will also run the test
|
||||
// runner in this process.
|
||||
LibraryLoader.getInstance().ensureInitialized();
|
||||
|
||||
// Now, start a new renderer process by creating a new view.
|
||||
// This will run the test runner in the renderer process.
|
||||
|
||||
LayoutInflater inflater =
|
||||
(LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
View view = inflater.inflate(R.layout.test_activity, null);
|
||||
mShellManager = view.findViewById(R.id.shell_container);
|
||||
mWindowAndroid = new ActivityWindowAndroid(this, false);
|
||||
mShellManager.setWindow(mWindowAndroid);
|
||||
|
||||
mShellManager.setStartupUrl("about:blank");
|
||||
|
||||
BrowserStartupController.getInstance().startBrowserProcessesAsync(
|
||||
LibraryProcessType.PROCESS_BROWSER, true, false,
|
||||
new BrowserStartupController.StartupCallback() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
finishInitialization(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure() {
|
||||
initializationFailed();
|
||||
}
|
||||
});
|
||||
|
||||
// TODO(digit): Ensure that after the content view is initialized,
|
||||
// the program finishes().
|
||||
}
|
||||
|
||||
private void finishInitialization(Bundle savedInstanceState) {
|
||||
String shellUrl = ShellManager.DEFAULT_SHELL_URL;
|
||||
mShellManager.launchShell(shellUrl);
|
||||
}
|
||||
|
||||
private void initializationFailed() {
|
||||
Log.e(TAG, "ContentView initialization failed.");
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
mWindowAndroid.saveInstanceState(outState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
|
||||
WebContents webContents = getActiveWebContents();
|
||||
if (webContents != null) webContents.onHide();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
|
||||
WebContents webContents = getActiveWebContents();
|
||||
if (webContents != null) webContents.onHide();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
mWindowAndroid.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The {@link WebContents} owned by the currently visible {@link Shell} or null if
|
||||
* one is not showing.
|
||||
*/
|
||||
public WebContents getActiveWebContents() {
|
||||
if (mShellManager == null) return null;
|
||||
Shell shell = mShellManager.getActiveShell();
|
||||
return shell != null ? shell.getWebContents() : null;
|
||||
}
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
// Copyright 2014 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.chromium_linker_test_apk;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
|
||||
import org.chromium.base.BuildConfig;
|
||||
import org.chromium.base.ContextUtils;
|
||||
import org.chromium.base.PathUtils;
|
||||
import org.chromium.base.library_loader.LibraryLoader;
|
||||
import org.chromium.base.library_loader.LibraryProcessType;
|
||||
import org.chromium.base.multidex.ChromiumMultiDexInstaller;
|
||||
import org.chromium.ui.base.ResourceBundle;
|
||||
|
||||
/**
|
||||
* Application for testing the Chromium Linker
|
||||
*/
|
||||
public class ChromiumLinkerTestApplication extends Application {
|
||||
private static final String PRIVATE_DATA_DIRECTORY_SUFFIX = "chromium_linker_test";
|
||||
|
||||
@Override
|
||||
protected void attachBaseContext(Context base) {
|
||||
super.attachBaseContext(base);
|
||||
boolean isBrowserProcess = !ContextUtils.getProcessName().contains(":");
|
||||
LibraryLoader.getInstance().setLibraryProcessType(isBrowserProcess
|
||||
? LibraryProcessType.PROCESS_BROWSER
|
||||
: LibraryProcessType.PROCESS_CHILD);
|
||||
if (BuildConfig.IS_MULTIDEX_ENABLED) {
|
||||
ChromiumMultiDexInstaller.install(this);
|
||||
}
|
||||
ContextUtils.initApplicationContext(this);
|
||||
ResourceBundle.setNoAvailableLocalePaks();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
PathUtils.setPrivateDataDirectorySuffix(PRIVATE_DATA_DIRECTORY_SUFFIX);
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
// Copyright 2014 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.chromium_linker_test_apk;
|
||||
|
||||
import org.chromium.base.annotations.JNINamespace;
|
||||
import org.chromium.base.annotations.NativeMethods;
|
||||
import org.chromium.base.library_loader.Linker;
|
||||
|
||||
/**
|
||||
* A class that is only used in linker test APK to perform runtime checks
|
||||
* in the current process.
|
||||
*/
|
||||
@JNINamespace("content")
|
||||
public class LinkerTests implements Linker.TestRunner {
|
||||
private static final String TAG = "LinkerTest";
|
||||
|
||||
public LinkerTests() {}
|
||||
|
||||
@Override
|
||||
public boolean runChecks(boolean isBrowserProcess) {
|
||||
return LinkerTestsJni.get().checkForSharedRelros(isBrowserProcess);
|
||||
}
|
||||
|
||||
@NativeMethods
|
||||
interface Natives {
|
||||
// Check that there are shared RELRO sections in the current process,
|
||||
// and that they are properly mapped read-only. Returns true on success.
|
||||
boolean checkForSharedRelros(boolean isBrowserProcess);
|
||||
}
|
||||
}
|
@ -104,7 +104,6 @@ display log messages to the `LogCat` pane.
|
||||
<classpathentry kind="src" path="content/shell/android/java/src"/>
|
||||
<classpathentry kind="src" path="content/shell/android/shell_apk/src"/>
|
||||
<classpathentry kind="src" path="content/shell/android/javatests/src"/>
|
||||
<classpathentry kind="src" path="content/shell/android/linker_test_apk/src"/>
|
||||
<classpathentry kind="lib" path="third_party/android_sdk/public/platforms/android-27/data/layoutlib.jar"/>
|
||||
<classpathentry kind="lib" path="third_party/android_sdk/public/platforms/android-27/android.jar"/>
|
||||
<classpathentry kind="output" path="out/bin"/>
|
||||
|
@ -4,13 +4,6 @@ The crazy linker is a custom dynamic linker used by Chrome on older Android
|
||||
versions where dynamic linking is not as advanced. It provides
|
||||
`android_dlopen_ext` functionality, RELRO sharing, compressed relocations, etc.
|
||||
|
||||
For crazy reasons outlined in `linker/test_case.py` this linker cannot be tested
|
||||
using GTest or instrumentation test, hence it also carries a custom testing
|
||||
framework. The tests are not run as part of CQ, but it is still desirable to run
|
||||
them before landing changes in code locations listed below.
|
||||
|
||||
Sorry.
|
||||
|
||||
These instructions assume
|
||||
[Building Chromium for Android](android_build_instructions.md) as a
|
||||
prerequisite.
|
||||
@ -23,12 +16,6 @@ third_party/android_crazy_linker
|
||||
base/android/java/src/org/chromium/base/library_loader
|
||||
```
|
||||
|
||||
The tests themselves are living mostly in these places:
|
||||
```
|
||||
build/android/pylib/linker/test_case.py
|
||||
content/shell/android
|
||||
```
|
||||
|
||||
## Running native tests
|
||||
|
||||
This will run both unittests and regression tests:
|
||||
@ -40,16 +27,6 @@ out/Release/bin/run_android_crazy_linker_tests --unit-tests
|
||||
Verbosity of the output can be increased by setting `CRAZY_DEBUG` to 1 in
|
||||
`crazy_linker_debug.h`.
|
||||
|
||||
## Running Java Tests
|
||||
|
||||
We recommend running these tests in Release mode, as there are known
|
||||
complications in testing with the component build. Setting `Linker.DEBUG` to
|
||||
`true` should also help increase verbosity of the output.
|
||||
```
|
||||
autoninja -C out/Release chromium_linker_test_apk
|
||||
out/Release/bin/run_chromium_linker_test_apk
|
||||
```
|
||||
|
||||
## Fuzzer Tests
|
||||
|
||||
There are also a few tests for fuzzing the ZIP parser. The instructions to run
|
||||
|
@ -220,7 +220,6 @@ to the classpath for downstream development. See "additional_entries" below.
|
||||
<classpathentry kind="src" path="content/shell/android/browsertests_apk/src"/>
|
||||
<classpathentry kind="src" path="content/shell/android/java/src"/>
|
||||
<classpathentry kind="src" path="content/shell/android/javatests/src"/>
|
||||
<classpathentry kind="src" path="content/shell/android/linker_test_apk/src"/>
|
||||
<classpathentry kind="src" path="content/shell/android/shell_apk/src"/>
|
||||
<classpathentry kind="src" path="device/bluetooth/android/java/src"/>
|
||||
<classpathentry kind="src" path="device/bluetooth/test/android/java/src"/>
|
||||
|
Reference in New Issue
Block a user