captureMemProfile function
Captures a full allocation profile and writes it to input.outputPath.
Single-isolate: returns MemProfileSuccess with the actual file path.
Multi-isolate (allIsolates: true): writes one file per isolate using the
pattern <stem>_<isolateName>.json; returns MemProfileMultiSuccess.
Never throws; all error conditions are represented as sealed result cases.
Implementation
Future<MemProfileResult> captureMemProfile(MemProfileInput input) async {
try {
final List<String> targetIds;
if (input.allIsolates) {
targetIds = await findAllIsolateIds();
if (targetIds.isEmpty) return const MemProfileError('No isolates found in running VM');
} else if (input.isolateId != null) {
final allIds = await findAllIsolateIds();
if (!allIds.contains(input.isolateId)) return MemProfileIsolateNotFound(input.isolateId!);
targetIds = [input.isolateId!];
} else {
final id = await findFlutterIsolateId() ?? (await findAllIsolateIds()).firstOrNull;
if (id == null) return const MemProfileError('No isolates found in running VM');
targetIds = [id];
}
if (targetIds.length == 1) return _captureIsolateProfile(targetIds.first, input.outputPath);
// Multi-isolate: one file per isolate, name resolved once and reused for
// both the filename and the MemProfileSuccess inside _captureIsolateProfile.
var totalClasses = 0;
final writtenPaths = <String>[];
final writtenNames = <String>[];
for (final id in targetIds) {
final name = await _isolateName(id);
final path = '${_stripExtension(input.outputPath)}_${_safeFileName(name)}.json';
final r = await _captureIsolateProfile(id, path, resolvedName: name);
if (r is MemProfileSuccess) {
totalClasses += r.classCount;
writtenPaths.add(r.outputPath);
writtenNames.add(r.isolateName);
} else {
return r; // Propagate first error.
}
}
return MemProfileMultiSuccess(outputPaths: writtenPaths, isolateNames: writtenNames, classCount: totalClasses);
} on AppDiedException catch (e) {
return MemProfileAppDied(logLines: e.logLines, reason: e.reason);
} catch (e) {
return MemProfileError(e.toString());
}
}