未验证 提交 aea0d7a6 编写于 作者: D Dan Field 提交者: GitHub

test scenario_app on CI (#10065)

上级 67524615
......@@ -16,10 +16,11 @@ task:
FLUTTER_ENGINE: "/tmp/clean_engine/src"
FRAMEWORK_PATH: "/tmp/master_framework"
PATH: "$FLUTTER_ENGINE/third_party/dart/tools/sdks/dart-sdk/bin:$DEPOT_TOOLS:$PATH"
USE_ANDROID: "False"
setup_script: |
git clone --depth 1 https://chromium.googlesource.com/chromium/tools/depot_tools.git $DEPOT_TOOLS
mkdir -p $ENGINE_PATH/src
echo 'solutions = [{"managed": False,"name": "src/flutter","url": "git@github.com:flutter/engine.git","deps_file": "DEPS", "custom_vars": {"download_android_deps" : False, "download_windows_deps" : False,},},]' > $ENGINE_PATH/.gclient
echo 'solutions = [{"managed": False,"name": "src/flutter","url": "git@github.com:flutter/engine.git","deps_file": "DEPS", "custom_vars": {"download_android_deps" : ' $USE_ANDROID ', "download_windows_deps" : False,},},]' > $ENGINE_PATH/.gclient
cd $ENGINE_PATH/src
rm -rf flutter
rm -rf out
......@@ -62,10 +63,9 @@ task:
cd $ENGINE_PATH/src
./flutter/testing/run_tests.sh host_release
- name: build_and_test_android_unopt_debug
get_android_sdk_script: |
echo 'solutions = [{"managed": False,"name": "src/flutter","url": "git@github.com:flutter/engine.git","deps_file": "DEPS", "custom_vars": {"download_windows_deps" : False,},},]' > $ENGINE_PATH/.gclient
cd $ENGINE_PATH/src
gclient sync
env:
USE_ANDROID: "True"
ANDROID_HOME: $ENGINE_PATH/src/third_party/android_tools/sdk
lint_host_script: |
cd $ENGINE_PATH/src/flutter/tools/android_lint
$ENGINE_PATH/src/third_party/dart/tools/sdks/dart-sdk/bin/pub get
......@@ -77,6 +77,27 @@ task:
mkdir javadoc_tmp
./flutter/tools/gen_javadoc.py --out-dir javadoc_tmp
test_android_script: cd $ENGINE_PATH/src && python ./flutter/testing/run_tests.py --type=java
- name: build_and_test_android_profile_app
env:
USE_ANDROID: "True"
ANDROID_HOME: $ENGINE_PATH/src/third_party/android_tools/sdk
GCLOUD_FIREBASE_TESTLAB_KEY: ENCRYPTED[3be31b3547bea4e70cff1d46f9a11ad8c6b42c1982a3964d81e437dee2035f674f12e130bde231352421d8de2029c55f]
compile_host_script: |
cd $ENGINE_PATH/src
./flutter/tools/gn --runtime-mode=profile --no-lto
autoninja -C out/host_profile
compile_android_script: |
cd $ENGINE_PATH/src
./flutter/tools/gn --android --runtime-mode=profile --no-lto --android-cpu=arm64
ninja -C out/android_profile_arm64
compile_app_script: |
cd $ENGINE_PATH/src/flutter/testing/scenario_app
./compile_android_aot.sh "$ENGINE_PATH/src/out/host_profile" "$ENGINE_PATH/src/out/android_profile_arm64/clang_x64"
cd android
./gradlew assembleDebug
firebase_test_script: |
cd $ENGINE_PATH/src
./flutter/ci/firebase_testlab.sh "$ENGINE_PATH/src/flutter/testing/scenario_app/android/app/build/outputs/apk/debug/app-debug.apk"
- name: format_and_dart_test
format_script: |
cd $ENGINE_PATH/src/flutter
......
......@@ -4,7 +4,7 @@ ENV DEPOT_TOOLS_PATH $HOME/depot_tools
ENV ENGINE_PATH $HOME/engine
RUN apt-get update
RUN apt-get install -y git wget curl unzip python lsb-release sudo
RUN apt-get install -y git wget curl unzip python lsb-release sudo apt-transport-https
RUN git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git $DEPOT_TOOLS_PATH
ENV PATH $PATH:$DEPOT_TOOLS_PATH
......@@ -18,3 +18,14 @@ WORKDIR $ENGINE_PATH/src
RUN ./build/install-build-deps.sh --no-prompt
RUN ./build/install-build-deps-android.sh --no-prompt
RUN ./flutter/build/install-build-deps-linux-desktop.sh
# Add repo for gcloud sdk and install it
RUN echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" | \
tee -a /etc/apt/sources.list.d/google-cloud-sdk.list
RUN curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | \
apt-key --keyring /usr/share/keyrings/cloud.google.gpg add -
RUN apt-get update && apt-get install -y google-cloud-sdk && \
gcloud config set core/disable_usage_reporting true && \
gcloud config set component_manager/disable_update_check true
#!/bin/bash
set -e
GIT_REVISION=$(git rev-parse HEAD)
if [[ ! -f $1 ]]; then
echo "File $1 not found."
exit -1
fi
# New contributors will not have permissions to run this test - they won't be
# able to access the service account information. We should just mark the test
# as passed - it will run fine on post submit, where it will still catch
# failures.
# We can also still make sure that building a release app bundle still works.
if [[ $GCLOUD_FIREBASE_TESTLAB_KEY == ENCRYPTED* ]]; then
echo "This user does not have permission to run this test."
exit 0
fi
echo $GCLOUD_FIREBASE_TESTLAB_KEY > ${HOME}/gcloud-service-key.json
gcloud auth activate-service-account --key-file=${HOME}/gcloud-service-key.json
gcloud --quiet config set project flutter-infra
# Run the test.
# game-loop tests are meant for OpenGL apps.
# This type of test will give the application a handle to a file, and
# we'll write the timeline JSON to that file.
# See https://firebase.google.com/docs/test-lab/android/game-loop
gcloud firebase test android run \
--type game-loop \
--app $1 \
--timeout 2m \
--results-bucket=gs://flutter_firebase_testlab \
--results-dir=engine_scenario_test/$GIT_REVISION/$CIRRUS_BUILD_ID
......@@ -27,6 +27,7 @@ dependencies {
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
implementation 'com.android.support:design:28.0.0'
implementation 'android.arch.lifecycle:common-java8:1.1.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
......
......@@ -2,7 +2,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="dev.flutter.scenarios">
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:name="io.flutter.app.FlutterApplication"
android:allowBackup="true"
......@@ -17,6 +16,11 @@
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="com.google.intent.action.TEST_LOOP"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="application/javascript"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
......
package dev.flutter.scenarios;
import android.Manifest;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.NonNull;
import io.flutter.app.FlutterActivity;
import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import io.flutter.Log;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.android.FlutterFragment;
import io.flutter.embedding.android.FlutterView;
import io.flutter.embedding.engine.FlutterShellArgs;
import io.flutter.embedding.engine.renderer.OnFirstFrameRenderedListener;
import io.flutter.plugin.common.BasicMessageChannel;
import io.flutter.plugin.common.BinaryCodec;
public class MainActivity extends FlutterActivity implements OnFirstFrameRenderedListener {
final static String TAG = "Scenarios";
public class MainActivity extends FlutterActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Intent launchIntent = getIntent();
if ("com.google.intent.action.TEST_LOOP".equals(launchIntent.getAction())) {
if(Build.VERSION.SDK_INT > 22){
requestPermissions(new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
}
// Run for one minute, get the timeline data, write it, and finish.
final Uri logFileUri = launchIntent.getData();
new Handler().postDelayed(() -> writeTimelineData(logFileUri), 20000);
}
}
public void onFirstFrameRendered() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
reportFullyDrawn();
}
}
private FlutterShellArgs getFlutterShellArgs() {
FlutterShellArgs args = FlutterShellArgs.fromIntent(getIntent());
args.add(FlutterShellArgs.ARG_TRACE_STARTUP);
args.add(FlutterShellArgs.ARG_ENABLE_DART_PROFILING);
args.add(FlutterShellArgs.ARG_VERBOSE_LOGGING);
return args;
}
@Override
@NonNull
protected FlutterFragment createFlutterFragment() {
return new FlutterFragment.Builder()
.dartEntrypoint(getDartEntrypoint())
.initialRoute(getInitialRoute())
.appBundlePath(getAppBundlePath())
.flutterShellArgs(getFlutterShellArgs())
.renderMode(FlutterView.RenderMode.surface)
.transparencyMode(FlutterView.TransparencyMode.opaque)
.shouldAttachEngineToActivity(true)
.build();
}
private void writeTimelineData(Uri logFile) {
if (logFile == null) {
throw new IllegalArgumentException();
}
if (getFlutterEngine() == null) {
Log.e(TAG, "Could not write timeline data - no engine.");
return;
}
final BasicMessageChannel<ByteBuffer> channel = new BasicMessageChannel<>(
getFlutterEngine().getDartExecutor(), "write_timeline", BinaryCodec.INSTANCE);
channel.send(null, (ByteBuffer reply) -> {
try {
final FileDescriptor fd = getContentResolver()
.openAssetFileDescriptor(logFile, "w").getFileDescriptor();
final FileOutputStream outputStream = new FileOutputStream(fd);
outputStream.write(reply.array());
outputStream.close();
} catch (IOException ex) {
Log.e(TAG, "Could not write timeline file: " + ex.toString());
}
finish();
});
}
}
......@@ -42,6 +42,7 @@ echo "Compiling ELF Shared Library..."
"$DEVICE_TOOLS/gen_snapshot" --deterministic --snapshot_kind=app-aot-elf --elf="$OUTDIR/libapp.so" --strip "$OUTDIR/app.dill"
mkdir -p "android/app/src/main/jniLibs/arm64-v8a"
mkdir -p "android/app/libs"
cp "$OUTDIR/libapp.so" "android/app/src/main/jniLibs/arm64-v8a/"
cp "$DEVICE_TOOLS/../flutter.jar" "android/app/libs/"
......
......@@ -3,6 +3,9 @@
// found in the LICENSE file.
import 'dart:convert';
import 'dart:developer' as developer;
import 'dart:io';
import 'dart:isolate';
import 'dart:typed_data';
import 'dart:ui';
......@@ -27,7 +30,7 @@ void main() {
window.sendPlatformMessage('scenario_status', data, null);
}
void _handlePlatformMessage(String name, ByteData data, PlatformMessageResponseCallback callback) {
Future<void> _handlePlatformMessage(String name, ByteData data, PlatformMessageResponseCallback callback) async {
if (name == 'set_scenario' && data != null) {
final String scenarioName = utf8.decode(data.buffer.asUint8List());
final Scenario candidateScenario = _scenarios[scenarioName];
......@@ -40,9 +43,41 @@ void _handlePlatformMessage(String name, ByteData data, PlatformMessageResponseC
data.setUint8(0, candidateScenario == null ? 0 : 1);
callback(data);
}
} else if (name == 'write_timeline') {
final String timelineData = await _getTimelineData();
callback(Uint8List.fromList(utf8.encode(timelineData)).buffer.asByteData());
}
}
Future<String> _getTimelineData() async {
final String isolateId = developer.Service.getIsolateID(Isolate.current);
final developer.ServiceProtocolInfo info = await developer.Service.getInfo();
final Uri cpuProfileTimelineUri = info.serverUri.resolve(
'_getCpuProfileTimeline?tags=None&isolateId=$isolateId',
);
final Uri vmServiceTimelineUri = info.serverUri.resolve('getVMTimeline');
final Map<String, dynamic> cpuTimelineJson = await _getJson(cpuProfileTimelineUri);
final Map<String, dynamic> vmServiceTimelineJson = await _getJson(vmServiceTimelineUri);
final Map<String, dynamic> cpuResult = cpuTimelineJson['result'].cast<String, dynamic>();
final Map<String, dynamic> vmServiceResult = vmServiceTimelineJson['result'].cast<String, dynamic>();
return json.encode(<String, dynamic>{
'stackFrames': cpuResult['stackFrames'],
'traceEvents': <dynamic>[...cpuResult['traceEvents'], ...vmServiceResult['traceEvents']],
});
}
Future<Map<String, dynamic>> _getJson(Uri uri) async {
final HttpClient client = HttpClient();
final HttpClientRequest request = await client.getUrl(uri);
final HttpClientResponse response = await request.close();
if (response.statusCode > 299) {
return null;
}
final String data = await utf8.decodeStream(response);
return json.decode(data);
}
void _onBeginFrame(Duration duration) {
_currentScenario.onBeginFrame(duration);
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册