android / android-test

An extensive framework for testing Android apps

Home Page:https://android.github.io/android-test

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

ViewRootImpl$CalledFromWrongThreadException when verifying Toast messages with androidx.test:core:1.5.0

Quantamm opened this issue · comments

Description

We're getting ViewRootImpl$CalledFromWrongThreadException exceptions when trying to verify Toast messages with androidx.test:core:1.5.0. 1.4.0 does not exhibit the issue. 1.6.0-alpha01 does.

Steps to Reproduce

On an Android 9 emulator, I use this ToastMatcher:

import android.view.WindowManager
import androidx.test.espresso.Root
import org.hamcrest.Description
import org.hamcrest.TypeSafeMatcher

class ToastMatcher : TypeSafeMatcher<Root>() {
    override fun describeTo(description: Description) {
        description.appendText("is toast")
    }

    override fun matchesSafely(root: Root) =
        root.windowLayoutParams.get().type == WindowManager.LayoutParams.TYPE_TOAST
                && root.decorView.windowToken === root.decorView.applicationWindowToken
}

with this line of code:

onView(withText("message")).inRoot(new ToastMatcher()).check(matches(isDisplayed()));

Expected Results

Using androidx.test:core:1.4.0, the matcher finds the Toast and the test passes.

Actual Results

using androidx.test:core:1.5.0, the test fails with:

android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:7753)
at android.view.ViewRootImpl.invalidateChildInParent(ViewRootImpl.java:1268)
at android.view.ViewRootImpl.invalidateChild(ViewRootImpl.java:1263)
at android.view.View.invalidateInternal(View.java:16434)
at android.view.View.invalidate(View.java:16398)
at android.view.View.invalidate(View.java:16381)
at androidx.test.core.view.ViewCapture.forceRedraw(ViewCapture.kt:113)
at androidx.test.core.app.DeviceCapture$forceRedrawGlobalWindowViews$1.run(DeviceCapture.kt:172)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)

AndroidX Test and Android OS Versions

androidx.test.core:1.5.0
androidx.arch.core:core-testing:2.2.0

Link to a public git repo demonstrating the problem:

I created a minimal project with the above code, but it doesn't reproduce the problem. I can't share the real project that's experiencing the issue, but I'm happy to answer any questions about our setup.

This stack trace is likely from when Espresso's error handler tries to take a screenshot from an already failing check. There is probably an earlier failure that is getting obscured.

Is your code under test inflating UI outside the main thread?

Is your code under test inflating UI outside the main thread?

Thank you for the sanity check. Since this issue only occurred with the upgrade of the library, I (falsely) assumed that it must be caused by the library. It turns out that one of the other devs apparently thought that calling Looper.prepare() on a background thread was the same thing as using the UI thread. I've fixed it and now we no longer have any issue.

Glad to hear you solved it!

It does sound like there is a legitimate debuggability issue with the new espresso library though if the root cause was not immediately apparent. Was the original stack trace the one reported as the cause of the failed test?

Was the original stack trace the one reported as the cause of the failed test?

I believe so. Here's the logcat from the check for the Toast message to the ViewRootImpl exception:

