Future toggleSelectedFrame()

in packages/devtools_app/lib/src/performance/performance_controller.dart [359:463]


  Future<void> toggleSelectedFrame(FlutterFrame frame) async {
    if (frame == null || data == null) {
      return;
    }

    _currentFrameBeingSelected = frame;

    // Unselect [frame] if is already selected.
    if (data.selectedFrame == frame) {
      data.selectedFrame = null;
      _selectedFrameNotifier.value = null;
      return;
    }

    data.selectedFrame = frame;
    _selectedFrameNotifier.value = frame;

    // Default to viewing the timeline events flame chart when a new frame is
    // selected.
    _selectedAnalysisTab.value = null;

    if (!offlineController.offlineMode.value) {
      final bool frameBeforeFirstWellFormedFrame =
          firstWellFormedFrameMicros != null &&
              frame.timeFromFrameTiming.start.inMicroseconds <
                  firstWellFormedFrameMicros;
      if (!frame.isWellFormed && !frameBeforeFirstWellFormedFrame) {
        // Only try to pull timeline events for frames that are after the first
        // well formed frame. Timeline events that occurred before this frame will
        // have already fallen out of the buffer.
        await processAvailableEvents();
      }

      if (_currentFrameBeingSelected != frame) return;

      // If the frame is still not well formed after processing all available
      // events, wait a short delay and try to process events again after the
      // VM has been polled one more time.
      if (!frame.isWellFormed && !frameBeforeFirstWellFormedFrame) {
        assert(!_processing.value);
        _processing.value = true;
        await Future.delayed(timelinePollingInterval, () async {
          if (_currentFrameBeingSelected != frame) return;
          await processTraceEvents(allTraceEvents);
          _processing.value = false;
        });
      }

      if (_currentFrameBeingSelected != frame) return;
    }

    // We do not need to pull the CPU profile because we will pull the profile
    // for the entire frame. The order of selecting the timeline event and
    // pulling the CPU profile for the frame (directly below) matters here.
    // If the selected timeline event is null, the event details section will
    // not show the progress bar while we are processing the CPU profile.
    await selectTimelineEvent(
      frame.timelineEventData.uiEvent,
      updateProfiler: false,
    );

    if (_currentFrameBeingSelected != frame) return;

    final storedProfileForFrame = cpuProfilerController.cpuProfileStore
        .lookupProfile(time: frame.timeFromEventFlows);
    if (storedProfileForFrame == null) {
      cpuProfilerController.reset();
      if (!offlineController.offlineMode.value &&
          frame.timeFromEventFlows.isWellFormed) {
        await cpuProfilerController.pullAndProcessProfile(
          startMicros: frame.timeFromEventFlows.start.inMicroseconds,
          extentMicros: frame.timeFromEventFlows.duration.inMicroseconds,
          processId: 'Flutter frame ${frame.id}',
        );
      }
      if (_currentFrameBeingSelected != frame) return;
      data.cpuProfileData = cpuProfilerController.dataNotifier.value;
    } else {
      if (!storedProfileForFrame.processed) {
        await cpuProfilerController.transformer.processData(
          storedProfileForFrame,
          processId: 'Flutter frame ${frame.id} - stored profile ',
        );
      }
      if (_currentFrameBeingSelected != frame) return;
      data.cpuProfileData = storedProfileForFrame;
      cpuProfilerController.loadProcessedData(
        storedProfileForFrame,
        storeAsUserTagNone: true,
      );
    }

    if (debugTimeline) {
      final buf = StringBuffer();
      buf.writeln('UI timeline event for frame ${frame.id}:');
      frame.timelineEventData.uiEvent.format(buf, '  ');
      buf.writeln('\nUI trace for frame ${frame.id}');
      frame.timelineEventData.uiEvent.writeTraceToBuffer(buf);
      buf.writeln('\Raster timeline event frame ${frame.id}:');
      frame.timelineEventData.rasterEvent.format(buf, '  ');
      buf.writeln('\nRaster trace for frame ${frame.id}');
      frame.timelineEventData.rasterEvent.writeTraceToBuffer(buf);
      log(buf.toString());
    }
  }