Skip to content

occur crash when switch DB #1202

Closed
Closed
@udyr-woo

Description

@udyr-woo

Is there an existing issue?

Build info

  • ObjectBox version: 4.0.3
  • OS: Android 13
  • Device/ABI/architecture: odroid-m2 | arm64-v8a

Steps to reproduce

I used normal db and test db(both are objectBox).
When changing isTestMode of a single-toned testMode Manager, there is a logic that the dataSource changes accordingly. Before changing, the work related to the db is terminated, but for some reason, a crash occurs.

Expected behavior

Don't occur crash

Actual behavior

Occur crash

Code

Code
@HiltViewModel
class HiddenSettingsViewModel @Inject constructor(
    private val stopCcuCommUseCase: StopCcuCommUseCase,
    private val testModeManager: TestModeManager,
    private val workCcuCommUseCase: WorkCcuCommUseCase,
    private val initializeLinkTableItemsUseCase: InitializeLinkTableItemsUseCase,
    private val removeTestModeItemsUseCase: RemoveTestModeItemsUseCase,
    private val stopTestCcuCommUseCase: StopTestCcuCommUseCase,
    private val workTestCcuCommUseCase: WorkTestCcuCommUseCase,
    private val stopMakeOutputRequestUseCase: StopMakeOutputRequestUseCase,
    private val workMakeOutputRequestUseCase: WorkMakeOutputRequestUseCase
): ViewModel() {

    private val _testModeStateFlow = MutableStateFlow(
        if (testModeManager.isTestMode) TestModeState.TestMode else TestModeState.NormalMode
    )
    val testModeStateFlow: StateFlow<TestModeState> = _testModeStateFlow

    private val _isTestMode = MutableStateFlow(testModeManager.isTestMode)
    val isTestMode: StateFlow<Boolean> = _isTestMode

    fun setTestMode(enabled: Boolean) {
        viewModelScope.launch {
            _testModeStateFlow.value = TestModeState.Loading
            try {
                stopMakeOutputRequestUseCase()
                workMakeOutputRequestUseCase()
                if (enabled) {
                    when (initializeLinkTableItemsUseCase()) {
                        is LinkTableRepositoryState.Success -> {
                            stopCcuCommUseCase()
                            workTestCcuCommUseCase()
                            _testModeStateFlow.value = TestModeState.TestMode
                            testModeManager.setTestMode(true)
                            _isTestMode.value = testModeManager.isTestMode
                        }
                        is LinkTableRepositoryState.InsertError -> {
                            _testModeStateFlow.value = TestModeState.Error
                            testModeManager.setTestMode(false)
                            _isTestMode.value = testModeManager.isTestMode
                        }
                    }
                } else {
                    stopTestCcuCommUseCase()
                    removeTestModeItemsUseCase()
                    workCcuCommUseCase()
                    _testModeStateFlow.value = TestModeState.NormalMode
                    testModeManager.setTestMode(false)
                    _isTestMode.value = testModeManager.isTestMode
                }
            } catch (e: Exception) {
                _testModeStateFlow.value = TestModeState.Error
                testModeManager.setTestMode(!enabled)
                _isTestMode.value = testModeManager.isTestMode
            }
        }
    }
}

Class CcuCommRepositoryImpl @Inject constructor(
    @IoDispatcher private val ioDispatcher: CoroutineDispatcher,
    @DefaultDispatcher private val defaultDispatcher: CoroutineDispatcher,
    private val allBox: AllBox,
    private val repeaterBox: RepeaterBox,
    private val detectorBox: DetectorBox,
    private val serialPortManager: SerialPortManager
) : CcuCommRepository {

override fun commProcess() {
        val serialPort0 = serialPortManager.serialPort0 ?: return
        val serialPort1 = serialPortManager.serialPort1 ?: return
        val serialPort3 = serialPortManager.serialPort3 ?: return

        if (ioScope == null || ioScope?.isActive == false) {
            ioScope = CoroutineScope(ioDispatcher + SupervisorJob())
        }
        if (defaultScope == null || defaultScope?.isActive == false) {
            defaultScope = CoroutineScope(defaultDispatcher + SupervisorJob())
        }

        defaultScope?.let { scope ->
            startMakeResponseByte(scope)
            workParsing(scope, requestBufferChannels)
        }
                                    .
                                    .
                                    .
}
                   .
                   .
                   .
override fun stop() {
        ioScope?.cancel()
        defaultScope?.cancel()
        ioScope = null
        defaultScope = null
    }
}

