Page MenuHomePhabricator

Schedule blob deletion on Android when large notifications arrives
ClosedPublic

Authored by marcin on Sep 1 2023, 9:35 AM.
Tags
None
Referenced Files
F3562063: D9069.id38942.diff
Fri, Dec 27, 9:44 AM
F3562062: D9069.id38938.diff
Fri, Dec 27, 9:44 AM
F3562060: D9069.id38931.diff
Fri, Dec 27, 9:44 AM
F3562059: D9069.id38930.diff
Fri, Dec 27, 9:44 AM
F3562058: D9069.id38923.diff
Fri, Dec 27, 9:44 AM
F3562057: D9069.id38781.diff
Fri, Dec 27, 9:44 AM
F3562055: D9069.id38190.diff
Fri, Dec 27, 9:44 AM
F3562054: D9069.id38188.diff
Fri, Dec 27, 9:43 AM
Subscribers

Details

Summary

This differential schedules blob deletion on background thread when large notification (notification containing metadata to an item on blob service) arrives. Deletion scheduling is implemented using WorkManager framework - native Android
library that handles persistence, optimal scheduling and retry policy of background tasks out of the box.

Test Plan
  1. Launch blob service locally
  2. Build android app substituting blob service URL in relevant places
  3. Send large notification (ex. 7000 'x' characters) to the device.
  4. Observe in blob service terminal that 30s after logging GET request, DELETE request is logged and reported successfull.
  5. Build the app again but change the line 38 of DeleteBlobWork.java to sth like "blobhash" (incorrect JSON structure).
  6. Send large notification (ex. 7000 'x' characters) to the device.
  7. Observe in blob service terminal that 30s after logging GET request, DELETE request is logged and reported unsuccessfull.
  8. Finally observe that DELETE request is retried several time - each time after longer period of time but don't wait for the final 10 retry since it will take 17 hours (retries are scheduled according to exponential backoff)

Additionally:

  1. Add line that logs blob holder when deletion is scheduled.
  2. Deploy the app to two different Android devices and send large notification.
  3. Open the app on each device and using console app ensure that each of them logs different holder.

Diff Detail

Repository
rCOMM Comm
Lint
Lint Not Applicable
Unit
Tests Not Applicable

Event Timeline

native/android/app/src/main/java/app/comm/android/notifications/CommAndroidNotificationsBlobServiceClient.java
35 ↗(On Diff #30707)

I think it is nice not to have private and public variables mixed in subsequent lines so I moved this line here.

95 ↗(On Diff #30707)

This enables us to schedule blob deletion upfront as soon as notification arrives. GET request already has time limit of 15 seconds so we can safely schedule blob deletion with 15 seconds delay as soon as notif arrives.

native/android/app/src/main/java/app/comm/android/notifications/DeleteBlobWork.java
18 ↗(On Diff #30707)

According to: https://stackoverflow.com/questions/58433063/android-worker-class-as-nested-class it is impossible to have this class as private class in CommAndroidNotificationsBlobServiceClient without some serious workaround. However it still needs access to shared instance of OkHttpClient so it was made public.

20 ↗(On Diff #30707)

This will take apprx. 17 hours to reach max number of retries assuming that each attempt fails: https://developer.android.com/guide/background/persistent/getting-started/define-work#retries_backoff

22 ↗(On Diff #30707)

We can't pass OkHttpClient as parameters since it only accepts easily serializable types: https://developer.android.com/reference/androidx/work/WorkerParameters

70 ↗(On Diff #30707)

This call is synchronous since all WorkManager tasks are executed on background threads.

I decided to add @kamil and @michal as reviewers since they are working on backup service and this introduces framework that is very strong candidate to implement backup protocol on Android with.

Looks good!

I'm wondering if the new deps change the bundle size significantly.

native/android/app/build.gradle
713–714 ↗(On Diff #30708)

It isn't specified as optional in the docs, but I'm wondering if we need it

native/android/app/src/main/java/app/comm/android/notifications/CommAndroidNotificationsBlobServiceClient.java
35 ↗(On Diff #30707)

We can consider keeping it private and exposing a newCall method of it as a new method of CommAndroidNotificationsBlobServiceClient. Then in DeleteBlobWork we could simply call

Response response =
          CommAndroidNotificationsBlobServiceClient.newCall(request)
              .execute();
95 ↗(On Diff #30707)

Can we instead schedule without a delay just after the download completes? Which option is better?

This revision is now accepted and ready to land.Sep 6 2023, 2:44 AM
native/android/app/build.gradle
713–714 ↗(On Diff #30708)

I will check.

native/android/app/src/main/java/app/comm/android/notifications/CommAndroidNotificationsBlobServiceClient.java
95 ↗(On Diff #30707)

My idea was that scheduling deletion with delay first is safer since if sth fails during the download part and the app crashes then we don't lose the ability to issue delete requests. It is possible that the crash occurs even before scheduling deletion, so we are not 100% safe - we just increase safety by scheduling deletion upfront.

I checked our app .apk file size twice: first time on a parent commit to this one and second time on this commit. In between I uninstalled the app and executed ./gradlew clean. My results are below:
Parent commit:

Screenshot 2023-09-11 at 15.53.25.png (244×869 px, 54 KB)

This commit:
Screenshot 2023-09-11 at 16.06.04.png (239×874 px, 70 KB)

So we probably have already had guava in some other dependency since the size in MB didn't change at all. However please correct my if my method of checking the size was wrong.

Remove unnecessary Kotlin WorkManager dependency

New dependency seems fine

tomek requested changes to this revision.EditedMar 22 2024, 9:37 AM

When creating a blob, we're setting one holder for the content. Then we send the same hash and holder to multiple recipients. After the processing, the recipient schedules blob deletion which means that other recipients may be unable to download the blob - as it is already deleted.

Shouldn't we have a separate holder for each recipient?

This revision now requires changes to proceed.Mar 22 2024, 9:37 AM

Send different holder to each recipient device

This revision is now accepted and ready to land.Apr 8 2024, 6:45 AM

Address Tomek suggestions

  1. Avoid using let instead of const.

Bring lines accidentally removed during conflict resolution

Check CI - last results confusing