Repository navigation
fix: bound the preferences custom modules may read from the host app - #939
Conversation
The configuration's custom module settings name a SharedPreferences file and the keys to read from it, and the SDK uploads the values it finds. Nothing limited which keys could be named, so the configuration could read any preference the host app keeps, and it also chose the mode the file was opened with. The SDK now reads only the Adobe Mobile Services identifiers custom modules were built to carry, matching the Apple SDK. A host app can allow more keys with MParticleOptions.Builder.customModulePreferenceKeys or stop the SDK reading them with collectCustomModulePreferences(false). A key outside the allowed set is neither read nor cached, and is logged. Preference files are always opened in private mode. When the SDK starts itself to handle a push message, it does not know the host app's options, so it reads no custom module preferences in that process. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Kotlin migration progress
Conversion progress: 0.0% (16,728 of 16,550 baseline Java LOC left to convert). 132 Java files and 36 Kotlin files in scope. |
Binary compatibility
Compares the release AAR against the same artifact at the last version published to Maven Central; R8-renamed classes and members are excluded (see the script docstring). Full japicmp HTML/XML reports are attached as the |
📦 SDK Size Impact ReportWhat the SDK adds to a minified release APK. mParticle Core SDKMeasured against an empty baseline app. Unlike the Rokt kit, android-core ships no Compose and no resources, so there is nothing here that a host app would already provide.
mParticle Core + Rokt kitMeasured against a Compose + Material3 reference app, so these are the costs on top of an app that already ships Compose. The reference app's dependencies are a documented convention, not a measured average: see
Rokt SDK+ umbrella (adds the payment extension)
➡️ SDK size impact change is minimal. Raw measurementscore, Target branch: {"baseline_dex_bytes": 0, "baseline_download_bytes": 2513, "baseline_install_bytes": 7529, "core_dex_bytes": 219692, "core_download_bytes": 123460, "core_install_bytes": 130712}core, This PR: {"baseline_dex_bytes": 0, "baseline_download_bytes": 2516, "baseline_install_bytes": 7533, "core_dex_bytes": 220412, "core_download_bytes": 123802, "core_install_bytes": 131052}rokt, Target branch: {"baseline_dex_bytes": 1829108, "baseline_download_bytes": 1240062, "baseline_install_bytes": 1300934, "kit_dex_bytes": 4163396, "kit_download_bytes": 2544133, "kit_install_bytes": 2623275, "sdkplus_dex_bytes": 9284332, "sdkplus_download_bytes": 7981260, "sdkplus_install_bytes": 8165359}rokt, This PR: {"baseline_dex_bytes": 1829108, "baseline_download_bytes": 1240062, "baseline_install_bytes": 1300934, "kit_dex_bytes": 4164084, "kit_download_bytes": 2544400, "kit_install_bytes": 2623275, "sdkplus_dex_bytes": 9285024, "sdkplus_download_bytes": 7982298, "sdkplus_install_bytes": 8165359} |
The Adobe Mobile Services SDK keeps install date, last-used date and launches under ADMS_InstallDate, ADMS_LastDateUsed and ADMS_Launches on Android, and under OMCK1, OMCK5 and OMCK6 on iOS. The default set of custom module preference keys copied the Apple SDK's and so had only the iOS names. Add the Android names, and keep the iOS names so a configuration shared with iOS still resolves those keys as before. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Why
The SDK's remote settings can name one of the host app's saved preference files and the keys to read from it, and the SDK uploads whatever values it finds. Nothing limited which keys could be named, so the settings could collect any preference an app stores, such as a sign-in token, and could also choose how the file was opened. Once this lands, the SDK reads only the Adobe values the feature was built to carry, plus any key the app itself allows, and an app can turn the feature off. The Apple SDK made the same change.
Programme
Standalone fix, no programme.
What changes
Before: custom module settings could read any key from any preference file they named, apart from the SDK's own files, which mParticle/mparticle-android-sdk#922 blocked. The file was opened with whatever mode the settings gave.
After:
ADB_LIFETIME_VALUE,ADOBEMOBILE_STOREDDEFAULTS_AIDandAPP_MEASUREMENT_VISITOR_ID, plus install date, last-used date and launches under both their Android names (ADMS_InstallDate,ADMS_LastDateUsed,ADMS_Launches) and their iOS names (OMCK1,OMCK5,OMCK6); any other key is neither read nor cached, and each one ignored is loggedMParticleOptions.Builder.customModulePreferenceKeys(List<String>)lets an app allow more keysMParticleOptions.Builder.collectCustomModulePreferences(false)stops the SDK reading preferences for custom modules at all; it defaults totruemfield, the file mode, is now ignored; the unusedKEY_PERSISTENCE_MODEconstant is removed with it. A mode taken from the configuration could make a file world-readable or world-writeable in apps targeting an API level below 24, and in apps targeting 24 or higher those modes throw, so reading fails. Reading another SDK's preferences never needs more than private mode. Configurations that sendmkeep working because the field is ignored, and one withoutmno longer fails to load.Start reading at
ProviderPersistence, and check first that a disallowed key is skipped before its cachedmp::value is read or written. Deliberately left alone: for an allowed key, the cached copy is still stored in the named file, so values already cached on devices keep working. The API dump gains four additive lines onMParticleOptions, a frozen contract, so this needs theapi-change-approvedlabel after API review. No documentation or changelog change is needed; the release notes are generated from the commit message.Linked work
Related: mParticle/mparticle-apple-sdk#1053, the same change in the Apple SDK, whose option names this matches; its default keys are the iOS names, and the Android names come from the Adobe SDK's own record of where it stores them, in adobe/aepsdk-core-android; mParticle/mparticle-android-sdk#922, which blocked the SDK's own preference files.
Rollout
Path: merging changes
mainonly. The fix ships in the next release ofandroid-core, and apps get it when they upgrade. It is live as soon as an app runs that release, with no ordering constraint.Feature flags: none. Apps control the behaviour with the two new options above.
Turning it off: an app that needs another key allows it with
customModulePreferenceKeys, in its own next build. Otherwise, revert this pull request and publish a new release. A published version cannot be recalled, so apps on the release that carries it keep the change until they upgrade again.What we watch: nothing monitors this path. We watch the issues reported on this repository after the release that carries it, and the
Unit Tests,Lint ChecksandKotlin Lint Checksjobs on this pull request.Risks
customModulePreferenceKeys, and the SDK logs each key it ignorescustomModulePreferenceKeysRisk class: medium, because it adds public API and changes what the SDK reads by default.
Who
Written by: an automated coding agent (Claude Code), working for a maintainer who asked for this fix.
Code reviewed before opening: an independent review agent, 14 October 2026; it found that the push-message start-up path ignored an app's opt-out, which is fixed here, and nothing else blocking.
Design reviewed before opening: no one; the design follows the Apple SDK's change.
Decision this implements: a maintainer's request on 14 October 2026; there is no public record.
Checked: the
ConfigManagerTestcases for these settings, where the allowed-keys case fails when the key check is disabled and another reads the Android lifecycle keys, aMParticleOptionsTestcase for the push-message start-up path, plus theandroid-coreunit tests,apiCheck,ktlintCheckandlint, on 14 October 2026.Not checked: a configuration without
m, which follows from the code but has no test; the instrumented tests; the private open mode on a device, because the unit-test context ignores the mode; and settings served to a real app.Size
Hand-written: 187 lines changed (added plus removed) in 5 files.
Generated: 1 file, listed below.
For the record
Generated:
android-core/api/android-core.api, by./gradlew apiDump.Hand-written:
MParticleOptions.java,ConfigManager.java,ProviderPersistence.java,ConfigManagerTest.kt,MParticleOptionsTest.kt.🤖 Generated with Claude Code