Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Native Graphics: Crash in ShadowNativeTypeface #9039

Open
realdadfish opened this issue May 2, 2024 · 4 comments
Open

Native Graphics: Crash in ShadowNativeTypeface #9039

realdadfish opened this issue May 2, 2024 · 4 comments

Comments

@realdadfish
Copy link
Contributor

When enabling native graphics mode in 4.11.1 or 4.12.1, Robolectric tests crash with

java.lang.NoClassDefFoundError: Could not initialize class android.graphics.Typeface
	at java.base/java.lang.Class.forName0(Native Method)
	at java.base/java.lang.Class.forName(Class.java:375)
	at org.robolectric.shadows.ShadowNativeTypeface.ensureInitialized(ShadowNativeTypeface.java:253)
	at org.robolectric.shadows.ShadowNativePaint.nInit(ShadowNativePaint.java:44)
	at android.graphics.Paint.nInit(Paint.java)
	at android.graphics.Paint.__constructor__(Paint.java:597)
	at android.graphics.Paint.<init>(Paint.java:596)
	at android.graphics.Paint.<init>(Paint.java:580)
	at com.android.internal.policy.DecorView.__constructor__(DecorView.java:279)
	at com.android.internal.policy.DecorView.<init>(DecorView.java:300)
	at com.android.internal.policy.PhoneWindow.generateDecor(PhoneWindow.java:2385)
	at com.android.internal.policy.PhoneWindow.installDecor(PhoneWindow.java:2727)
	at com.android.internal.policy.PhoneWindow.getDecorView(PhoneWindow.java:2144)
	at android.app.ActivityTransitionState.setEnterActivityOptions(ActivityTransitionState.java:171)
	at android.app.Activity.performCreate(Activity.java:8299)
	at android.app.Activity.performCreate(Activity.java:8269)
	at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1384)
	at org.robolectric.android.internal.RoboMonitoringInstrumentation.callActivityOnCreate(RoboMonitoringInstrumentation.java:382)
	at org.robolectric.android.controller.ActivityController.lambda$create$0(ActivityController.java:138)
	at org.robolectric.shadows.ShadowPausedLooper.runPaused(ShadowPausedLooper.java:243)
	at org.robolectric.android.controller.ActivityController.create(ActivityController.java:136)
	at org.robolectric.android.controller.ActivityController.create(ActivityController.java:146)
	at org.robolectric.android.internal.RoboMonitoringInstrumentation.lambda$startActivitySyncInternal$0(RoboMonitoringInstrumentation.java:130)
	at org.robolectric.shadows.ShadowInstrumentation.runOnMainSyncNoIdle(ShadowInstrumentation.java:1190)
	at org.robolectric.android.internal.RoboMonitoringInstrumentation.startActivitySyncInternal(RoboMonitoringInstrumentation.java:125)
	at org.robolectric.android.internal.LocalActivityInvoker.startActivity(LocalActivityInvoker.java:36)
	at org.robolectric.android.internal.LocalActivityInvoker.startActivity(LocalActivityInvoker.java:41)
	at androidx.test.core.app.ActivityScenario.launchInternal(ActivityScenario.java:362)
	at androidx.test.core.app.ActivityScenario.launch(ActivityScenario.java:235)
	at androidx.fragment.app.testing.FragmentScenario$Companion.internalLaunch$fragment_testing_release(FragmentScenario.kt:521)
	at androidx.fragment.app.testing.FragmentScenario$Companion.launchInContainer(FragmentScenario.kt:492)
	at androidx.fragment.app.testing.FragmentScenario$Companion.launchInContainer$default(FragmentScenario.kt:486)
	at androidx.fragment.app.testing.FragmentScenario$Companion.launchInContainer(FragmentScenario.kt)
	at androidx.fragment.app.testing.FragmentScenario.launchInContainer(FragmentScenario.kt)
	at eu.gls.parcelos.android.service.SubsystemServicesStatusFragmentTest.testSubsystemServiceStatusFragmentFail(SubsystemServicesStatusFragmentTest.java:57)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.robolectric.RobolectricTestRunner$HelperTestRunner$1.evaluate(RobolectricTestRunner.java:489)
	at org.robolectric.internal.SandboxTestRunner$2.lambda$evaluate$2(SandboxTestRunner.java:290)
	at org.robolectric.internal.bytecode.Sandbox.lambda$runOnMainThread$0(Sandbox.java:104)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
	at java.base/java.lang.Thread.run(Thread.java:840)
Caused by: java.lang.ExceptionInInitializerError: Exception java.lang.RuntimeException: java.lang.reflect.InvocationTargetException [in thread "SDK 33 Main Thread"]
	at org.robolectric.internal.bytecode.ShadowWrangler.classInitializing(ShadowWrangler.java:187)
	at org.robolectric.internal.bytecode.RobolectricInternals.classInitializing(RobolectricInternals.java:21)
	at android.graphics.Typeface.<clinit>(Typeface.java)
	at java.base/java.lang.Class.forName0(Native Method)
	at java.base/java.lang.Class.forName(Class.java:375)
	at org.robolectric.shadows.ShadowNativeTypeface.ensureInitialized(ShadowNativeTypeface.java:253)
	at org.robolectric.shadows.ShadowNativePaint.nInit(ShadowNativePaint.java:44)
	at android.graphics.Paint.nInit(Paint.java)
	at android.graphics.Paint.$$robo$$android_graphics_Paint$__constructor__(Paint.java:597)
	at android.graphics.Paint.<init>(Paint.java:596)
	at android.graphics.Paint.<init>(Paint.java:580)
	at com.android.internal.policy.DecorView.$$robo$$com_android_internal_policy_DecorView$__constructor__(DecorView.java:279)
	at com.android.internal.policy.DecorView.<init>(DecorView.java:300)
	at com.android.internal.policy.PhoneWindow.$$robo$$com_android_internal_policy_PhoneWindow$generateDecor(PhoneWindow.java:2385)
	at com.android.internal.policy.PhoneWindow.generateDecor(PhoneWindow.java)
	at com.android.internal.policy.PhoneWindow.$$robo$$com_android_internal_policy_PhoneWindow$installDecor(PhoneWindow.java:2727)
	at com.android.internal.policy.PhoneWindow.installDecor(PhoneWindow.java)
	at com.android.internal.policy.PhoneWindow.$$robo$$com_android_internal_policy_PhoneWindow$getDecorView(PhoneWindow.java:2144)
	at com.android.internal.policy.PhoneWindow.getDecorView(PhoneWindow.java)
	at androidx.activity.ComponentActivity.initializeViewTreeOwners(ComponentActivity.java:474)
	at androidx.activity.ComponentActivity.setContentView(ComponentActivity.java:438)
	at eu.gls.parcelos.android.service.app.MainActivity.onCreate(MainActivity.java:51)
	at android.app.Activity.$$robo$$android_app_Activity$performCreate(Activity.java:8290)
	at android.app.Activity.performCreate(Activity.java)
	at android.app.Activity.$$robo$$android_app_Activity$performCreate(Activity.java:8269)
	at android.app.Activity.performCreate(Activity.java)
	at android.app.Instrumentation.$$robo$$android_app_Instrumentation$callActivityOnCreate(Instrumentation.java:1384)
	at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java)
	at org.robolectric.android.internal.RoboMonitoringInstrumentation.callActivityOnCreate(RoboMonitoringInstrumentation.java:382)
	at org.robolectric.android.controller.ActivityController.lambda$create$0(ActivityController.java:138)
	at org.robolectric.shadows.ShadowPausedLooper.runPaused(ShadowPausedLooper.java:243)
	at org.robolectric.android.controller.ActivityController.create(ActivityController.java:136)
	at org.robolectric.android.controller.ActivityController.create(ActivityController.java:146)
	at org.robolectric.android.internal.RoboMonitoringInstrumentation.lambda$startActivitySyncInternal$0(RoboMonitoringInstrumentation.java:130)
	at org.robolectric.shadows.ShadowInstrumentation.runOnMainSyncNoIdle(ShadowInstrumentation.java:1190)
	at org.robolectric.android.internal.RoboMonitoringInstrumentation.startActivitySyncInternal(RoboMonitoringInstrumentation.java:125)
	at org.robolectric.android.internal.LocalActivityInvoker.startActivity(LocalActivityInvoker.java:36)
	at org.robolectric.android.internal.LocalActivityInvoker.startActivity(LocalActivityInvoker.java:41)
	at androidx.test.core.app.ActivityScenario.launchInternal(ActivityScenario.java:362)
	at androidx.test.core.app.ActivityScenario.launch(ActivityScenario.java:202)
	at eu.gls.parcelos.android.service.MainActivityTest.setUp(MainActivityTest.java:34)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
	at org.junit.internal.runners.statements.RunBefores.invokeMethod(RunBefores.java:33)
	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
	... 8 more

This happens on several SDK levels (30, 32, 33) that we've tested.

@realdadfish
Copy link
Contributor Author

I haven't yet been able to make a small reproducer, it's probably another dependency that causes the issue. Here is another part of the stacktrace I was previously missing:

Caused by: java.lang.NullPointerException: Cannot read field "mStyle" because "family" is null
	at android.graphics.Typeface.create(Typeface.java:916)
	at android.graphics.Typeface.setSystemFontMap(Typeface.java:1362)
	at android.graphics.Typeface.loadPreinstalledSystemFontMap(Typeface.java:1445)
	at org.robolectric.shadows.ShadowNativeTypeface.__staticInitializer__(ShadowNativeTypeface.java:61)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at org.robolectric.internal.bytecode.ShadowWrangler.classInitializing(ShadowWrangler.java:182)
	at org.robolectric.internal.bytecode.RobolectricInternals.classInitializing(RobolectricInternals.java:21)
	at android.graphics.Typeface.<clinit>(Typeface.java)
	at java.base/java.lang.Class.forName0(Native Method)
	at java.base/java.lang.Class.forName(Class.java:375)
	at org.robolectric.shadows.ShadowNativeTypeface.ensureInitialized(ShadowNativeTypeface.java:253)
	at org.robolectric.shadows.ShadowNativePaint.nInit(ShadowNativePaint.java:44)
	at android.graphics.Paint.nInit(Paint.java)
	at android.graphics.Paint.__constructor__(Paint.java:597)
	at android.graphics.Paint.<init>(Paint.java:596)
	at android.graphics.Paint.<init>(Paint.java:580)
	at com.android.internal.policy.DecorView.__constructor__(DecorView.java:279)
	at com.android.internal.policy.DecorView.<init>(DecorView.java:300)
	at com.android.internal.policy.PhoneWindow.generateDecor(PhoneWindow.java:2385)
	at com.android.internal.policy.PhoneWindow.installDecor(PhoneWindow.java:2727)
	at com.android.internal.policy.PhoneWindow.getDecorView(PhoneWindow.java:2144)
	at androidx.activity.ComponentActivity.initializeViewTreeOwners(ComponentActivity.java:474)
	at androidx.activity.ComponentActivity.setContentView(ComponentActivity.java:438)
	at eu.gls.parcelos.android.service.app.MainActivity.onCreate(MainActivity.java:51)
	at android.app.Activity.performCreate(Activity.java:8290)
	at android.app.Activity.performCreate(Activity.java:8269)
	at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1384)
	at org.robolectric.android.internal.RoboMonitoringInstrumentation.callActivityOnCreate(RoboMonitoringInstrumentation.java:382)
	at org.robolectric.android.controller.ActivityController.lambda$create$0(ActivityController.java:138)
	at org.robolectric.shadows.ShadowPausedLooper.runPaused(ShadowPausedLooper.java:243)
	at org.robolectric.android.controller.ActivityController.create(ActivityController.java:136)
	at org.robolectric.android.controller.ActivityController.create(ActivityController.java:146)
	at org.robolectric.android.internal.RoboMonitoringInstrumentation.lambda$startActivitySyncInternal$0(RoboMonitoringInstrumentation.java:130)
	at org.robolectric.shadows.ShadowInstrumentation.runOnMainSyncNoIdle(ShadowInstrumentation.java:1190)
	at org.robolectric.android.internal.RoboMonitoringInstrumentation.startActivitySyncInternal(RoboMonitoringInstrumentation.java:125)
	at org.robolectric.android.internal.LocalActivityInvoker.startActivity(LocalActivityInvoker.java:36)
	at org.robolectric.android.internal.LocalActivityInvoker.startActivity(LocalActivityInvoker.java:41)
	at androidx.test.core.app.ActivityScenario.launchInternal(ActivityScenario.java:362)
	at androidx.test.core.app.ActivityScenario.launch(ActivityScenario.java:202)
	at eu.gls.parcelos.android.service.MainActivityTest.setUp(MainActivityTest.java:34)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	... 13 more

@hoisie
Copy link
Contributor

hoisie commented May 2, 2024

From a cursory glance, this could happen if system fonts are not extracted or get corrupted:

https://github.com/robolectric/robolectric/blob/master/nativeruntime/src/main/java/org/robolectric/nativeruntime/DefaultNativeRuntimeLoader.java#L108

Does it happen 100% of the time?

nativeruntime-dist-compat.jar has a resource directory called fonts that contains Android system fonts:

https://repo.maven.apache.org/maven2/org/robolectric/nativeruntime-dist-compat/1.0.9/

@realdadfish
Copy link
Contributor Author

Yes, happens reproducible every time when native graphics are enabled. Then again, the test (and production code) is so simple that I couldn't yet reproduce it outside of my project, yet. Seems as if some other dependency triggers that behavior.

@hoisie
Copy link
Contributor

hoisie commented May 18, 2024

Does this still happen with 4.12.2?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants