dotnet / android

.NET for Android provides open-source bindings of the Android SDK for use with .NET managed languages such as C#
MIT License
1.93k stars 528 forks source link

HAXM acceleration not working with emulator versions >= 27.2.7 #2165

Closed mbikovitsky closed 6 years ago

mbikovitsky commented 6 years ago

Steps to Reproduce

  1. Use Windows 10 April 2018 Update (version 1803).
  2. Install Xamarin, the Android emulator and HAXM via the Visual Studio 2017 installer.
  3. Launch an x86 device image.

Expected Behavior

HAXM acceleration is used.

Actual Behavior

The emulator attempts to use the Windows Hypervisor Platform (WHPX), as evidenced by the following command-line: "C:\Program Files (x86)\Android\android-sdk\emulator\emulator.exe" "-verbose" "-feature" "WindowsHypervisorPlatform". This fails because Hyper-V is not installed on the machine, and so acceleration is completely disabled.

Version Information

Xamarin   4.11.0.756 (d15-8@b66ff7180)
Visual Studio extension to enable development for Xamarin.iOS and Xamarin.Android.

Xamarin.Android SDK   9.0.0.19 (HEAD/a8a3b0ec7)
Xamarin.Android Reference Assemblies and MSBuild support.

Log File

The Android Device Manager log clearly shows that HAXM is detected correctly:

[18-09-08 23:22:33.30] Detecting component Intel x86 Emulator Accelerator (HAXM installer) r7.2.0 [Extra: (Intel Corporation)] in directory 'C:\Program Files (x86)\Android\android-sdk\extras/intel/Hardware_Accelerated_Execution_Manager'
[18-09-08 23:22:33.30]   Found revision 7.2.0 on the system

However, when an image is launched, the following is written to the log:

[18-09-08 23:28:42.18] Going to start Android_Accelerated_x86_Oreo
[18-09-08 23:28:42.19] [HypervisorManager] Checking for accelerated emulator: True
[18-09-08 23:28:42.19] Executing command: cmd "/C" "sc" "query" "intelhaxm"
[18-09-08 23:28:42.24] [HypervisorManager] WHPX + HAXM
[18-09-08 23:28:42.24] [EmulatorManager] Adding WHPX flag

Again, HAXM is detected, but the emulator is launched with WHPX nonetheless.

Additional Notes

I managed to track the issue down to the StartProcess method in the Xamarin.DeviceManager.Common.EmulatorManager class, inside AndroidDevices.exe (pardon my use of dotPeek):

if (AppInfo.OSInformation.SupportsNativeHypervisor && this.EmulatorComponentSupportsHypervisorPlatform)
{
    Logger.Log("[EmulatorManager] Adding WHPX flag");
    stringList.InsertRange(0, (IEnumerable<string>) new string[3]
    {
        "-verbose",
        "-feature",
        "WindowsHypervisorPlatform"
    });
    this.runningWithWHPX = true;
}

As can be seen, the emulator is directed to use WHPX when both the OS and the emulator support it:

public virtual bool EmulatorComponentSupportsHypervisorPlatform
{
    get
    {
        return this.GetEmulatorComponent(EmulatorManager.EmulatorFindMode.FindInstalled)?.InstalledRevision >= EmulatorManager.MIN_HYPERVISOR_SUPPORTED_EMU_VERSION;
    }
}

However, no check is made to ensure that WHPX is actually enabled on the system. This results in no acceleration being used by the emulator.

JonDouglas commented 6 years ago

@mbikovitsky Thank you so much for your detailed issue. The original functionality that Visual Studio 2017 had was to check for hyper-v first, and then WHPX. This of course would run an emulator in an unaccelerated mode if only WHPX was enabled and not Hyper-V. I believe you are running into this use-case. To confirm this, do you have only WHPX enabled in Windows Features and not Hyper-V? https://docs.microsoft.com/en-us/xamarin/android/get-started/installation/android-emulator/hardware-acceleration?tabs=vswin#enabling-hyper-v-acceleration

I believe the problem with enabling WHPX, is that it disables HAXM. Thus only the WHPX hypervisor is available to use. Can you double check this for me locally by using the following?

https://docs.microsoft.com/en-us/xamarin/android/get-started/installation/android-emulator/troubleshooting?tabs=vswin#hardware-acceleration-not-available

Here is a local command with WHPX enabled, and Hyper-V disabled:

C:\Users\dougl\AppData\Local\Android\sdk\emulator>emulator-check accel
accel:
0
HAXM is not installed, but Windows Hypervisor Platform is available.
accel

Note: HAXM is installed on my machine.

If I were to disable WHPX and Hyper-V, and already had HAXM installed previously, I would then default to HAXM:

C:\Users\dougl\AppData\Local\Android\sdk\emulator>emulator-check accel
accel:
0
HAXM version 6.2.0 (4) is installed and usable.
accel

Thus it seems like you can't mix the two hypervisors.

Needless to say, we've patched the emulator launching command in Visual Studio 2017 to ensure it can launch with a WHPX-only use-case. As for the Device Manager, I believe it already handles this use-case correctly. I'd love to hear your thoughts on this to ensure we aren't missing anything here.

In short, if you have WHPX enabled(With or without hyper-v), the emulator will launch with the Windows hypervisor. If you have HAXM enabled and WHPX/Hyper-V disabled, the emulator with launch with the HAXM hypervisor

mbikovitsky commented 6 years ago

Here is the output from emulator-check on my machine:

accel:
0
HAXM version 7.2.0 (4) is installed and usable.
accel

Additionally, both Hyper-V and WHPX are disabled: Windows Features dialog showing Hyper-V is unchecked Windows Features dialog showing Windows Hypervisor Platform is unchecked

However, the code in AndroidDevices.exe does not check whether WHPX is enabled. Instead, it simply compares the Windows version to 1803, which is where the Hypervisor Platform API was first introduced.

Perhaps a better way to solve this would be to call WHvGetCapability (exported from WinHvPlatform.dll) with the code WHvCapabilityCodeHypervisorPresent.

JonDouglas commented 6 years ago

@mbikovitsky Thanks for the clarification.

Now that I have full context, I believe your thoughts are correct and thank you so much for your detailed report! The Device Manager is adding the -feature WindowsHypervisorPlatform flag regardless of if WHPX is enabled or not due to the Windows OS version check. Luckily the emulator program is smart enough to fallback to HAXM if WHPX is disabled. I will relay this information to our Device Manager team to ensure we aren't adding this flag unless we have a WHPX check in place.

mbikovitsky commented 6 years ago

Oh, I didn't realize the emulator could do a fall back. Thank you for your help!

JonDouglas commented 6 years ago

@mbikovitsky We fixed this in an upstream version of the device manager. You should see it in a new release of Visual Studio 2017. Thank you for bringing it to our attention!