Skip to content
This repository has been archived by the owner on Feb 25, 2025. It is now read-only.

Add Windows AutomationId #53476

Closed
wants to merge 16 commits into from
Closed
Show file tree
Hide file tree
Changes from 15 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
2 changes: 1 addition & 1 deletion DEPS
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ vars = {
# Dart is: https://github.com/dart-lang/sdk/blob/main/DEPS
# You can use //tools/dart/create_updated_flutter_deps.py to produce
# updated revision list of existing dependencies.
'dart_revision': 'bb65648e20e29abc47acf3dd984518d29fd625c3',
'dart_revision': 'b0e7f171c7c9ab82944ffd6918b80a0df36e0549',

# WARNING: DO NOT EDIT MANUALLY
# The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py
Expand Down
2 changes: 1 addition & 1 deletion ci/licenses_golden/licenses_dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Signature: 436d820942d64c56e10183515883c9b6
Signature: 4f1220293023cdec5a6af5bd69bcb0ab

====================================================================================================
LIBRARY: dart
Expand Down
3 changes: 3 additions & 0 deletions common/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,9 @@ struct Settings {
bool enable_impeller = false;
#endif

// Log a warning during shell initialization if Impeller is not enabled.
bool warn_on_impeller_opt_out = false;

// The selected Android rendering API.
AndroidRenderingAPI android_rendering_api =
AndroidRenderingAPI::kSkiaOpenGLES;
Expand Down
3 changes: 3 additions & 0 deletions impeller/tessellator/tessellator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,9 @@ std::vector<Point> Tessellator::TessellateConvex(const Path& path,
[this](Path::Polyline::PointBufferPtr point_buffer) {
point_buffer_ = std::move(point_buffer);
});
if (polyline.points->size() == 0) {
return output;
}

output.reserve(polyline.points->size() +
(4 * (polyline.contours.size() - 1)));
Expand Down
13 changes: 13 additions & 0 deletions impeller/tessellator/tessellator_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,19 @@ TEST(TessellatorTest, FilledRoundRectTessellationVertices) {
Rect::MakeXYWH(5000, 10000, 2000, 3000), {50, 70});
}

TEST(TessellatorTest, EarlyReturnEmptyConvexShape) {
// This path is not technically empty (it has a size in one dimension),
// but is otherwise completely flat.
auto tessellator = std::make_shared<Tessellator>();
PathBuilder builder;
builder.MoveTo({0, 0});
builder.MoveTo({10, 10}, /*relative=*/true);

auto points = tessellator->TessellateConvex(builder.TakePath(), 3.0);

EXPECT_TRUE(points.empty());
}

#if !NDEBUG
TEST(TessellatorTest, ChecksConcurrentPolylineUsage) {
auto tessellator = std::make_shared<Tessellator>();
Expand Down
2 changes: 2 additions & 0 deletions impeller/toolkit/android/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ source_set("unittests_lib") {
":unittests_fixtures",
"//flutter/testing",
]

defines = [ "TESTING" ]
}

executable("unittests") {
Expand Down
2 changes: 1 addition & 1 deletion impeller/toolkit/android/hardware_buffer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ std::optional<uint64_t> HardwareBuffer::GetSystemUniqueID() const {
std::optional<uint64_t> HardwareBuffer::GetSystemUniqueID(
AHardwareBuffer* buffer) {
if (!GetProcTable().AHardwareBuffer_getId) {
return false;
return std::nullopt;
}
uint64_t out_id = 0u;
if (GetProcTable().AHardwareBuffer_getId(buffer, &out_id) != 0) {
Expand Down
5 changes: 5 additions & 0 deletions impeller/toolkit/android/proc_table.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ const ProcTable& GetProcTable() {
return gProcTable;
}

// Only used by tests.
ProcTable& GetMutableProcTable() {
return const_cast<ProcTable&>(GetProcTable());
}

template <class T>
void ResolveAndroidProc(
AndroidProc<T>& proc,
Expand Down
4 changes: 4 additions & 0 deletions impeller/toolkit/android/proc_table.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@ struct ProcTable {

const ProcTable& GetProcTable();

#ifdef TESTING
ProcTable& GetMutableProcTable();
#endif

} // namespace impeller::android

#endif // FLUTTER_IMPELLER_TOOLKIT_ANDROID_PROC_TABLE_H_
17 changes: 17 additions & 0 deletions impeller/toolkit/android/toolkit_android_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,18 @@

namespace impeller::android::testing {

#define DISABLE_ANDROID_PROC(name) \
struct Disable##name { \
Disable##name() { \
real_proc = GetMutableProcTable().name.proc; \
GetMutableProcTable().name.proc = nullptr; \
} \
~Disable##name() { \
GetMutableProcTable().name.proc = real_proc; \
} \
decltype(name)* real_proc; \
} disable##name;

TEST(ToolkitAndroidTest, CanCreateProcTable) {
ProcTable proc_table;
ASSERT_TRUE(proc_table.IsValid());
Expand Down Expand Up @@ -49,6 +61,11 @@ TEST(ToolkitAndroidTest, CanGetHardwareBufferIDs) {
ASSERT_TRUE(buffer.GetSystemUniqueID().has_value());
}

TEST(ToolkitAndroidTest, HardwareBufferNullIDIfAPIUnavailable) {
DISABLE_ANDROID_PROC(AHardwareBuffer_getId);
ASSERT_FALSE(HardwareBuffer::GetSystemUniqueID(nullptr).has_value());
}

TEST(ToolkitAndroidTest, CanDescribeHardwareBufferHandles) {
if (!HardwareBuffer::IsAvailableOnPlatform()) {
GTEST_SKIP() << "Hardware buffers are not supported on this platform.";
Expand Down
8 changes: 8 additions & 0 deletions shell/common/shell.cc
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,14 @@ Shell::Shell(DartVMRef vm,
weak_factory_(this) {
FML_CHECK(!settings.enable_software_rendering || !settings.enable_impeller)
<< "Software rendering is incompatible with Impeller.";
if (!settings.enable_impeller && settings.warn_on_impeller_opt_out) {
FML_LOG(IMPORTANT)
<< "[Action Required] The application opted out of Impeller by either "
"using the --no-enable-impeller flag or FLTEnableImpeller=false "
"plist flag. This option is going to go away in an upcoming Flutter "
"release. Remove the explicit opt-out. If you need to opt-out, "
"report a bug describing the issue.";
}
FML_CHECK(vm_) << "Must have access to VM to create a shell.";
FML_DCHECK(task_runners_.IsValid());
FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
Expand Down
24 changes: 23 additions & 1 deletion shell/common/shell_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <strstream>
#define FML_USED_ON_EMBEDDER

#include <algorithm>
#include <chrono>
#include <ctime>
#include <future>
#include <memory>
#include <strstream>
#include <thread>
#include <utility>
#include <vector>
Expand Down Expand Up @@ -4689,6 +4689,28 @@ TEST_F(ShellTest, RuntimeStageBackendWithImpeller) {
}
#endif // IMPELLER_SUPPORTS_RENDERING

TEST_F(ShellTest, WillLogWarningWhenImpellerIsOptedOut) {
#if !IMPELLER_SUPPORTS_RENDERING
GTEST_SKIP() << "This platform doesn't support Impeller.";
#endif
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
Settings settings = CreateSettingsForFixture();
settings.enable_impeller = false;
settings.warn_on_impeller_opt_out = true;
// Log captures are thread specific. Just put the shell in single threaded
// configuration.
const auto& runner = fml::MessageLoop::GetCurrent().GetTaskRunner();
TaskRunners task_runners("test", runner, runner, runner, runner);
std::ostringstream stream;
fml::LogMessage::CaptureNextLog(&stream);
std::unique_ptr<Shell> shell = CreateShell(settings, task_runners);
ASSERT_TRUE(stream.str().find(
"[Action Required] The application opted out of Impeller") !=
std::string::npos);
ASSERT_TRUE(shell);
DestroyShell(std::move(shell), task_runners);
}

} // namespace testing
} // namespace flutter

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,7 @@ void onPostResume() {
ensureAlive();
if (flutterEngine != null) {
updateSystemUiOverlays();
flutterEngine.getPlatformViewsController().onResume();
} else {
Log.w(TAG, "onPostResume() invoked before FlutterFragment was attached to an Activity.");
}
Expand Down Expand Up @@ -1020,6 +1021,7 @@ void onTrimMemory(int level) {
flutterEngine.getSystemChannel().sendMemoryPressureWarning();
}
flutterEngine.getRenderer().onTrimMemory(level);
flutterEngine.getPlatformViewsController().onTrimMemory(level);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,12 @@

package io.flutter.embedding.engine.loader;

import static io.flutter.Build.API_LEVELS;

import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.hardware.display.DisplayManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
Expand Down Expand Up @@ -237,13 +234,6 @@ public InitResult call() {
}
}

private static boolean areValidationLayersOnByDefault() {
if (BuildConfig.DEBUG && Build.VERSION.SDK_INT >= API_LEVELS.API_26) {
return Build.SUPPORTED_ABIS[0].equals("arm64-v8a");
}
return false;
}

/**
* Blocks until initialization of the native system has completed.
*
Expand Down Expand Up @@ -353,8 +343,7 @@ public void ensureInitializationComplete(
if (metaData.getBoolean(ENABLE_IMPELLER_META_DATA_KEY, false)) {
shellArgs.add("--enable-impeller");
}
if (metaData.getBoolean(
ENABLE_VULKAN_VALIDATION_META_DATA_KEY, areValidationLayersOnByDefault())) {
if (metaData.getBoolean(ENABLE_VULKAN_VALIDATION_META_DATA_KEY, false)) {
shellArgs.add("--enable-vulkan-validation");
}
if (metaData.getBoolean(IMPELLER_OPENGL_GPU_TRACING_DATA_KEY, false)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import static io.flutter.Build.API_LEVELS;

import android.annotation.TargetApi;
import android.content.ComponentCallbacks2;
import android.graphics.Bitmap;
import android.graphics.ImageFormat;
import android.graphics.Rect;
Expand All @@ -17,6 +18,7 @@
import android.media.ImageReader;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.view.Surface;
import androidx.annotation.Keep;
import androidx.annotation.NonNull;
Expand All @@ -28,11 +30,11 @@
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.nio.ByteBuffer;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
Expand Down Expand Up @@ -414,12 +416,18 @@ final class ImageReaderSurfaceProducer
// Flip when debugging to see verbose logs.
private static final boolean VERBOSE_LOGS = false;

// We must always cleanup on memory pressure on Android 14 due to a bug in Android.
// It is safe to do on all versions so we unconditionally have this set to true.
private static final boolean CLEANUP_ON_MEMORY_PRESSURE = true;

private final long id;

private boolean released;
// Will be true in tests and on Android API < 33.
private boolean ignoringFence = false;

private boolean trimOnMemoryPressure = CLEANUP_ON_MEMORY_PRESSURE;

// The requested width and height are updated by setSize.
private int requestedWidth = 1;
private int requestedHeight = 1;
Expand All @@ -433,10 +441,11 @@ final class ImageReaderSurfaceProducer
private long lastDequeueTime = 0;
private long lastQueueTime = 0;
private long lastScheduleTime = 0;
private int numTrims = 0;

private Object lock = new Object();
// REQUIRED: The following fields must only be accessed when lock is held.
private final LinkedList<PerImageReader> imageReaderQueue = new LinkedList<PerImageReader>();
private final ArrayDeque<PerImageReader> imageReaderQueue = new ArrayDeque<PerImageReader>();
private final HashMap<ImageReader, PerImageReader> perImageReaders =
new HashMap<ImageReader, PerImageReader>();
private PerImage lastDequeuedImage = null;
Expand All @@ -456,7 +465,7 @@ public PerImage(Image image, long queuedTime) {
/** Internal class: state held per ImageReader. */
private class PerImageReader {
public final ImageReader reader;
private final LinkedList<PerImage> imageQueue = new LinkedList<PerImage>();
private final ArrayDeque<PerImage> imageQueue = new ArrayDeque<PerImage>();
private boolean closed = false;

private final ImageReader.OnImageAvailableListener onImageAvailableListener =
Expand All @@ -479,7 +488,8 @@ private class PerImageReader {

public PerImageReader(ImageReader reader) {
this.reader = reader;
reader.setOnImageAvailableListener(onImageAvailableListener, new Handler());
reader.setOnImageAvailableListener(
onImageAvailableListener, new Handler(Looper.getMainLooper()));
}

PerImage queueImage(Image image) {
Expand Down Expand Up @@ -649,6 +659,15 @@ PerImage dequeueImage() {

@Override
public void onTrimMemory(int level) {
if (!trimOnMemoryPressure) {
return;
}
if (level < ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) {
return;
}
synchronized (lock) {
numTrims++;
}
cleanup();
createNewReader = true;
}
Expand Down Expand Up @@ -865,6 +884,13 @@ public int numImageReaders() {
}
}

@VisibleForTesting
public int numTrims() {
synchronized (lock) {
return numTrims;
}
}

@VisibleForTesting
public int numImages() {
int r = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import static io.flutter.Build.API_LEVELS;

import android.annotation.TargetApi;
import android.content.ComponentCallbacks2;
import android.content.Context;
import android.content.MutableContextWrapper;
import android.os.Build;
Expand Down Expand Up @@ -1053,6 +1054,24 @@ private void diposeAllViews() {
}
}

// Invoked when the Android system is requesting we reduce memory usage.
public void onTrimMemory(int level) {
if (level < ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) {
return;
}
for (VirtualDisplayController vdc : vdControllers.values()) {
vdc.clearSurface();
}
}

// Called after the application has been resumed.
// This is where we undo whatever may have been done in onTrimMemory.
public void onResume() {
for (VirtualDisplayController vdc : vdControllers.values()) {
vdc.resetSurface();
}
}

/**
* Disposes a single
*
Expand Down
Loading