Android 8 and uiautomator2 issues.
During performing some tests on new devices with android 8 I've noticed that there is a problem with performing them using uiautomator2. At first I thoguht that it is related to appium-dotnet-driver. But I've reproduced the issue on java-client. The behavior is that on some requests server is hanging. I tried both versions, with click, with touch actions. Nothing is working. Issue has been recreated on appium 1.8.0 and 1.8.1 with uiautomator2 server 1.7.0 and 1.12.0 with same results.
Java-client code:
DesiredCapabilities capabilities = new DesiredCapabilities(); capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "auto"); capabilities.setCapability(MobileCapabilityType.APP, app.getAbsolutePath()); capabilities.setCapability(MobileCapabilityType.AUTOMATION_NAME, AutomationName.ANDROID_UIAUTOMATOR2); AppiumDriver<MobileElement> driver = new AndroidDriver<>( new URL("http://127.0.0.1:4723/wd/hub"), capabilities); MobileElement element = driver.findElementById("android:id/tabs"); final List<MobileElement> elementsByXPath = element.findElementsByXPath("//*"); element.findElementsByXPath("//*").stream().filter((x) -> x.getText().equals("CONTROLS")).findFirst().get().click();
logs from java-client uiautomator2 execution
[HTTP] --> POST /wd/hub/session/5ed3282d-6d05-4ce1-b61c-65e51b56e007/element/160bbe9a-b513-411a-98fe-072e96ee6576/click [HTTP] {"id":"160bbe9a-b513-411a-98fe-072e96ee6576"} [debug] [W3C] Calling AppiumDriver.click() with args: ["160bbe9a-b513-411a-98fe-072e96ee6576","5ed3282d-6d05-4ce1-b61c-65e51b56e007"] [debug] [JSONWP Proxy] Proxying [POST /element/160bbe9a-b513-411a-98fe-072e96ee6576/click] to [POST http://localhost:8200/wd/hub/session/4ad824e3-8852-41ca-922b-c262b248a78d/element/160bbe9a-b513-411a-98fe-072e96ee6576/click] with body: {"element":"160bbe9a-b513-411a-98fe-072e96ee6576"} [HTTP] <-- POST /wd/hub/session/5ed3282d-6d05-4ce1-b61c-65e51b56e007/element/160bbe9a-b513-411a-98fe-072e96ee6576/click - - ms - -
Logcat device logs https://gist.github.com/GrzegorzSidwa/20785948221a23e6757ae80557b76c4c
Logcat appium-uiautomator2-server logs https://gist.github.com/GrzegorzSidwa/0750ace36bcaaf2b3711f1bff92f6aaa
appium-dotnet-driver code
AndroidDriver<AppiumWebElement> driver = new AndroidDriver<AppiumWebElement>(new Uri("http://127.0.0.1:4723/wd/hub"), caps, TimeSpan.FromMinutes(15)); var element = driver.FindElementById(@"android:id/tabs"); var appiumWebElement = element.FindElementsByXPath("//*").FirstOrDefault(x => x.Text == "CONTROLS"); new TouchAction(driver).Press(appiumWebElement).Wait(500).Release().Perform();
logs from appium-dotnet-driver execution
[HTTP] --> POST /wd/hub/session/23a503cc-e4b2-4e48-b750-63e4d362b354/touch/perform [HTTP] {"actions":[{"action":"press","options":{"element":"dcbad3b6-d315-42f7-a574-8ebb59fead73"}},{"action":"wait","options":{"ms":500}},{"action":"release"}]} [debug] [W3C] Calling AppiumDriver.performTouch() with args: [[{"action":"press","options":{"element":"dcbad3b6-d315-42f7-a574-8ebb59fead73"}},{"action":"wait","options":{"ms":500}},{"action":"release"}],"23a503cc-e4b2-4e48-b750-63e4d362b354"] [UiAutomator2] calling get location: dcbad3b6-d315-42f7-a574-8ebb59fead73 [debug] [JSONWP Proxy] Proxying [GET /element/dcbad3b6-d315-42f7-a574-8ebb59fead73/location] to [GET http://localhost:8200/wd/hub/session/b493e649-4d2f-48ca-af88-a3ebacd59f51/element/dcbad3b6-d315-42f7-a574-8ebb59fead73/location] with body: {}
Conclusion Exactly the same tests executed on device with Android 7 are working correctly.
Very similar issue has been described here: https://github.com/appium/appium-uiautomator2-server/issues/101
this is thread dump for that issue: java.lang.Thread.State: RUNNABLE at android.view.accessibility.AccessibilityInteractionClient.getInstanceForThread(AccessibilityInteractionClient.java:131) at android.view.accessibility.AccessibilityInteractionClient.getInstance(AccessibilityInteractionClient.java:119) at android.view.accessibility.AccessibilityNodeInfo.getNodeForAccessibilityId(AccessibilityNodeInfo.java:3673) at android.view.accessibility.AccessibilityNodeInfo.getParent(AccessibilityNodeInfo.java:1620) at android.support.test.uiautomator.UiObject2.getVisibleBounds(UiObject2.java:235) at android.support.test.uiautomator.UiObject2.getVisibleBounds(UiObject2.java:210) at android.support.test.uiautomator.UiObject2.getVisibleCenter(UiObject2.java:251) at android.support.test.uiautomator.UiObject2.click(UiObject2.java:343) at io.appium.uiautomator2.model.UiObject2Element.click(UiObject2Element.java:64) at io.appium.uiautomator2.handler.Click.safeHandle(Click.java:38) at io.appium.uiautomator2.handler.request.SafeRequestHandler.handle(SafeRequestHandler.java:65) at io.appium.uiautomator2.server.AppiumServlet.handleRequest(AppiumServlet.java:247) at io.appium.uiautomator2.server.AppiumServlet.handleHttpRequest(AppiumServlet.java:238) at io.appium.uiautomator2.http.ServerHandler.channelRead(ServerHandler.java:44) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:366) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:352) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:345) at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:366) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:352) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:345) at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:435) at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:293) at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:267) at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:250) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:366) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:352) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:345) at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1294) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:366) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:352) at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:911) at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:131) at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:611) at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:552) at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:466) at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:438) at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:140) at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:144) at java.lang.Thread.run(Thread.java:764)
@ArturKurowski1 As you can see the code is stuck inside standard Android lib. I don't think that anything could be changed there from Appium side.
@mykola-mokhnach Yes I noticed it goes into infinite loop inside UIObject2.getVisibleBounds since we do not have scrollable element in our test app on that screen , and for some reasonse getting parent is infinite. From Appium and ui-automator2-server everything is fine
https://issuetracker.google.com/issues/111312903
The Issue: So the issue here as mentioned above is that getVisibleBounds is stuck in an endless loop because the parent is never null and is never a scrollable element. The REAL issue is probably originates from the application itself, i debugged an application with this issue and it seems that eventually getParent will return an element we already iterated on... meaning there is a recursion of parents that none of them is a scrollable element, which causes the loop to be... well, an infinity loop.
The Solution!... NOTE: getting a parent with getParent creates a new Object everytime from the parentId! Luckily, this is something that can be solved, we just need create a Set that holds all the parentId we already iterated on in the for loop and once we find a parentId that is already inside our Set we can safely break the loop knowing we are probably stuck on the right element.
The concrete solution without changing internal libraries is to actually override them. I've attached my simple override in a zip file. ClickFix.zip