09-01 14:56:54.604 19119 19119 I ViewInteraction: Checking 'MatchesViewAssertion{viewMatcher=(view has effective visibility <VISIBLE> and view.getGlobalVisibleRect() to return non-empty rectangle)}' assertion on view an instance of android.widget.TextView and view.getText() with or without transformation to match: is "Toast message."
09-01 14:56:54.611 19119 19173 D cucumber-android: I should see the Launcher
09-01 14:56:54.619 19119 19119 I ViewInteraction: Checking 'MatchesViewAssertion{viewMatcher=(view has effective visibility <VISIBLE> and view.getGlobalVisibleRect() to return non-empty rectangle)}' assertion on view (view.getId() is <2131297314/com.my.package:id/primary_text> and an instance of android.widget.TextView and view.getText() equals string from resource id: <2131886629> [app_name] value: My App)
09-01 14:56:54.623 19119 19119 I ViewInteraction: Checking 'MatchesViewAssertion{viewMatcher=(view has effective visibility <VISIBLE> and view.getGlobalVisibleRect() to return non-empty rectangle)}' assertion on view view.getId() is <2131297511/com.my.package:id/status_layout>
09-01 14:56:54.627 19119 19173 V com.my.package.test.common.TestLogger.echoToAppLogger:427: java.lang
09-01 14:56:55.183 19119 19173 V com.my.package.notes.common.AppLoggerWrapper.trace:25: Added 137 smime certificates, 0 of which are user-provided
09-01 14:56:55.226 19119 19173 W Settings: Setting airplane_mode_on has moved from android.provider.Settings.System to android.provider.Settings.Global, returning read-only value.
09-01 14:56:55.229  1966  1998 D AutofillManagerService: Close system dialogs
09-01 14:56:55.231 19119 19173 V com.my.package.android.common.AuthenticationLockout.clearAuthenticationErrorNotificatENTRY
09-01 14:56:55.232 19119 19173 V com.my.package.android.common.AuthenticationLockout.clearAuthenticationErrorNotificatEXIT
09-01 14:56:55.233  2104  2104 V StatusBar: mStatusBarWindow: com.android.systemui.statusbar.phone.StatusBarWindowView{4a537ae V.ED..... ........ 0,0-1440,84} canPanelBeCollapsed(): false
09-01 14:56:55.234  2104  2104 V StatusBar: mStatusBarWindow: com.android.systemui.statusbar.phone.StatusBarWindowView{4a537ae V.ED..... ........ 0,0-1440,84} canPanelBeCollapsed(): false
09-01 14:56:55.236 19119 19173 V com.my.package.client.CalendarStore.instance:158: Using existing CalendarStore instance for account UUID = cb1c3f9d-b428-407a-ada1-d03246837b4f
09-01 14:56:55.237 19119 19173 V com.my.package.test.common.TestLogger.echoToAppLogger:427: java.lang
09-01 14:56:55.237  2104  2104 I vol.Events: writeEvent dismiss_dialog volume_controller
09-01 14:56:55.237  2104  2104 I vol.Events: writeEvent dismiss_dialog volume_controller
09-01 14:56:55.238 19119 19173 V com.my.package.test.common.TestLogger.echoToAppLogger:427: java.lang
09-01 14:56:55.243 19119 19119 I ViewInteraction: Performing 'send keyCode: 4, metaState: 0 key event' action on view view.getRootView() to equal view
09-01 14:56:55.250 19119 19119 V com.my.package.android.common.TravelerActivity.onBackPressed:174: ActivityClass=StatusActivity FragmentClasses=<empty>
09-01 14:56:55.250 19119 19119 V com.my.package.android.common.TravelerActivity.closedOpenDrawer:210: ActivityClass=StatusActivity FragmentClasses=<empty>
09-01 14:56:55.256 19119 19119 V com.my.package.android.common.TravelerActivity.onSafePause:612: ActivityClass=StatusActivity FragmentClasses=<empty>
09-01 14:56:55.257 19119 19119 D LifecycleMonitor: Lifecycle status change: com.my.package.StatusActivity@46cbb93 in: PAUSED
09-01 14:56:55.267  1966  1989 E memtrack: Couldn't load memtrack module
09-01 14:56:55.267  1966  1989 W android.os.Debug: failed to get memory consumption info: -1
09-01 14:56:55.313  1637  1699 D gralloc_ranchu: gralloc_alloc: Creating ashmem region of size 14749696
09-01 14:56:55.323  1637  1698 D gralloc_ranchu: gralloc_alloc: Creating ashmem region of size 14749696
09-01 14:56:55.329  1637  1699 D gralloc_ranchu: gralloc_alloc: Creating ashmem region of size 14749696
09-01 14:56:55.337  1799  1799 D SurfaceFlinger: duplicate layer name: changing com.google.android.apps.nexuslauncher/com.google.android.apps.nexuslauncher.NexusLauncherActivity to com.google.android.apps.nexuslauncher/com.google.android.apps.nexuslauncher.NexusLauncherActivity#1
09-01 14:56:55.358  1637  1699 D gralloc_ranchu: gralloc_alloc: Creating ashmem region of size 14749696
09-01 14:56:55.359  1637  1698 D gralloc_ranchu: gralloc_alloc: Creating ashmem region of size 14749696
09-01 14:56:55.365  1637  1699 D gralloc_ranchu: gralloc_alloc: Creating ashmem region of size 14749696
09-01 14:56:55.368  2840  3012 D EGL_emulation: eglMakeCurrent: 0x7e8aa9c398e0: ver 3 1 (tinfo 0x7e8aa9c891a0)
09-01 14:56:55.371  2095  2095 I GoogleInputMethod: onFinishInput() : Dummy InputConnection bound
09-01 14:56:55.377  2095  2095 I GoogleInputMethod: onStartInput() : Dummy InputConnection bound
09-01 14:56:55.401  2871  3210 D HostConnection: HostConnection::get() New Host Connection established 0xe55b3ba0, tid 3210
09-01 14:56:55.403  2871  3210 D HostConnection: HostComposition ext ANDROID_EMU_CHECKSUM_HELPER_v1 ANDROID_EMU_native_sync_v2 ANDROID_EMU_native_sync_v3 ANDROID_EMU_native_sync_v4 ANDROID_EMU_dma_v1 ANDROID_EMU_YUV420_888_to_NV21 ANDROID_EMU_YUV_Cache ANDROID_EMU_sync_buffer_data GL_OES_EGL_image_external_essl3 GL_OES_vertex_array_object GL_KHR_texture_compression_astc_ldr ANDROID_EMU_host_side_tracing ANDROID_EMU_gles_max_version_3_1 
09-01 14:56:55.406  2104  2424 D EGL_emulation: eglMakeCurrent: 0x7e8a96254220: ver 3 1 (tinfo 0x7e8aa823fe80)
09-01 14:56:55.412  2871  3210 I ConfigStore: android::hardware::configstore::V1_0::ISurfaceFlingerConfigs::hasWideColorDisplay retrieved: 0
09-01 14:56:55.412  2871  3210 I ConfigStore: android::hardware::configstore::V1_0::ISurfaceFlingerConfigs::hasHDRDisplay retrieved: 0
09-01 14:56:55.412  2871  3210 I OpenGLRenderer: Initialized EGL, version 1.4
09-01 14:56:55.413  2871  3210 D OpenGLRenderer: Swap behavior 1
09-01 14:56:55.413  2871  3210 W OpenGLRenderer: Failed to choose config with EGL_SWAP_BEHAVIOR_PRESERVED, retrying without...
09-01 14:56:55.413  2871  3210 D OpenGLRenderer: Swap behavior 0
09-01 14:56:55.425  2871  3210 D eglCodecCommon: setVertexArrayObject: set vao to 0 (0) 0 0
09-01 14:56:55.426  2871  3210 D EGL_emulation: eglCreateContext: 0xcc645d20: maj 3 min 1 rcv 4
09-01 14:56:55.428  2104  2424 D EGL_emulation: eglMakeCurrent: 0x7e8a96254220: ver 3 1 (tinfo 0x7e8aa823fe80)
09-01 14:56:55.428  2871  3210 D EGL_emulation: eglMakeCurrent: 0xcc645d20: ver 3 1 (tinfo 0xcc6082d0)
09-01 14:56:55.430  2871  3210 E eglCodecCommon: glUtilsParamSize: unknow param 0x000082da
09-01 14:56:55.430  2871  3210 E eglCodecCommon: glUtilsParamSize: unknow param 0x000082da
09-01 14:56:55.475  2871  3210 D EGL_emulation: eglMakeCurrent: 0xcc645d20: ver 3 1 (tinfo 0xcc6082d0)
09-01 14:56:55.482  2491 14635 E SQLiteDatabase: Error inserting period=7071000 preferred_charging_state=1 preferred_network_type=1 target_class=com.google.android.gms.measurement.PackageMeasurementTaskService required_network_type=0 runtime=1693598215472 required_idleness_state=0 source=16 service_kind=0 target_package=com.google.android.gms persistence_level=1 source_version=202414000 last_runtime=0 user_id=0 job_id=-1 requires_charging=0 tag=Measurement.PackageMeasurementTaskService.UPLOAD_TASK_TAG flex_time=3535000 task_type=0 retry_strategy={"maximum_backoff_seconds":{"3600":0},"initial_backoff_seconds":{"30":0},"retry_policy":{"0":0}}
09-01 14:56:55.482  2491 14635 E SQLiteDatabase: android.database.sqlite.SQLiteConstraintException: UNIQUE constraint failed: pending_ops.tag, pending_ops.target_class, pending_ops.target_package, pending_ops.user_id (code 2067 SQLITE_CONSTRAINT_UNIQUE)
09-01 14:56:55.482  2491 14635 E SQLiteDatabase:        at android.database.sqlite.SQLiteConnection.nativeExecuteForLastInsertedRowId(Native Method)
09-01 14:56:55.482  2491 14635 E SQLiteDatabase:        at android.database.sqlite.SQLiteConnection.executeForLastInsertedRowId(SQLiteConnection.java:796)
09-01 14:56:55.482  2491 14635 E SQLiteDatabase:        at android.database.sqlite.SQLiteSession.executeForLastInsertedRowId(SQLiteSession.java:788)
09-01 14:56:55.482  2491 14635 E SQLiteDatabase:        at android.database.sqlite.SQLiteStatement.executeInsert(SQLiteStatement.java:86)
09-01 14:56:55.482  2491 14635 E SQLiteDatabase:        at android.database.sqlite.SQLiteDatabase.insertWithOnConflict(SQLiteDatabase.java:1564)
09-01 14:56:55.482  2491 14635 E SQLiteDatabase:        at android.database.sqlite.SQLiteDatabase.insert(SQLiteDatabase.java:1433)
09-01 14:56:55.482  2491 14635 E SQLiteDatabase:        at aqui.a(:com.google.android.gms@202414023@20.24.14 (040800-319035315):175)
09-01 14:56:55.482  2491 14635 E SQLiteDatabase:        at aqtk.a(:com.google.android.gms@202414023@20.24.14 (040800-319035315):182)
09-01 14:56:55.482  2491 14635 E SQLiteDatabase:        at aqtk.a(:com.google.android.gms@202414023@20.24.14 (040800-319035315):23)
09-01 14:56:55.482  2491 14635 E SQLiteDatabase:        at aqtk.a(:com.google.android.gms@202414023@20.24.14 (040800-319035315):177)
09-01 14:56:55.482  2491 14635 E SQLiteDatabase:        at aqpu.run(:com.google.android.gms@202414023@20.24.14 (040800-319035315):9)
09-01 14:56:55.482  2491 14635 E SQLiteDatabase:        at soy.b(:com.google.android.gms@202414023@20.24.14 (040800-319035315):12)
09-01 14:56:55.482  2491 14635 E SQLiteDatabase:        at soy.run(:com.google.android.gms@202414023@20.24.14 (040800-319035315):8)
09-01 14:56:55.482  2491 14635 E SQLiteDatabase:        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
09-01 14:56:55.482  2491 14635 E SQLiteDatabase:        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
09-01 14:56:55.482  2491 14635 E SQLiteDatabase:        at sux.run(:com.google.android.gms@202414023@20.24.14 (040800-319035315):0)
09-01 14:56:55.482  2491 14635 E SQLiteDatabase:        at java.lang.Thread.run(Thread.java:764)
09-01 14:56:55.492  1637  1699 D gralloc_ranchu: gralloc_alloc: Creating ashmem region of size 14749696
09-01 14:56:55.533  1966  2385 I GnssLocationProvider: WakeLock acquired by sendMessage(REPORT_SV_STATUS, 0, com.android.server.location.GnssLocationProvider$SvStatusInfo@864851a)
09-01 14:56:55.534  1966  1989 I GnssLocationProvider: WakeLock released by handleMessage(REPORT_SV_STATUS, 0, com.android.server.location.GnssLocationProvider$SvStatusInfo@864851a)
09-01 14:56:55.561 19119 19119 V com.my.package.android.common.TravelerActivity.onSafeStop:621: ActivityClass=StatusActivity FragmentClasses=<empty>
09-01 14:56:55.561 19119 19119 V com.my.package.android.common.TravelerActivity.hideProgressBarIcon:353: Hide syncProgressBar icon without delay
09-01 14:56:55.562 19119 19119 V com.my.package.common.ui.ThumbnailRetrievalQueue.clearQueue:101: THUMBPROVIDER: clearing retrieval queue, task count=0
09-01 14:56:55.563  1966  5369 D HostConnection: HostConnection::get() New Host Connection established 0x7e8a8c5b5c20, tid 5369
09-01 14:56:55.564 19119 19119 D LifecycleMonitor: Lifecycle status change: com.my.package.StatusActivity@46cbb93 in: STOPPED
09-01 14:56:55.565  1966  5369 D HostConnection: HostComposition ext ANDROID_EMU_CHECKSUM_HELPER_v1 ANDROID_EMU_native_sync_v2 ANDROID_EMU_native_sync_v3 ANDROID_EMU_native_sync_v4 ANDROID_EMU_dma_v1 ANDROID_EMU_YUV420_888_to_NV21 ANDROID_EMU_YUV_Cache ANDROID_EMU_sync_buffer_data GL_OES_EGL_image_external_essl3 GL_OES_vertex_array_object GL_KHR_texture_compression_astc_ldr ANDROID_EMU_host_side_tracing ANDROID_EMU_gles_max_version_3_1 
09-01 14:56:55.571  1966  5369 I ConfigStore: android::hardware::configstore::V1_0::ISurfaceFlingerConfigs::hasWideColorDisplay retrieved: 0
09-01 14:56:55.571  1966  5369 I ConfigStore: android::hardware::configstore::V1_0::ISurfaceFlingerConfigs::hasHDRDisplay retrieved: 0
09-01 14:56:55.571  1966  5369 I OpenGLRenderer: Initialized EGL, version 1.4
09-01 14:56:55.571  1966  5369 D OpenGLRenderer: Swap behavior 1
09-01 14:56:55.571  1966  5369 W OpenGLRenderer: Failed to choose config with EGL_SWAP_BEHAVIOR_PRESERVED, retrying without...
09-01 14:56:55.571  1966  5369 D OpenGLRenderer: Swap behavior 0
09-01 14:56:55.586  2840  2855 I s.nexuslaunche: NativeAlloc concurrent copying GC freed 3982(315KB) AllocSpace objects, 3(256KB) LOS objects, 49% free, 3MB/7MB, paused 9.791ms total 50.014ms
09-01 14:56:55.589  1966  5369 D eglCodecCommon: setVertexArrayObject: set vao to 0 (0) 0 0
09-01 14:56:55.589  1966  5369 D EGL_emulation: eglCreateContext: 0x7e8a92bbd760: maj 3 min 1 rcv 4
09-01 14:56:55.607  1966  5369 D EGL_emulation: eglMakeCurrent: 0x7e8a92bbd760: ver 3 1 (tinfo 0x7e8a8c497240)
09-01 14:56:55.610  1966  5369 E eglCodecCommon: glUtilsParamSize: unknow param 0x000082da
09-01 14:56:55.610  1966  5369 E eglCodecCommon: glUtilsParamSize: unknow param 0x000082da
09-01 14:56:55.617  2104  2119 I ndroid.systemu: NativeAlloc concurrent copying GC freed 21657(1281KB) AllocSpace objects, 0(0B) LOS objects, 49% free, 5MB/11MB, paused 16.745ms total 69.365ms
09-01 14:56:55.618 19119 19119 D LifecycleMonitor: Lifecycle status change: com.my.package.StatusActivity@46cbb93 in: DESTROYED
09-01 14:56:55.640  1966  5369 D eglCodecCommon: setVertexArrayObject: set vao to 0 (0) 1 2
09-01 14:56:55.666  2871  2871 W SessionLifecycleManager: Handover failed. Creating new session controller.
09-01 14:56:55.232  1966  1998 D AutofillManagerService: Close system dialogs
09-01 14:56:55.716  1966  1966 V SettingsProvider: Notifying for 0: content://settings/secure/accessibility_enabled
09-01 14:56:55.737 19119 19119 D AndroidRuntime: Shutting down VM
09-01 14:56:55.741 19119 19119 E AndroidRuntime: FATAL EXCEPTION: main
09-01 14:56:55.741 19119 19119 E AndroidRuntime: Process: com.my.package, PID: 19119
09-01 14:56:55.741 19119 19119 E AndroidRuntime: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
09-01 14:56:55.741 19119 19119 E AndroidRuntime:        at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:7753)
09-01 14:56:55.741 19119 19119 E AndroidRuntime:        at android.view.ViewRootImpl.invalidateChildInParent(ViewRootImpl.java:1268)
09-01 14:56:55.741 19119 19119 E AndroidRuntime:        at android.view.ViewRootImpl.invalidateChild(ViewRootImpl.java:1263)
09-01 14:56:55.741 19119 19119 E AndroidRuntime:        at android.view.View.invalidateInternal(View.java:16434)
09-01 14:56:55.741 19119 19119 E AndroidRuntime:        at android.view.View.invalidate(View.java:16398)
09-01 14:56:55.741 19119 19119 E AndroidRuntime:        at android.view.View.invalidate(View.java:16381)
09-01 14:56:55.741 19119 19119 E AndroidRuntime:        at androidx.test.core.view.ViewCapture.forceRedraw(ViewCapture.kt:109)
09-01 14:56:55.741 19119 19119 E AndroidRuntime:        at androidx.test.core.app.DeviceCapture$forceRedrawGlobalWindowViews$1.run(DeviceCapture.kt:165)
09-01 14:56:55.741 19119 19119 E AndroidRuntime:        at android.os.Handler.handleCallback(Handler.java:873)
09-01 14:56:55.741 19119 19119 E AndroidRuntime:        at android.os.Handler.dispatchMessage(Handler.java:99)
09-01 14:56:55.741 19119 19119 E AndroidRuntime:        at android.os.Looper.loop(Looper.java:193)
09-01 14:56:55.741 19119 19119 E AndroidRuntime:        at android.app.ActivityThread.main(ActivityThread.java:6669)
09-01 14:56:55.741 19119 19119 E AndroidRuntime:        at java.lang.reflect.Method.invoke(Native Method)
09-01 14:56:55.741 19119 19119 E AndroidRuntime:        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
09-01 14:56:55.741 19119 19119 E AndroidRuntime:        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)