blob: 83e55d2f909676d2814b12c10032d1d625186cb3 [file] [log] [blame]
# Copyright 2016 The Cobalt Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Starboard Android shared platform configuration for gyp_cobalt."""
from __future__ import print_function
import imp # pylint: disable=deprecated-module
import os
import subprocess
from starboard.android.shared import sdk_utils
from starboard.build import clang as clang_build
from starboard.build.platform_configuration import PlatformConfiguration
from starboard.tools import build
from starboard.tools.testing import test_filter
from starboard.tools.toolchain import ar
from starboard.tools.toolchain import bash
from starboard.tools.toolchain import clang
from starboard.tools.toolchain import clangxx
from starboard.tools.toolchain import cp
from starboard.tools.toolchain import touch
_APK_DIR = os.path.join(os.path.dirname(__file__), os.path.pardir, 'apk')
_APK_BUILD_ID_FILE = os.path.join(_APK_DIR, 'build.id')
_COBALT_GRADLE = os.path.join(_APK_DIR, 'cobalt-gradle.sh')
# The API level of NDK tools to use. This should be the minimum API level on
# which the app is expected to run. If some feature from a newer NDK level is
# needed, this may be increased with caution.
# https://developer.android.com/ndk/guides/stable_apis.html
#
# Using 24 will lead to missing symbols on API 23 devices.
# https://github.com/android-ndk/ndk/issues/126
_ANDROID_NDK_API_LEVEL = '21'
# Maps the Android ABI to the clang & ar executable names.
_ABI_TOOL_NAMES = {
'x86': ('i686-linux-android{}-clang'.format(_ANDROID_NDK_API_LEVEL),
'i686-linux-android-ar'),
'x86_64': ('x86_64-linux-android{}-clang'.format(_ANDROID_NDK_API_LEVEL),
'x86_64-linux-android-ar'),
'armeabi':
('armv7a-linux-androideabi{}-clang'.format(_ANDROID_NDK_API_LEVEL),
'armv7a-linux-androideabi-ar'),
'armeabi-v7a':
('armv7a-linux-androideabi{}-clang'.format(_ANDROID_NDK_API_LEVEL),
'arm-linux-androideabi-ar'),
'arm64-v8a':
('aarch64-linux-android{}-clang'.format(_ANDROID_NDK_API_LEVEL),
'aarch64-linux-android-ar'),
}
class AndroidConfiguration(PlatformConfiguration):
"""Starboard Android platform configuration."""
# TODO: make ASAN work with NDK tools and enable it by default
def __init__(self,
platform,
android_abi,
asan_enabled_by_default=False,
sabi_json_path='starboard/sabi/default/sabi.json'):
super(AndroidConfiguration, self).__init__(platform,
asan_enabled_by_default)
self._target_toolchain = None
self._host_toolchain = None
self.AppendApplicationConfigurationPath(os.path.dirname(__file__))
self.android_abi = android_abi
self.sabi_json_path = sabi_json_path
self.android_home = sdk_utils.GetSdkPath()
self.android_ndk_home = sdk_utils.GetNdkPath()
print('Using Android SDK at {}'.format(self.android_home))
print('Using Android NDK at {}'.format(self.android_ndk_home))
def GetBuildFormat(self):
"""Returns the desired build format."""
# The comma means that ninja and qtcreator_ninja will be chained and use the
# same input information so that .gyp files will only have to be parsed
# once.
return 'ninja,qtcreator_ninja'
def GetVariables(self, configuration):
variables = super(AndroidConfiguration, self).GetVariables(
configuration, use_clang=1)
variables.update({
'ANDROID_HOME':
self.android_home,
'NDK_HOME':
self.android_ndk_home,
'ANDROID_ABI':
self.android_abi,
'include_path_platform_deploy_gypi':
'starboard/android/shared/platform_deploy.gypi',
})
return variables
def GetDeployPathPatterns(self):
# example src/out/android-arm64/devel/cobalt.apk
return ['*.apk']
def GetGeneratorVariables(self, config_name):
_ = config_name
generator_variables = {
'qtcreator_session_name_prefix': 'cobalt',
}
return generator_variables
def SetupPlatformTools(self, build_number):
sdk_utils.InstallSdkIfNeeded()
subprocess.call([_COBALT_GRADLE, '--reset'])
with open(_APK_BUILD_ID_FILE, 'w') as build_id_file:
build_id_file.write('{}'.format(build_number))
def GetEnvironmentVariables(self):
env_variables = {}
# Android builds tend to consume significantly more memory than the
# default settings permit, so cap this at 1 in order to avoid build
# issues. Without this, 32GB machines end up getting automatically
# configured to run 5 at a time, which can be too much for at least
# android-arm64_debug.
# TODO: Eventually replace this with something more robust, like an
# implementation of the abstract toolchain for Android.
env_variables.update({'GYP_LINK_CONCURRENCY': '1'})
return env_variables
def GetTargetToolchain(self, **kwargs):
if not self._target_toolchain:
tool_prefix = os.path.join(sdk_utils.GetNdkPath(), 'toolchains', 'llvm',
'prebuilt', 'linux-x86_64', 'bin', '')
cc_path = self.build_accelerator + ' ' + tool_prefix + _ABI_TOOL_NAMES[
self.android_abi][0]
cxx_path = cc_path + '++'
ar_path = tool_prefix + _ABI_TOOL_NAMES[self.android_abi][1]
clang_flags = [
# libwebp uses the cpufeatures library to detect ARM NEON support
'-I{}/sources/android/cpufeatures'.format(self.android_ndk_home),
# Mimic build/cmake/android.toolchain.cmake in the Android NDK.
'-ffunction-sections',
'-funwind-tables',
'-fstack-protector-strong',
'-no-canonical-prefixes',
# Other flags
'-fsigned-char',
'-fno-limit-debug-info',
'-fno-exceptions',
'-fcolor-diagnostics',
'-fno-strict-aliasing', # See http://crbug.com/32204
# Default visibility is hidden to enable dead stripping.
'-fvisibility=hidden',
# Any warning will stop the build.
'-Werror',
# Disable errors for the warning till the Android NDK r19 is fixed.
# The warning is trigger when compiling .c files and complains for
# '-stdlib=libc++' which is added by the NDK.
'-Wno-error=unused-command-line-argument',
# Don't warn about register variables (in base and net)
'-Wno-deprecated-register',
# Don't warn about deprecated ICU methods (in googleurl and net)
'-Wno-deprecated-declarations',
# Skia doesn't use overrides.
'-Wno-inconsistent-missing-override',
# shifting a negative signed value is undefined
'-Wno-shift-negative-value',
# Don't warn for implicit sign conversions. (in v8 and protobuf)
'-Wno-sign-conversion',
]
clang_defines = [
# Enable compile-time decisions based on the ABI
'ANDROID_ABI={}'.format(self.android_abi),
# -DANDROID is an argument to some ifdefs in the NDK's eglplatform.h
'ANDROID',
# Cobalt on Linux flag
'COBALT_LINUX',
# So that we get the PRI* macros from inttypes.h
'__STDC_FORMAT_MACROS',
# Enable GNU extensions to get prototypes like ffsl.
'_GNU_SOURCE=1',
# Undefining __linux__ causes the system headers to make wrong
# assumptions about which C-library is used on the platform.
'__BIONIC__',
# Undefining __linux__ leaves libc++ without a threads implementation.
# TODO: See if there's a way to make libcpp threading use Starboard.
'_LIBCPP_HAS_THREAD_API_PTHREAD',
]
linker_flags = [
# Use the static LLVM libc++.
'-static-libstdc++',
# Mimic build/cmake/android.toolchain.cmake in the Android NDK, but
# force build-id to sha1, so that older lldb versions can still find
# debugsymbols, see https://github.com/android-ndk/ndk/issues/885
'-Wl,--build-id=sha1',
'-Wl,--warn-shared-textrel',
'-Wl,--fatal-warnings',
'-Wl,--gc-sections',
'-Wl,-z,nocopyreloc',
# Wrapper synchronizes punch-out video bounds with the UI frame.
'-Wl,--wrap=eglSwapBuffers',
]
self._target_toolchain = [
clang.CCompiler(
path=cc_path, defines=clang_defines, extra_flags=clang_flags),
clang.CxxCompiler(
path=cxx_path,
defines=clang_defines,
extra_flags=clang_flags + [
'-std=c++14',
]),
clang.AssemblerWithCPreprocessor(
path=cc_path, defines=clang_defines, extra_flags=clang_flags),
ar.StaticThinLinker(path=ar_path),
ar.StaticLinker(path=ar_path),
clangxx.SharedLibraryLinker(path=cxx_path, extra_flags=linker_flags),
clangxx.ExecutableLinker(path=cxx_path, extra_flags=linker_flags),
]
return self._target_toolchain
def GetHostToolchain(self, **kwargs):
if not self._host_toolchain:
if not hasattr(self, 'host_compiler_environment'):
self.host_compiler_environment = build.GetHostCompilerEnvironment(
clang_build.GetClangSpecification(), self.build_accelerator)
cc_path = self.host_compiler_environment['CC_host']
cxx_path = self.host_compiler_environment['CXX_host']
self._host_toolchain = [
clang.CCompiler(path=cc_path),
clang.CxxCompiler(path=cxx_path),
clang.AssemblerWithCPreprocessor(path=cc_path),
ar.StaticThinLinker(),
ar.StaticLinker(),
clangxx.ExecutableLinker(path=cxx_path),
clangxx.SharedLibraryLinker(path=cxx_path),
cp.Copy(),
touch.Stamp(),
bash.Shell(),
]
return self._host_toolchain
def GetLauncher(self):
"""Gets the module used to launch applications on this platform."""
module_path = os.path.abspath(
os.path.join(os.path.dirname(__file__), 'launcher.py'))
launcher_module = imp.load_source('launcher', module_path)
return launcher_module
def GetTestFilters(self):
filters = super(AndroidConfiguration, self).GetTestFilters()
for target, tests in self.__FILTERED_TESTS.iteritems():
filters.extend(test_filter.TestFilter(target, test) for test in tests)
return filters
# A map of failing or crashing tests per target.
__FILTERED_TESTS = { # pylint: disable=invalid-name
'player_filter_tests': [
# GetMaxNumberOfCachedFrames() on Android is device dependent,
# and Android doesn't provide an API to get it. So, this function
# doesn't make sense on Android. But HoldFramesUntilFull tests depend
# on this number strictly.
'VideoDecoderTests/VideoDecoderTest.HoldFramesUntilFull/*',
# Currently, invalid input tests are not supported.
'VideoDecoderTests/VideoDecoderTest.SingleInvalidInput/*',
'VideoDecoderTests/VideoDecoderTest'
'.MultipleValidInputsAfterInvalidKeyFrame/*',
'VideoDecoderTests/VideoDecoderTest.MultipleInvalidInput/*',
# Android currently does not support multi-video playback, which
# the following tests depend upon.
'VideoDecoderTests/VideoDecoderTest.ThreeMoreDecoders/*',
# The video pipeline will hang if it doesn't receive any input.
'PlayerComponentsTests/PlayerComponentsTest.EOSWithoutInput/*',
# The e/eac3 audio time reporting during pause will be revisitied.
'PlayerComponentsTests/PlayerComponentsTest.Pause/15',
],
'nplb': [
# This test is failing because localhost is not defined for IPv6 in
# /etc/hosts.
'SbSocketAddressTypes/SbSocketResolveTest.Localhost/1',
# These tests are taking longer due to interop on android. Work is
# underway to investigate whether this is acceptable.
'SbMediaCanPlayMimeAndKeySystem.ValidatePerformance',
'SbMediaConfigurationTest.ValidatePerformance',
# SbDirectory has problems with empty Asset dirs.
'SbDirectoryCanOpenTest.SunnyDayStaticContent',
'SbDirectoryGetNextTest.SunnyDayStaticContent',
'SbDirectoryOpenTest.SunnyDayStaticContent',
'SbFileGetPathInfoTest.WorksOnStaticContentDirectories',
# These tests are disabled due to not receiving the kEndOfStream
# player state update within the specified timeout.
'SbPlayerWriteSampleTests/SbPlayerWriteSampleTest.NoInput/*',
# Android does not use SbDrmSessionClosedFunc, which these tests
# depend on.
'SbDrmSessionTest.SunnyDay',
'SbDrmSessionTest.CloseDrmSessionBeforeUpdateSession',
# This test is failing because Android calls the
# SbDrmSessionUpdateRequestFunc with SbDrmStatus::kSbDrmStatusSuccess
# when invalid initialization data is passed to
# SbDrmGenerateSessionUpdateRequest().
'SbDrmSessionTest.InvalidSessionUpdateRequestParams',
],
}
def GetPathToSabiJsonFile(self):
return self.sabi_json_path