Description
Device labels (e.g., "main.dart (macOS)", "main.dart (iPhone 16 Pro)") no longer appear in Run/Debug tab titles starting with IntelliJ 2025.3 (Android Studio Panda). All tabs show only the run configuration name (e.g., "main.dart"), making it impossible to distinguish which device a build is running on when targeting multiple platforms simultaneously.
Root Cause
The reflection code in LaunchState.java (lines 173-185) that sets the display name is silently failing on every launch.
The code gets the private myDisplayNameView field from RunContentDescriptor, then calls getMethod("setValue", Object.class) on the field's runtime class, then calls invoke(). This worked when the field type was MutableReactiveProperty (a public IntelliJ-internal class), but broke in IntelliJ 2025.3 when the field type was changed to MutableStateFlow from kotlinx-coroutines (JetBrains/intellij-community@aaa88849ba4c).
The runtime implementation class kotlinx.coroutines.flow.StateFlowImpl is package-private. Java's access control prevents Method.invoke() on a public method when the declaring class is not accessible from the caller, throwing IllegalAccessException. The exception is caught silently (logged at INFO without stack trace), so the device name is never applied.
Verification
The Android Studio idea.log shows "Error setting display name" (from the catch block in LaunchState.java:184) on every Flutter launch in Panda.
Reproduced independently by calling the same reflection against the actual kotlinx-coroutines-core-jvm.jar shipped with Android Studio Panda:
MutableStateFlow<String> flow = StateFlowKt.MutableStateFlow(null);
Method m = flow.getClass().getMethod("setValue", Object.class);
m.invoke(flow, "test");
// IllegalAccessException: cannot access a member of class
// kotlinx.coroutines.flow.StateFlowImpl with modifiers "public"
Proposed Fix
Use RunContentDescriptor.setDisplayName() (an existing protected method on RunContentDescriptor) via reflection instead of reaching into the private field's internal type:
Method setDisplayName = RunContentDescriptor.class.getDeclaredMethod("setDisplayName", String.class);
setDisplayName.setAccessible(true);
setDisplayName.invoke(descriptor, nameWithDeviceName);
This is more resilient because it calls a stable API method on a public class rather than depending on the internal type of a private field.
An alternative minimal fix would be to add setValueMethod.setAccessible(true) before the invoke() call in the existing code, but this remains fragile if the field type changes again.
Affected Versions
- Broken: Android Studio Panda 1 (2025.3.1), IntelliJ 2025.3+
- Working: Android Studio Narwhal (2025.1.x), IntelliJ 2025.1 and earlier
Related
Description
Device labels (e.g., "main.dart (macOS)", "main.dart (iPhone 16 Pro)") no longer appear in Run/Debug tab titles starting with IntelliJ 2025.3 (Android Studio Panda). All tabs show only the run configuration name (e.g., "main.dart"), making it impossible to distinguish which device a build is running on when targeting multiple platforms simultaneously.
Root Cause
The reflection code in
LaunchState.java(lines 173-185) that sets the display name is silently failing on every launch.The code gets the private
myDisplayNameViewfield fromRunContentDescriptor, then callsgetMethod("setValue", Object.class)on the field's runtime class, then callsinvoke(). This worked when the field type wasMutableReactiveProperty(a public IntelliJ-internal class), but broke in IntelliJ 2025.3 when the field type was changed toMutableStateFlowfrom kotlinx-coroutines (JetBrains/intellij-community@aaa88849ba4c).The runtime implementation class
kotlinx.coroutines.flow.StateFlowImplis package-private. Java's access control preventsMethod.invoke()on a public method when the declaring class is not accessible from the caller, throwingIllegalAccessException. The exception is caught silently (logged at INFO without stack trace), so the device name is never applied.Verification
The Android Studio
idea.logshows"Error setting display name"(from the catch block inLaunchState.java:184) on every Flutter launch in Panda.Reproduced independently by calling the same reflection against the actual
kotlinx-coroutines-core-jvm.jarshipped with Android Studio Panda:Proposed Fix
Use
RunContentDescriptor.setDisplayName()(an existing protected method onRunContentDescriptor) via reflection instead of reaching into the private field's internal type:This is more resilient because it calls a stable API method on a public class rather than depending on the internal type of a private field.
An alternative minimal fix would be to add
setValueMethod.setAccessible(true)before theinvoke()call in the existing code, but this remains fragile if the field type changes again.Affected Versions
Related
aaa88849ba4cmyDisplayNameViewreflection