google / flutter.widgets

https://pub.dev/packages/flutter_widgets
BSD 3-Clause "New" or "Revised" License
1.37k stars 474 forks source link

Crash occurs when using PlatformView and EngineGroup simultaneously #499

Closed tianrp closed 11 months ago

tianrp commented 11 months ago

Problem description

A crash occurred when opening multiple pages containing PlatformView using EngineGroup. Crash information is as follows:

[VERBOSE-3:shared_thread_merger.cc(59)] Check failed: lease_term_ref > 0. lease_term should always be positive when merged, lease_term=0
2023-10-20 14:44:03.206019+0800 Runner[44679:2472818] 
[VERBOSE-2:profiler_metrics_ios.mm(203)] Error retrieving thread information: (os/kern) invalid argument

Steps to reproduce

1.Start an engine using EngineGroup and open a page containing a PlatformView, then remove the PlatformView from the page. 2.Use the same EngineGroup to create a new engine to render a new page containing a PlatformView, which will trigger a crash.

https://github.com/google/flutter.widgets/assets/42142356/9fd02489-4307-4133-bdb8-b5e7887f6c19

Expected behavior

PlatformView should display properly when using EngineGroup.

Actual behavior

A crash occurred.

Environment

[!] Flutter (Channel [user-branch], 3.13.8-0.0.pre.4, on macOS 13.3.1 22E772610a darwin-arm64, locale zh-Hans-CN) ! Flutter version 3.13.8-0.0.pre.4 on channel [user-branch] at Currently on an unknown channel. Run flutter channel to switch to an official channel. If that doesn't fix the issue, reinstall Flutter by following instructions at https://flutter.dev/docs/get-started/install. ! Upstream repository is not a standard remote. Set environment variable "FLUTTER_GIT_URL" to dismiss this error. [✓] Android toolchain - develop for Android devices (Android SDK version 30.0.3) [✓] Xcode - develop for iOS and macOS (Xcode 14.3) [✓] Chrome - develop for the web [✓] Android Studio (version 2022.1) [✓] IntelliJ IDEA Ultimate Edition (version 2020.2.4) [✓] IntelliJ IDEA Community Edition (version 2021.3.3) [✓] VS Code (version 1.82.2) [✓] Connected device (4 available) [✓] Network resources

platform: iOS

Additional details

Cause analysis: After the page removes the PlatformView, SharedThreadMerger will perform an unmerge when the lease count for the corresponding engine decreases to 0. However, after the unmerge, the raster_thread_merger for the engine is not removed from the lease map. When opening the second page, since the page contains a PlatformView, it will trigger a merge again. This causes the first engine to also check if the lease has expired when drawing. Since the raster_thread_merger of the main engine was not removed during the previous unmerge, a situation with a lease count of 0 occurs. Thus, the error check below was triggered:

bool SharedThreadMerger::DecrementLease(RasterThreadMergerId caller) {
  std::scoped_lock lock(mutex_);
  auto entry = lease_term_by_caller_.find(caller);
  bool exist = entry != lease_term_by_caller_.end();
  if (exist) {
    std::atomic_size_t& lease_term_ref = entry->second;
    FML_CHECK(lease_term_ref > 0)
        << "lease_term should always be positive when merged, lease_term="
        << lease_term_ref;
    lease_term_ref--;
  } else {
    FML_LOG(WARNING) << "The caller does not exist when calling "
                        "DecrementLease(), ignored. This may happens after "
                        "caller is erased in UnMergeNowIfLastOne(). caller="
                     << caller;
  }
  if (IsAllLeaseTermsZeroUnSafe()) {
    // Unmerge now because lease_term_ decreased to zero.
    UnMergeNowUnSafe();
    return true;
  }
  return false;
}

Suggested modifications: In DecrementLease, check if the lease count has been reduced to 0 for a caller. If so, remove the caller from lease_term_bycaller. However, it's unclear whether this change might have any side effects.