Fix synchronization issue with android notification#21
Fix synchronization issue with android notification#21thomasttvo wants to merge 22 commits intomasterfrom
Conversation
| NoWifi, NoInternet, Ok; | ||
|
|
||
| companion object { | ||
| fun fetch(context: Context, wifiOnly: Boolean): Connectivity { |
There was a problem hiding this comment.
moved from UploadWorker.ts no logical change
| } | ||
|
|
||
| // builds the notification required to enable Foreground mode | ||
| fun build(context: Context): Notification { |
There was a problem hiding this comment.
moved from UploadWorker.ts. Not much has changed except for val wifiOnly = getActiveUpload()?.wifiOnly ?: false
| if (this.activeUpload?.id == upload.id) this.activeUpload = null | ||
| } | ||
|
|
||
| fun setOptions(opts: ReadableMap) { |
There was a problem hiding this comment.
these options are moved over from the Upload class, so they are now global options instead of per-Upload options
| setProgress(undefined); | ||
| console.log('Upload error!', err); | ||
| }); | ||
| for (let i = 0; i < 100; i++) { |
There was a problem hiding this comment.
Can we add a comment explaining the magic number 100 and why we have to perform Upload.startUpload 100 times?
There was a problem hiding this comment.
ah this is just the test app, but it's good to add a comment still
- Name response variable in use block (UploadUtils.kt) - Fix shadowed it in takeIf lambda (UploadUtils.kt) - Rename set() to setIfNotNull() (UploadProgress.kt) - Add complete() method to Progress class (UploadProgress.kt) - Rename clearIfNeeded() to clearIfCompleted() (UploadProgress.kt) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
|
bugbot run |
Ensures the notification shows correct "Waiting for WiFi/Internet" title when network degrades after initial foreground setup. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
cbc41c0 to
c2c9922
Compare
|
bugbot run |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
Comment @cursor review or bugbot run to trigger another review on this PR
| channel = opts.getString("notificationChannel") | ||
| ?: throw MissingOptionException("notificationChannel") | ||
| maxRetries = if (opts.hasKey("maxRetries")) opts.getInt("maxRetries") else 5 | ||
| } |
There was a problem hiding this comment.
Thread-safety gap in setOptions vs concurrent readers
Medium Severity
The setOptions() method writes to shared properties (id, title, channel, maxRetries, etc.) without @Synchronized, while build(), getForegroundInfo(), and checkRetry() read these properties from background worker threads. This creates a race condition where a worker resuming from a previous session could call build() while setOptions() is executing, resulting in inconsistent notification content (e.g., old channel ID paired with new title). Other methods in UploadNotification that access activeUpload are correctly synchronized, but this synchronization pattern isn't applied to the configuration properties.
Additional Locations (1)
| val url: String, | ||
| val path: String, | ||
| val method: String, | ||
| val maxRetries: Int, |
There was a problem hiding this comment.
Resumed workers use uninitialized notification settings after app restart
Medium Severity
The notification settings (notificationChannel, notificationId, etc.) were removed from the Upload class, so they're no longer serialized with WorkManager input data. When workers resume after an app restart (process death), they depend on UploadNotification singleton state which hasn't been initialized yet—initialize() is called by JS code that may not have executed. The worker uses the default channel "File Uploads" which likely doesn't exist, causing the foreground notification to fail. This could result in missing notifications or setForeground() failures that prevent the worker from running properly.
Fixes notification race condition where queued uploads could overwrite the active upload's notification settings. The bug occurred because each Upload object carried its own notification config—when a Wi-Fi-only upload was queued while a regular upload was running, the queued upload could touch the shared system notification and apply its wifiOnly=true preference before actually executing.
Centralization solves this by making UploadNotification the single source of truth for notification state. It tracks exactly one activeUpload at a time (synchronized), and notification content is built by reading getActiveUpload()?.wifiOnly rather than arbitrary upload configs. Queued uploads can exist in memory with their settings, but they can't affect the notification until they call setActiveUpload() when they start executing. This eliminates the race condition—only the actively running upload determines what the user sees.
Test Plan:
Note
Android notification handling consolidated and race fixed
UploadNotificationsingleton andConnectivity.fetchto build/update a single foreground notification reflecting active upload or queue needs (WiFi vs internet), with sharedmaxRetriesUpload; addsinitialize(options)to set global notification config (JS/types updated)UploadWorkerto use centralized notification/ connectivity, mark active upload, and update notification on progress/success/error; retries now use globalmaxRetriesUploadProgressto trackwifiOnlyand exposehasNonWifiOnlyUploads()for accurate notification messagesUpload.initializeand starts multiple uploads; bumps package to7.6.0Written by Cursor Bugbot for commit c2c9922. Configure here.