Fatal Exception: java.lang.VerifyError when using Datastore with my own data class on some devices

34 views Asked by At

So I noticed the following crashes at Firebase Crashlytics of my app which happens only for a couple of devices (so rarely) but still it happens:

Fatal Exception: java.lang.VerifyError Verifier rejected class o3.c: java.security.cert.X509Certificate[] o3.c.E(java.nio.ByteBuffer, java.util.HashMap, java.security.cert.CertificateFactory) failed to verify: java.security.cert.X509Certificate[] o3.c.E(java.nio.ByteBuffer, java.util.HashMap, java.security.cert.CertificateFactory): [0x135] register v0 has type Reference: java.nio.ByteBuffer but expected Precise Reference: byte[] (declaration of 'o3.c' appears in /data/app/~~N1_TwW2swHQZzciPS8e0uw==/com.hidden_my_package.myapp-O87GcvydxMif4uP_FrnEXQ==/base.apk) kotlinx.coroutines.flow.FlowKt__ShareKt.asStateFlow (FlowKt__Share.kt:38)

com.hidden_my_package.datastore.di.DatastoreModule_ProvidePreferencesManagerFactory.providePreferencesManager (DatastoreModule_ProvidePreferencesManagerFactory.java:420) com.hidden_my_package.myapp.DaggerMyApplication_HiltComponents_SingletonC$SingletonCImpl$SwitchingProvider.get (DaggerBVRApplication_HiltComponents_SingletonC.java:420)

I can't reproduce the issue myself.

So based on the stack trace I have the following implementation of DataStore to save users' preferences:

class PreferencesManagerImpl(
    private val context: Context,
    private val dataStore: DataStore<Preferences>,
    lifecycleOwner: LifecycleOwner,
) : PreferencesManager {

    override val preferences: StateFlow<Preferences> = preferencesStateFlow.asStateFlow()
    
    ...

My custom preferences data class:

// the next free proto number = 119

@Serializable
data class Preferences(
    ....
    @ProtoNumber(62) val preferencesCamera: HashMap<String, PreferencesCamera>, // key - camera id
    @ProtoNumber(63) val useMiles: Boolean,
    ...
) {

// next free proto number 14

@Serializable
data class PreferencesCamera(
    @ProtoNumber(1) val cameraAperture: Float,
    @ProtoNumber(2) val cameraControlSceneMode: CameraSceneMode?,
    @ProtoNumber(3) val cameraControlSceneModeNight: CameraSceneMode?,
    @ProtoNumber(4) val cameraExposure: Int,
    @ProtoNumber(5) val cameraExposureNight: Int,
    ...
)

So yes, I use DataStore + Protobuf:

class PreferencesDatastoreSerializer @Inject constructor(
    @ApplicationContext private val context: Context
) : Serializer<Preferences> {
    override val defaultValue: Preferences
        get() = PreferencesDefaults.getDefaultPreferences(context)

    override suspend fun readFrom(input: InputStream): Preferences {
        return try {
            ProtoBuf.decodeFromByteArray<Preferences>(input.readBytes())
        } catch (e: Throwable) {
            e.printStackTrace()
            throw CorruptionException("The data could not be de-serialized", e)
        }
    }

    @Suppress("BlockingMethodInNonBlockingContext")
    override suspend fun writeTo(t: Preferences, output: OutputStream) {
        output.write(ProtoBuf.encodeToByteArray(t))
    }
}

object PreferencesDefaults {
    fun getDefaultPreferences(context: Context): Preferences {
        ...
        return Preferences(
            ...
            preferencesCamera = hashMapOf(),
        )
    }
    ...

The error mentions something about byte arrays and hashmap during this exception, I don't have byte arrays in my Preference data class, but I use hashmap there:

@ProtoNumber(62) val preferencesCamera: HashMap<String, PreferencesCamera>

By byte arrays it just means that something happened when it was trying to encode or decode data from protobuf file (*.pb), I guess...

But what could be the issue here as it doesn't happen for most users and only for some?

0

There are 0 answers