[Android] add HCPP platform views benchmark and integration test. (#163018)

Adds a benchmark and integration test of HCPP using a Pixel 7.
This commit is contained in:
Jonah Williams 2025-02-10 18:12:49 -08:00 committed by GitHub
parent e8a0fbbe69
commit 6291a51ce2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 251 additions and 2 deletions

View File

@ -3210,6 +3210,16 @@ targets:
["devicelab", "android", "linux", "pixel", "7pro"]
task_name: platform_views_scroll_perf_impeller__timeline_summary
- name: Linux_pixel_7pro platform_views_hcpp_scroll_perf__timeline_summary
recipe: devicelab/devicelab_drone
presubmit: false
bringup: true
timeout: 60
properties:
tags: >
["devicelab", "android", "linux", "pixel", "7pro"]
task_name: platform_views_hcpp_scroll_perf__timeline_summary
# linux mokey benchmark
- name: Linux_mokey platform_view__start_up
recipe: devicelab/devicelab_drone

View File

@ -108,6 +108,7 @@
/dev/devicelab/bin/tasks/complex_layout_scroll_perf_impeller__timeline_summary.dart @jonahwilliams @flutter/engine
/dev/devicelab/bin/tasks/complex_layout_scroll_perf_impeller_gles__timeline_summary.dart @jonahwilliams @flutter/engine
/dev/devicelab/bin/tasks/rrect_blur_perf__timeline_summary.dart @gaaclarke @flutter/engine
/dev/devicelab/bin/tasks/platform_views_hcpp_scroll_perf__timeline_summary.dart @jonahwilliams @flutter/engine
## Windows Android DeviceLab tests
/dev/devicelab/bin/tasks/basic_material_app_win__compile.dart @bkonyi @flutter/tool

View File

@ -0,0 +1,126 @@
// Copyright 2014 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 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
void main() {
runApp(const PlatformViewApp());
}
class PlatformViewApp extends StatefulWidget {
const PlatformViewApp({super.key});
@override
PlatformViewAppState createState() => PlatformViewAppState();
}
class PlatformViewAppState extends State<PlatformViewApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.light(),
title: 'Advanced Layout',
home: const PlatformViewLayout(),
);
}
}
class PlatformViewLayout extends StatelessWidget {
const PlatformViewLayout({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Platform View Scrolling Layout')),
body: ListView.builder(
key: const Key('platform-views-scroll'), // This key is used by the driver test.
itemCount: 200,
itemBuilder: (BuildContext context, int index) {
return Padding(
padding: const EdgeInsets.all(5.0),
child: Material(
elevation: (index % 5 + 1).toDouble(),
color: Colors.white,
child: const Stack(children: <Widget>[_AndroidPlatformView(), RotationContainer()]),
),
);
},
),
);
}
}
final class _AndroidPlatformView extends StatelessWidget {
const _AndroidPlatformView();
static const String viewType = 'benchmarks/platform_views_layout/DummyPlatformView';
@override
Widget build(BuildContext context) {
return SizedBox(
width: 400,
height: 200,
child: PlatformViewLink(
viewType: viewType,
surfaceFactory: (BuildContext context, PlatformViewController controller) {
return AndroidViewSurface(
controller: controller as AndroidViewController,
gestureRecognizers: const <Factory<OneSequenceGestureRecognizer>>{},
hitTestBehavior: PlatformViewHitTestBehavior.opaque,
);
},
onCreatePlatformView: (PlatformViewCreationParams params) {
return PlatformViewsService.initHybridAndroidView(
id: params.id,
viewType: viewType,
layoutDirection: TextDirection.ltr,
creationParamsCodec: const StandardMessageCodec(),
)
..addOnPlatformViewCreatedListener(params.onPlatformViewCreated)
..create();
},
),
);
}
}
class RotationContainer extends StatefulWidget {
const RotationContainer({super.key});
@override
State<RotationContainer> createState() => _RotationContainerState();
}
class _RotationContainerState extends State<RotationContainer> with SingleTickerProviderStateMixin {
late AnimationController _rotationController;
@override
void initState() {
super.initState();
_rotationController = AnimationController(
vsync: this,
duration: const Duration(seconds: 1),
value: 1,
);
_rotationController.repeat();
}
@override
void dispose() {
_rotationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return RotationTransition(
turns: Tween<double>(begin: 0.0, end: 1.0).animate(_rotationController),
child: Container(color: Colors.purple, width: 50.0, height: 50.0),
);
}
}

View File

@ -0,0 +1,13 @@
// Copyright 2014 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 'package:flutter/widgets.dart';
import 'package:flutter_driver/driver_extension.dart';
import 'package:platform_views_layout/main_hcpp.dart' as app;
void main() {
enableFlutterDriverExtension();
runApp(const app.PlatformViewApp());
}

View File

@ -0,0 +1,61 @@
// Copyright 2014 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 'package:flutter_driver/flutter_driver.dart';
import 'package:test/test.dart' hide TypeMatcher, isInstanceOf;
void main() {
group('scrolling performance test', () {
late FlutterDriver driver;
setUpAll(() async {
driver = await FlutterDriver.connect();
await driver.waitUntilFirstFrameRasterized();
});
tearDownAll(() async {
driver.close();
});
Future<void> testScrollPerf(String listKey, String summaryName) async {
// The slight initial delay avoids starting the timing during a
// period of increased load on the device. Without this delay, the
// benchmark has greater noise.
// See: https://github.com/flutter/flutter/issues/19434
await Future<void>.delayed(const Duration(milliseconds: 250));
await driver.forceGC();
final Timeline timeline = await driver.traceAction(() async {
// Find the scrollable stock list
final SerializableFinder list = find.byValueKey(listKey);
for (int j = 0; j < 5; j += 1) {
// Scroll down
for (int i = 0; i < 5; i += 1) {
await driver.scroll(list, 0.0, -300.0, const Duration(milliseconds: 300));
await Future<void>.delayed(const Duration(milliseconds: 500));
}
// Scroll up
for (int i = 0; i < 5; i += 1) {
await driver.scroll(list, 0.0, 300.0, const Duration(milliseconds: 300));
await Future<void>.delayed(const Duration(milliseconds: 500));
}
}
});
final TimelineSummary summary = TimelineSummary.summarize(timeline);
await summary.writeTimelineToFile(summaryName, pretty: true);
}
test('platform_views_scroll_perf', () async {
// Disable frame sync, since there are ongoing animations.
await driver.runUnsynchronized(() async {
await testScrollPerf('platform-views-scroll', 'platform_views_hcpp_scroll_perf');
});
}, timeout: Timeout.none);
});
}

View File

@ -0,0 +1,12 @@
// Copyright 2014 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 'package:flutter_devicelab/framework/devices.dart';
import 'package:flutter_devicelab/framework/framework.dart';
import 'package:flutter_devicelab/tasks/perf_tests.dart';
Future<void> main() async {
deviceOperatingSystem = DeviceOperatingSystem.android;
await task(createAndroidHCPPScrollPerfTest());
}

View File

@ -107,6 +107,19 @@ TaskFunction createAndroidTextureScrollPerfTest({bool? enableImpeller}) {
).run;
}
TaskFunction createAndroidHCPPScrollPerfTest() {
return PerfTest(
'${flutterDirectory.path}/dev/benchmarks/platform_views_layout',
'test_driver/scroll_perf_hcpp.dart',
'platform_views_hcpp_scroll_perf',
testDriver: 'test_driver/scroll_perf_hcpp_test.dart',
needsFullTimeline: false,
enableImpeller: true,
enableSurfaceControl: true,
enableMergedPlatformThread: true,
).run;
}
TaskFunction createAndroidViewScrollPerfTest() {
return PerfTest(
'${flutterDirectory.path}/dev/benchmarks/platform_views_layout_hybrid_composition',
@ -847,6 +860,13 @@ void _addMetadataToManifest(String testDirectory, List<(String, String)> keyPair
file.writeAsStringSync(xmlDoc.toXmlString(pretty: true, indent: ' '));
}
void _addSurfaceControlSupportToManifest(String testDirectory) {
final List<(String, String)> keyPairs = <(String, String)>[
('io.flutter.embedding.android.EnableSurfaceControl', 'true'),
];
_addMetadataToManifest(testDirectory, keyPairs);
}
void _addMergedPlatformThreadSupportToManifest(String testDirectory) {
final List<(String, String)> keyPairs = <(String, String)>[
('io.flutter.embedding.android.EnableMergedPlatformUIThread', 'true'),
@ -1204,6 +1224,7 @@ class PerfTest {
this.forceOpenGLES,
this.disablePartialRepaint = false,
this.enableMergedPlatformThread = false,
this.enableSurfaceControl = false,
this.createPlatforms = const <String>[],
}) : _resultFilename = resultFilename;
@ -1225,6 +1246,7 @@ class PerfTest {
this.forceOpenGLES,
this.disablePartialRepaint = false,
this.enableMergedPlatformThread = false,
this.enableSurfaceControl = false,
this.createPlatforms = const <String>[],
}) : saveTraceFile = false,
timelineFileName = null,
@ -1281,6 +1303,9 @@ class PerfTest {
/// Whether the UI thread should be the platform thread.
final bool enableMergedPlatformThread;
/// Whether to enable SurfaceControl swapchain.
final bool enableSurfaceControl;
/// Number of seconds to time out the test after, allowing debug callbacks to run.
final int? timeoutSeconds;
@ -1376,6 +1401,9 @@ class PerfTest {
if (enableMergedPlatformThread) {
_addMergedPlatformThreadSupportToManifest(testDirectory);
}
if (enableSurfaceControl) {
_addSurfaceControlSupportToManifest(testDirectory);
}
}
if (disablePartialRepaint || enableMergedPlatformThread) {
changedPlist = true;
@ -1450,8 +1478,6 @@ class PerfTest {
recordGPU = false;
}
// TODO(liyuqian): Remove isAndroid restriction once
// https://github.com/flutter/flutter/issues/61567 is fixed.
final bool isAndroid = deviceOperatingSystem == DeviceOperatingSystem.android;
return TaskResult.success(
data,