Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ group("flutter") {
]
}

if (is_ios || is_android) {
public_deps += [ "//flutter/testing/scenario_app" ]
}

# Compile all unittests targets if enabled.
if (enable_unittests) {
public_deps += [
Expand Down
165 changes: 163 additions & 2 deletions build/dart/rules.gni
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,171 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

# This file has rules for making Dart packages and Dart-based Mojo applications.
# The entrypoint is the dart_pkg rule.
# This file has rules for making Dart packages and snapshots.

import("//build/compiled_action.gni")
import("//build/module_args/dart.gni")
import("//flutter/common/config.gni")
import("//third_party/dart/build/dart/dart_action.gni")

# Creates a dart kernel (dill) file suitable for use with gen_snapshot, as well
# as the app-jit, aot-elf, or aot-assembly snapshot for Android or iOS.
#
# Invoker must supply dart_main and package_config. Invoker may optionally
# supply aot as a boolean and product as a boolean.
template("dart_snapshot") {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an unfortunate repetition of the rule (in //flutter/testing/testing.gni) used by the gtest harness for Dart fixtures. Can we dry this up (in a later patch if you wish)? If anything, //build/dart/rules.gni is the right spot for such rules.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this will lead to template name collision if both gnis are included from a .GN definition.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are now several places where we have rules like this - I'd like to clean them up separately to avoid potential issues that only get caught in post submit :\

One thing I can see is that the testing rules lack special handling for iOS, which will need to be addressed.

assert(!is_fuchsia)
assert(defined(invoker.main_dart), "main_dart is a required parameter.")
assert(defined(invoker.package_config),
"package_config is a required parameter.")

kernel_target = "_${target_name}_kernel"
snapshot_target = "_${target_name}_snapshot"
is_aot =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Perhaps add assert(!is_fuchsia) here as this would be invalid on that target.

@richkadel: FYI, you may run into such assumptions while working with engine GN rules for Dart. We can patch them later though. The issue is that the assumption of AOT being tied to a specific runtime mode does not hold on Fuchsia.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fuchsia has its own template(s) for this.

Perhaps we could add it as an arg and default it to this, and let fuchsia specify the arg differently?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

flutter_runtime_mode can also be jit_release. It might simplify things for Fuchsia to use that to signal that a release build is using JIT rather than AOT (if it isn't like that already.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now I'm just moving this to //flutter/testing/scenario_app/runtime_mode.gni.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Errr... wrong comment thread - I moved it from common.gni. I'll add the assert.

flutter_runtime_mode == "profile" || flutter_runtime_mode == "release"

kernel_output = "$target_gen_dir/kernel_blob.bin"

prebuilt_dart_action(kernel_target) {
script = "//flutter/flutter_frontend_server/bin/starter.dart"

main_dart = rebase_path(invoker.main_dart)
package_config = rebase_path(invoker.package_config)
flutter_patched_sdk = rebase_path("$root_out_dir/flutter_patched_sdk")

deps = [ "//flutter/lib/snapshot:strong_platform" ]

inputs = [
main_dart,
package_config,
]

outputs = [ kernel_output ]

depfile = "$kernel_output.d"
abs_depfile = rebase_path(depfile)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: Not that it matters here, but using absolute paths trips up compiler proxies. If the script supports relative depfile paths, I'd recommend just using relative paths from the get go.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was cargo-culted from another template - it seems to make dart happy, which doesn't support compiler proxies so... I guess it's ok?

rebased_output = rebase_path(kernel_output, root_build_dir)
vm_args = [
"--depfile=$abs_depfile",
"--depfile_output_filename=$rebased_output",
"--disable-dart-dev",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this flag need to come first?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know - it's how the VM gets invoked today though and it doesn't complain?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just asked around. It did have to come first at some point in the past, but it can go anywhere now.

]

args = [
"--packages=" + rebase_path(package_config),
"--target=flutter",
"--sdk-root=" + flutter_patched_sdk,
"--output-dill=" + rebase_path(kernel_output),
]

if (is_aot) {
args += [
"--aot",
"--tfa",
]
} else {
# --no-link-platform is only valid when --aot isn't specified
args += [ "--no-link-platform" ]
}

if (defined(invoker.product) && invoker.product) {
# Setting this flag in a non-product release build for AOT (a "profile"
# build) causes the vm service isolate code to be tree-shaken from an app.
# See the pragma on the entrypoint here:
#
# https://github.com/dart-lang/sdk/blob/master/sdk/lib/_internal/vm/bin/vmservice_io.dart#L240
#
# Also, this define excludes debugging and profiling code from Flutter.
args += [ "-Ddart.vm.product=true" ]
} else {
if (!is_debug) {
# The following define excludes debugging code from Flutter.
args += [ "-Ddart.vm.profile=true" ]
}
}

args += [ rebase_path(main_dart) ]
}

compiled_action(snapshot_target) {
if (target_cpu == "x86" && host_os == "linux") {
# By default Dart will create a 32-bit gen_snapshot host binary if the target
# platform is 32-bit. Override this to create a 64-bit gen_snapshot for x86
# targets because some host platforms may not support 32-bit binaries.
tool = "//third_party/dart/runtime/bin:gen_snapshot_host_targeting_host"
toolchain = "//build/toolchain/$host_os:clang_x64"
} else {
tool = "//third_party/dart/runtime/bin:gen_snapshot"
}

inputs = [ kernel_output ]
deps = [ ":$kernel_target" ]
outputs = []

args = [ "--lazy_async_stacks" ]

if (is_debug && flutter_runtime_mode != "profile" &&
flutter_runtime_mode != "release" &&
flutter_runtime_mode != "jit_release") {
args += [ "--enable_asserts" ]
}

if (is_aot) {
args += [ "--deterministic" ]
if (is_ios) {
snapshot_assembly = "$target_gen_dir/ios/snapshot_assembly.S"
outputs += [ snapshot_assembly ]
args += [
"--snapshot_kind=app-aot-assembly",
"--assembly=" + rebase_path(snapshot_assembly),
]
} else if (is_android) {
libapp = "$target_gen_dir/android/libs/$android_app_abi/libapp.so"
outputs += [ libapp ]
args += [
"--snapshot_kind=app-aot-elf",
"--elf=" + rebase_path(libapp),
]
} else {
assert(false)
}
} else {
deps += [ "//flutter/lib/snapshot:generate_snapshot_bin" ]
vm_snapshot_data =
"$root_gen_dir/flutter/lib/snapshot/vm_isolate_snapshot.bin"
snapshot_data = "$root_gen_dir/flutter/lib/snapshot/isolate_snapshot.bin"
isolate_snapshot_data = "$target_gen_dir/isolate_snapshot_data"
isolate_snapshot_instructions = "$target_gen_dir/isolate_snapshot_instr"

inputs += [
vm_snapshot_data,
snapshot_data,
]

outputs += [
isolate_snapshot_data,
isolate_snapshot_instructions,
]
args += [
"--snapshot_kind=app-jit",
"--load_vm_snapshot_data=" + rebase_path(vm_snapshot_data),
"--load_isolate_snapshot_data=" + rebase_path(snapshot_data),
"--isolate_snapshot_data=" + rebase_path(isolate_snapshot_data),
"--isolate_snapshot_instructions=" +
rebase_path(isolate_snapshot_instructions),
]
}

args += [ rebase_path(kernel_output) ]
}

group(target_name) {
public_deps = [
":$kernel_target",
":$snapshot_target",
]
}
}

template("dart_pkg_helper") {
assert(defined(invoker.package_name))
Expand Down
49 changes: 49 additions & 0 deletions testing/scenario_app/BUILD.gn
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Copyright 2013 The Flutter 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("//flutter/build/dart/rules.gni")
import("//flutter/testing/scenario_app/runtime_mode.gni")

dart_snapshot("scenario_app_snapshot") {
main_dart = "lib/main.dart"
package_config = ".dart_tool/package_config.json"
}

if (!is_aot) {
if (is_android) {
_flutter_assets_dir = "$root_out_dir/scenario_app/app/assets/flutter_assets"
} else if (is_ios) {
_flutter_assets_dir =
"$root_out_dir/scenario_app/Scenarios/App.framework/flutter_assets"
} else {
assert(false)
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest adding a final else clause that contains only an assert(false, error message).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


copy("copy_jit_assets") {
visibility = [ ":*" ]
sources = [
"$target_gen_dir/isolate_snapshot_data",
"$target_gen_dir/isolate_snapshot_instr",
"$target_gen_dir/kernel_blob.bin",
]
outputs = [ "$_flutter_assets_dir/{{source_file_part}}" ]
deps = [ ":scenario_app_snapshot" ]
}
}

group("scenario_app") {
deps = [ ":scenario_app_snapshot" ]

if (!is_aot) {
deps += [ ":copy_jit_assets" ]
}

if (is_android) {
deps += [ "android" ]
}

if (is_ios) {
deps += [ "ios" ]
}
}
50 changes: 50 additions & 0 deletions testing/scenario_app/android/BUILD.gn
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Copyright 2013 The Flutter 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("//flutter/testing/scenario_app/runtime_mode.gni")

action("android") {
script = "run_gradle.py"

inputs = [ "$root_out_dir/flutter.jar" ]
sources = [
"app/build.gradle",
"app/src/androidTest/java/dev/flutter/TestRunner.java",
"app/src/androidTest/java/dev/flutter/scenarios/EngineLaunchE2ETest.java",
"app/src/androidTest/java/dev/flutter/scenarios/ExampleInstrumentedTest.java",
"app/src/androidTest/java/dev/flutter/scenariosui/MemoryLeakTests.java",
"app/src/androidTest/java/dev/flutter/scenariosui/PlatformTextureUiTests.java",
"app/src/androidTest/java/dev/flutter/scenariosui/PlatformViewUiTests.java",
"app/src/androidTest/java/dev/flutter/scenariosui/ScreenshotUtil.java",
"app/src/androidTest/java/dev/flutter/scenariosui/SpawnEngineTests.java",
"app/src/main/AndroidManifest.xml",
"app/src/main/java/dev/flutter/scenarios/SpawnedEngineActivity.java",
"app/src/main/java/dev/flutter/scenarios/StrictModeFlutterActivity.java",
"app/src/main/java/dev/flutter/scenarios/TestActivity.java",
"app/src/main/java/dev/flutter/scenarios/TestableFlutterActivity.java",
"app/src/main/java/dev/flutter/scenarios/TextPlatformView.java",
"app/src/main/java/dev/flutter/scenarios/TextPlatformViewActivity.java",
"app/src/main/java/dev/flutter/scenarios/TextPlatformViewFactory.java",
"app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java",
"build.gradle",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what do you think about globbing under app/src?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GN does not like globs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(gradle will still build the files anyway, but GN won't be aware of changes to unmentioned ones dirtying the build)

]
outputs = [ "$root_out_dir/scenario_app/app/outputs/apk/debug/app-debug.apk" ]

args = [
"assembleDebug",
"--no-daemon",
"-Pflutter_jar=" + rebase_path("$root_out_dir/flutter.jar"),
"-Pout_dir=" + rebase_path("$root_out_dir/scenario_app"),
]

if (is_aot) {
args += [ "-Plibapp=" + rebase_path("$target_gen_dir/libs") ]
inputs += [ "$target_gen_dir/libs/$android_app_abi/libapp.so" ]
}

deps = [
"//flutter/shell/platform/android:android_jar",
"//flutter/testing/scenario_app:scenario_app_snapshot",
]
}
10 changes: 7 additions & 3 deletions testing/scenario_app/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,18 @@ android {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
sourceSets {
main.assets.srcDirs += "${project.buildDir}/assets"
sourceSets.main {
assets.srcDirs += "${project.buildDir}/assets"
if (project.hasProperty('libapp')) {
jni.srcDirs = []
jniLibs.srcDirs = [project.property('libapp')]
}
}
}

dependencies {
implementation files(project.property('flutter_jar'))
compile 'com.facebook.testing.screenshot:layout-hierarchy-common:0.12.0'
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'com.google.android.material:material:1.0.0'
Expand Down
5 changes: 4 additions & 1 deletion testing/scenario_app/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ allprojects {
}
}

rootProject.buildDir = '../build'
rootProject.buildDir = project.hasProperty('out_dir')
? project.property('out_dir')
: '../build'

subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
Expand Down
26 changes: 26 additions & 0 deletions testing/scenario_app/android/run_gradle.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/usr/bin/env python
# Copyright 2013 The Flutter Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""
Invokes gradlew for building the scenario_app from GN/Ninja.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does gn have a way to run a target? If yes, is this wrapper script still needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GN knows how to run compiler binaries with some help, and it knows how to run python scripts.

This is actually really hacky - we shouldn't be invoking gradle from GN, but refactoring that will take more work and we're no worse off than we were before invoking gradle from a shell script.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does it know how to run a bash script? If that's the case, then gradlew directly should work, no?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That doesn't work on Windows.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could use gradlew.bat on Windows

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which is all this python script is doing

"""

import os
import sys
import subprocess

def main():
BAT = '.bat' if sys.platform.startswith(('cygwin', 'win')) else ''
android_dir = os.path.abspath(os.path.dirname(__file__))
gradle_bin = os.path.join('.', 'gradlew%s' % BAT)
result = subprocess.check_output(
args=[gradle_bin] + sys.argv[1:],
cwd=android_dir,
)
return 0


if __name__ == '__main__':
sys.exit(main())
13 changes: 3 additions & 10 deletions testing/scenario_app/assemble_apk.sh
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,9 @@ SCRIPT_DIR=$(follow_links "$(dirname -- "${BASH_SOURCE[0]}")")
SRC_DIR="$(cd "$SCRIPT_DIR/../../.."; pwd -P)"
export ANDROID_HOME="$SRC_DIR/third_party/android_tools/sdk"

"$SRC_DIR/flutter/tools/gn" --unopt
ninja -C "$SRC_DIR/out/host_debug_unopt" sky_engine -j 400

"$SCRIPT_DIR/compile_android_aot.sh" "$1" "$2"

(
cd "$SCRIPT_DIR/android"
./gradlew assembleDebug --no-daemon
)
# TODO(dnfield): Delete this whole file.
DEVICE_OUT_DIR=${2%"clang_x64"}

# LUCI expects to find the APK here
mkdir -p "$SCRIPT_DIR/android/app/build/outputs/apk/debug"
cp "$SCRIPT_DIR/build/app/outputs/apk/debug/app-debug.apk" "$SCRIPT_DIR/android/app/build/outputs/apk/debug"
cp "$DEVICE_OUT_DIR/scenario_app/app/outputs/apk/debug/app-debug.apk" "$SCRIPT_DIR/android/app/build/outputs/apk/debug"
3 changes: 0 additions & 3 deletions testing/scenario_app/build_and_run_android_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,8 @@ fi

if [[ ! -d "$SRC_DIR/out/$FLUTTER_ENGINE" ]]; then
"$GN" --android --unoptimized --android-cpu x64 --runtime-mode debug
"$GN" --unoptimized --runtime-mode debug
fi

autoninja -C "$SRC_DIR/out/$FLUTTER_ENGINE"
autoninja -C "$SRC_DIR/out/host_debug_unopt"

"$SCRIPT_DIR/compile_android_jit.sh" "$SRC_DIR/out/host_debug_unopt" "$SRC_DIR/out/$FLUTTER_ENGINE/clang_x64"
"$SCRIPT_DIR/run_android_tests.sh" "$FLUTTER_ENGINE"
2 changes: 0 additions & 2 deletions testing/scenario_app/build_and_run_ios_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,5 @@ if [ ! -d "$SRC_DIR/out/$FLUTTER_ENGINE" ]; then
fi

autoninja -C "$SRC_DIR/out/$FLUTTER_ENGINE"
autoninja -C "$SRC_DIR/out/host_debug_unopt"

"$SCRIPT_DIR/compile_ios_jit.sh" "$SRC_DIR/out/host_debug_unopt" "$SRC_DIR/out/$FLUTTER_ENGINE/clang_x64"
"$SCRIPT_DIR/run_ios_tests.sh" "$FLUTTER_ENGINE"
Loading