feat. multi process - #4
Conversation
There was a problem hiding this comment.
Code Review
This pull request configures several services to run in a separate ":engine" process and updates the Room database and DataStore instances to support multi-process access. The review feedback highlights critical issues in the new multi-process DataStore implementations, including a compilation error due to referencing the internal "PreferencesFileSerializer", missing "@volatile" annotations on the "INSTANCE" variables for double-checked locking, and unsafe synchronization on a framework class instead of a private lock object.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| private var INSTANCE: DataStore<ConfigItem>? = null | ||
|
|
||
| val Context.configDataStore: DataStore<ConfigItem> | ||
| get() = INSTANCE ?: synchronized(MultiProcessDataStoreFactory::class.java) { | ||
| INSTANCE ?: MultiProcessDataStoreFactory.create( | ||
| serializer = ConfigItemSerializer, | ||
| produceFile = { this.applicationContext.dataStoreFile("config.json") } | ||
| ).also { INSTANCE = it } | ||
| } |
There was a problem hiding this comment.
Concurrency & Thread Safety Issues
- Missing
@Volatile: TheINSTANCEvariable is used in a double-checked locking pattern but is not marked as@Volatile. Without this, writes toINSTANCEmight not be immediately visible to other threads, or the compiler/CPU might reorder instructions, leading to another thread reading a partially initializedINSTANCE. - Locking on a Framework Class: Locking on
MultiProcessDataStoreFactory::class.javais not recommended. It is a framework class, and locking on it can lead to unexpected contention or deadlocks if other parts of the app or libraries also lock on it. Use a private lock object instead.
| private var INSTANCE: DataStore<ConfigItem>? = null | |
| val Context.configDataStore: DataStore<ConfigItem> | |
| get() = INSTANCE ?: synchronized(MultiProcessDataStoreFactory::class.java) { | |
| INSTANCE ?: MultiProcessDataStoreFactory.create( | |
| serializer = ConfigItemSerializer, | |
| produceFile = { this.applicationContext.dataStoreFile("config.json") } | |
| ).also { INSTANCE = it } | |
| } | |
| @Volatile | |
| private var INSTANCE: DataStore<ConfigItem>? = null | |
| private val lock = Any() | |
| val Context.configDataStore: DataStore<ConfigItem> | |
| get() = INSTANCE ?: synchronized(lock) { | |
| INSTANCE ?: MultiProcessDataStoreFactory.create( | |
| serializer = ConfigItemSerializer, | |
| produceFile = { this.applicationContext.dataStoreFile("config.json") } | |
| ).also { INSTANCE = it } | |
| } |
| private var INSTANCE: DataStore<Preferences>? = null | ||
|
|
||
| val Context.preferencesDataStore: DataStore<Preferences> | ||
| get() = INSTANCE ?: synchronized(MultiProcessDataStoreFactory::class.java) { | ||
| INSTANCE ?: MultiProcessDataStoreFactory.create( | ||
| serializer = PreferencesFileSerializer, | ||
| produceFile = { | ||
| this.applicationContext.dataStoreFile("config.preferences_pb") | ||
| } | ||
| ).also { INSTANCE = it } | ||
| } No newline at end of file |
There was a problem hiding this comment.
Compilation & Concurrency Issues
- Compilation Error (
PreferencesFileSerializeris internal):PreferencesFileSerializeris aninternalobject in theandroidx.datastore.preferences.corepackage. Referencing it directly here will cause a compilation error. To resolve this, you can copy the implementation ofPreferencesFileSerializerinto your project or implement a custom serializer forPreferences. - Missing
@Volatile: TheINSTANCEvariable is used in a double-checked locking pattern but is not marked as@Volatile. - Locking on a Framework Class: Locking on
MultiProcessDataStoreFactory::class.javais not recommended. Use a private lock object instead.
| private var INSTANCE: DataStore<Preferences>? = null | |
| val Context.preferencesDataStore: DataStore<Preferences> | |
| get() = INSTANCE ?: synchronized(MultiProcessDataStoreFactory::class.java) { | |
| INSTANCE ?: MultiProcessDataStoreFactory.create( | |
| serializer = PreferencesFileSerializer, | |
| produceFile = { | |
| this.applicationContext.dataStoreFile("config.preferences_pb") | |
| } | |
| ).also { INSTANCE = it } | |
| } | |
| @Volatile | |
| private var INSTANCE: DataStore<Preferences>? = null | |
| private val lock = Any() | |
| val Context.preferencesDataStore: DataStore<Preferences> | |
| get() = INSTANCE ?: synchronized(lock) { | |
| INSTANCE ?: MultiProcessDataStoreFactory.create( | |
| serializer = PreferencesFileSerializer, | |
| produceFile = { | |
| this.applicationContext.dataStoreFile("config.preferences_pb") | |
| } | |
| ).also { INSTANCE = it } | |
| } |
No description provided.