# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- # vim: set filetype=python: # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. # Ensure Android SDK and build-tools versions depending on mobile target. @depends(host, toolchains_base_dir, "--help") @imports(_from="os.path", _import="isdir") def default_android_sdk_root(host, toolchains_base_dir, _): sdk_basename = { "Darwin": "android-sdk-macosx", "Linux": "android-sdk-linux", "WINNT": "android-sdk-windows", }.get(host.kernel, "android-sdk") for sdk_basename in (sdk_basename, "android-sdk"): path = os.path.join(toolchains_base_dir, sdk_basename) if isdir(path): return path option( "--with-android-sdk", nargs=1, default=default_android_sdk_root, help="Location where the Android SDK can be found (like ~/.mozbuild/android-sdk-linux){|}", ) @dependable @imports(_from="platform", _import="machine") @imports(_from="mozboot.android", _import="get_os_name_for_android") @imports(_from="mozboot.android", _import="get_os_tag_for_android") def android_os_info(): os_name = get_os_name_for_android() os_tag = get_os_tag_for_android(os_name) os_arch = machine() if os_arch.lower() == "amd64": # On Windows, x86_64 is reported as AMD64, but we use x86_64 # everywhere else, so let's normalize it. os_arch = "x86_64" if os_name == "windows" and os_arch.startswith("arm"): die( "Building for Android is not supported on ARM64 Windows because " "Google does not distribute an emulator binary for ARM64 Windows. " "See also https://issuetracker.google.com/issues/264614669." ) return namespace(os_name=os_name, os_tag=os_tag, os_arch=os_arch) @depends(android_os_info) @imports(_from="mozboot.android", _import="AVD_MANIFEST_X86_64") @imports(_from="mozboot.android", _import="AVD_MANIFEST_ARM64") @imports(_from="mozboot.android", _import="get_avd_manifest") def avd_manifest(android_os_info): if any(k in android_os_info.os_arch for k in ("x86", "x86_64")): avd_manifest_path_for_arch = AVD_MANIFEST_X86_64 else: avd_manifest_path_for_arch = AVD_MANIFEST_ARM64 return get_avd_manifest(avd_manifest_path_for_arch) @imports(_from="os.path", _import="exists") @imports(_from="mozboot.android", _import="get_android_packages") @imports(_from="mozboot.android", _import="ensure_android_packages") @imports(_from="mozboot.android", _import="AndroidPackageList") def _ensure_android_package( package_relative_path, sdk_root, os_name, os_arch, want_bootstrap, package_prefix, package_list_enum, avd_manifest=None, ): full_path = os.path.join(sdk_root, package_relative_path) if exists(full_path): return [full_path] if not want_bootstrap("android-sdk"): die( f"You must install the Android {package_relative_path}. " f"Try |mach bootstrap|. (Looked for {full_path})" ) packages = get_android_packages(package_list_enum) to_install = {pkg for pkg in packages if pkg.startswith(package_prefix)} ensure_android_packages( os_name, os_arch, packages=to_install, no_interactive=True, avd_manifest=avd_manifest, ) return [full_path] @depends("--with-android-sdk", android_os_info, want_bootstrap) @imports(_from="os.path", _import="isdir") @imports(_from="mozboot.android", _import="ensure_android_sdk") @imports(_from="mozboot.android", _import="get_sdk_path") def android_sdk_root(value, android_os_info, want_bootstrap): if value: sdk_path = value[0] if not isdir(sdk_path): die( "The path you specified with --with-android-sdk (%s) is not " "a directory" % sdk_path ) return sdk_path if not want_bootstrap("android-sdk"): die( "You must specify --with-android-sdk=/path/to/sdk when targeting Android, " "or try |mach bootstrap|." ) ensure_android_sdk(android_os_info.os_name, android_os_info.os_tag) return str(get_sdk_path(android_os_info.os_name)) @dependable def android_sdk_version(): # We support Android SDK version 21 and up by default. # See the --enable-android-min-sdk option below. # # Warning: Before increasing the with-android-min-sdk value, please note several places in # and out of tree have to be changed. Otherwise, places like Treeherder or archive.mozilla.org # will advertise a bad API level. This may confuse people. As an example, please look at # bug 1384482. # If you think you can't handle the whole set of changes, please reach out to the Release # Engineering team. return namespace( build_tools_version="36.0.0", compile_sdk_version="36", target_sdk_version="35", min_sdk_version="21", ) option( "--with-android-min-sdk", default=android_sdk_version.min_sdk_version, help="Impose a minimum Firefox for Android SDK version", ) @depends("--with-android-min-sdk", android_sdk_version.target_sdk_version) @imports(_from="__builtin__", _import="ValueError") def valid_android_min_sdk(min_sdk_version, target_sdk_version): if not min_sdk_version: die("--without-android-min-sdk is not a valid option") try: if int(min_sdk_version[0]) > int(target_sdk_version): die( "--with-android-min-sdk is expected to be less than {}".format( target_sdk_version ) ) except ValueError: die("--with-android-min-sdk takes a numerical value") return min_sdk_version[0] set_config("MOZ_ANDROID_MIN_SDK_VERSION", valid_android_min_sdk) @depends(android_sdk_root, android_sdk_version, android_os_info, want_bootstrap) @checking("for Android build-tools") @imports(_from="mozboot.android", _import="AndroidPackageList") def android_build_tools(sdk_root, sdk_version, android_os_info, want_bootstrap): prefix = "build-tools" return _ensure_android_package( package_relative_path=os.path.join(prefix, sdk_version.build_tools_version), sdk_root=sdk_root, os_name=android_os_info.os_name, os_arch=android_os_info.os_arch, want_bootstrap=want_bootstrap, package_prefix=prefix, package_list_enum=AndroidPackageList.ALL, ) @depends(android_sdk_root, android_os_info, want_bootstrap) @checking("for Android platform-tools") @imports(_from="mozboot.android", _import="AndroidPackageList") def android_platform_tools(sdk_root, android_os_info, want_bootstrap): prefix = "platform-tools" return _ensure_android_package( package_relative_path=prefix, sdk_root=sdk_root, os_name=android_os_info.os_name, os_arch=android_os_info.os_arch, want_bootstrap=want_bootstrap, package_prefix=prefix, package_list_enum=AndroidPackageList.ALL, ) @depends(android_sdk_root, android_sdk_version, android_os_info, want_bootstrap) @checking("for Android platforms") @imports(_from="mozboot.android", _import="AndroidPackageList") def android_platforms(sdk_root, sdk_version, android_os_info, want_bootstrap): prefix = "platforms" platforms_path = os.path.join(prefix, "android-" + sdk_version.compile_sdk_version) return _ensure_android_package( package_relative_path=platforms_path, sdk_root=sdk_root, os_name=android_os_info.os_name, os_arch=android_os_info.os_arch, want_bootstrap=want_bootstrap, package_prefix=prefix, package_list_enum=AndroidPackageList.ALL, ) # Emulator @depends(android_sdk_root, android_os_info, want_bootstrap, avd_manifest) @checking("for Android emulator") @imports(_from="os.path", _import="exists") @imports(_from="mozboot.android", _import="AndroidPackageList") def android_emulator(sdk_root, android_os_info, want_bootstrap, avd_manifest): prefix = "emulator" return _ensure_android_package( package_relative_path=prefix, sdk_root=sdk_root, os_name=android_os_info.os_name, os_arch=android_os_info.os_arch, want_bootstrap=want_bootstrap, package_prefix=prefix, package_list_enum=AndroidPackageList.EMULATOR, avd_manifest=avd_manifest, ) @depends(toolchains_base_dir, want_bootstrap) @checking("for Bundletool") @imports(_from="os.path", _import="exists") @imports(_from="mozboot.android", _import="ensure_bundletool") def android_bundletool(toolchains_base_dir, want_bootstrap): bundletool_path = os.path.join(toolchains_base_dir, "bundletool.jar") if exists(bundletool_path): return [bundletool_path] if not want_bootstrap("android-sdk"): die( "You must install Bundletool. Try |mach bootstrap|. (Looked for %s)" % bundletool_path ) ensure_bundletool() return [bundletool_path] @depends( toolchains_base_dir, android_os_info, want_bootstrap, avd_manifest, when=~moz_automation, ) @checking("for AVD") @imports(_from="os.path", _import="exists") @imports(_from="mozboot.android", _import="ensure_android_avd") def android_avd(toolchains_base_dir, android_os_info, want_bootstrap, avd_manifest): avd_path = os.path.join(toolchains_base_dir, "android-device", "avd") if exists(avd_path): return [avd_path] if not want_bootstrap("android-sdk"): die("You must install AVD. Try |mach bootstrap|. (Looked for %s)" % avd_path) ensure_android_avd( android_os_info.os_name, android_os_info.os_arch, no_interactive=True, avd_manifest=avd_manifest, ) return [avd_path] @template def check_file(filename, search_dirs): @depends(search_dirs) @checking("for %s" % filename) @imports(_from="os.path", _import="exists") @imports(_from="os.path", _import="join") def require_file(dirs): for d in dirs: path = join(d, filename) if exists(path): return path die("The file %s was not found. Try |mach bootstrap|" % filename) return require_file @template def check_android_tools(tool, tool_dir): check = check_prog( tool.upper(), (tool, tool + ".exe"), paths=tool_dir, allow_missing=True ) @depends(check) def require_tool(result): if result is None: die("The program %s was not found. Try |mach bootstrap|" % tool) return result return require_tool set_config("ANDROID_SDK_ROOT", android_sdk_root) check_android_tools("zipalign", android_build_tools) check_android_tools("adb", android_platform_tools) check_android_tools("emulator", android_emulator) check_file("android.jar", android_platforms) set_config("ANDROID_BUILD_TOOLS_VERSION", android_sdk_version.build_tools_version) set_config("ANDROID_TARGET_SDK", android_sdk_version.target_sdk_version) set_config("ANDROID_COMPILE_SDK", android_sdk_version.compile_sdk_version)