class AllBoxImpl @Inject constructor(
    @Impermanence private val impermanenceInternalCommBox: Box<InternalCommEntity>,
    @Impermanence private val impermanenceStationCommBox: Box<StationCommEntity>,
    @Impermanence private val impermanenceStationPowerBox: Box<StationPowerEntity>,
    @Impermanence private val impermanenceCcuBox: Box<CcuEntity>,
    @Impermanence private val impermanenceDetectorBox: Box<DetectorEntity>,
    @Impermanence private val impermanenceRepeaterBox: Box<RepeaterEntity>,
    @Impermanence private val impermanenceRepeaterInputBox: Box<RepeaterInputEntity>,
    @Impermanence private val impermanenceRepeaterOutputBox: Box<RepeaterOutputEntity>,
    @TestMode private val testModeInternalCommBox: Box<InternalCommEntity>,
    @TestMode private val testModeStationCommBox: Box<StationCommEntity>,
    @TestMode private val testModeStationPowerBox: Box<StationPowerEntity>,
    @TestMode private val testModeCcuBox: Box<CcuEntity>,
    @TestMode private val testModeDetectorBox: Box<DetectorEntity>,
    @TestMode private val testModeRepeaterBox: Box<RepeaterEntity>,
    @TestMode private val testModeRepeaterInputBox: Box<RepeaterInputEntity>,
    @TestMode private val testModeRepeaterOutputBox: Box<RepeaterOutputEntity>,
    private val switchBox: Box<SwitchEntity>,
    private val switchBoardBox: Box<SwitchBoardEntity>,
    private val pumpBox: Box<PumpEntity>,
    private val pumpBoardBox: Box<PumpBoardEntity>,
    private val mccRelayBox: Box<MccRelayEntity>,
    private val broadcastRelayBox: Box<BroadcastRelayEntity>,
    private val ebcBox: Box<EbcEntity>,
    private val do24Box: Box<Do24Entity>,
    private val tbBox: Box<TbEntity>,
    @IoDispatcher private val ioDispatcher: CoroutineDispatcher,
) : AllBox {

    private val internalCommQueryByInternalCommIds =
        impermanenceInternalCommBox.query().inValues(InternalCommEntity_.internalCommId, longArrayOf()).build()
    private val stationPowerQueryByStationId =
        impermanenceStationPowerBox.query().inValues(StationPowerEntity_.stationId, longArrayOf()).build()
    private val stationCommQueryByStationId =
        impermanenceStationCommBox.query().inValues(StationCommEntity_.stationId, longArrayOf()).build()
    private val ccuQueryByFullCompositeKeys = impermanenceCcuBox.query().inValues(
        CcuEntity_.fullCompositeKey,
        arrayOf(), QueryBuilder.StringOrder.CASE_INSENSITIVE
    ).build()
    private val detectorQueryByFullCompositeKeys = impermanenceDetectorBox.query().inValues(
        DetectorEntity_.fullCompositeKey,
        arrayOf(),
        QueryBuilder.StringOrder.CASE_INSENSITIVE
    ).build()
    private val repeaterQueryByFullCompositeKeys = impermanenceRepeaterBox.query().inValues(
        RepeaterEntity_.fullCompositeKey,
        arrayOf(),
        QueryBuilder.StringOrder.CASE_INSENSITIVE
    ).eager(RepeaterEntity_.inputs).eager(RepeaterEntity_.outputs).build()

    override suspend fun addAllInstances(
        internalCommInstances: List<InternalCommEntity>,
        stationCommInstances: List<StationCommEntity>,
        stationPowerInstances: List<StationPowerEntity>,
        ccuInstances: List<CcuEntity>,
        detectorInstances: List<DetectorEntity>,
        repeaterInstances: List<RepeaterEntity>,
        repeaterInputInstances: List<RepeaterInputEntity>,
        repeaterOutputInstances: List<RepeaterOutputEntity>,
    ) = withContext(ioDispatcher) {
        impermanenceInternalCommBox.store.runInTxAsync({
            impermanenceInternalCommBox.put(internalCommInstances)
            impermanenceStationCommBox.put(stationCommInstances)
            impermanenceStationPowerBox.put(stationPowerInstances)
            impermanenceCcuBox.put(ccuInstances)
            impermanenceDetectorBox.put(detectorInstances)
            impermanenceRepeaterInputBox.put(repeaterInputInstances)
            impermanenceRepeaterOutputBox.put(repeaterOutputInstances)
            impermanenceRepeaterBox.put(repeaterInstances)
        }, null)
        impermanenceInternalCommBox.store.closeThreadResources()
    }
    
    override suspend fun getAllInstances(
        internalCommIds: LongArray,
        stationIds: LongArray,
        ccuFullCompositeKeys: Array<String>,
        deviceFullCompositeKeys: Array<String>,
    ): AllInstances = withContext(ioDispatcher) {
        var result: AllInstances? = null
        impermanenceInternalCommBox.store.runInReadTx {
            val internalComms = internalCommQueryByInternalCommIds.copy()
                .setParameter(InternalCommEntity_.internalCommId, internalCommIds).find()
            val stationComms = stationCommQueryByStationId.copy()
                .setParameter(StationCommEntity_.stationId, stationIds).find()
            val stationPowers = stationPowerQueryByStationId.copy()
                .setParameter(StationPowerEntity_.stationId, stationIds).find()
            val ccus = ccuQueryByFullCompositeKeys.copy()
                .setParameter(CcuEntity_.fullCompositeKey, ccuFullCompositeKeys).find()
            val detectors = detectorQueryByFullCompositeKeys.copy()
                .setParameter(DetectorEntity_.fullCompositeKey, deviceFullCompositeKeys).find()
            val repeaters = repeaterQueryByFullCompositeKeys.copy()
                .setParameter(RepeaterEntity_.fullCompositeKey, deviceFullCompositeKeys).find()
            result =
                AllInstances(internalComms, stationComms, stationPowers, ccus, detectors, repeaters)
        }
        result ?: throw IllegalStateException("Transaction failed to return result")
    }
}

Log

Logs crash1 crash2 crash3

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions