[Background Sync] Allow native processing to finish

sending any pending Background Sync events, before exiting the
background task that woke up the browser.

Bug: 924490
Change-Id: Id63b2d9edeb6e9255dff616ea06f02c9f77cc0d3
Reviewed-on: https://chromium-review.googlesource.com/c/1477707
Commit-Queue: Mugdha Lakhani <[email protected]>
Reviewed-by: Peter Beverloo <[email protected]>
Reviewed-by: Rayan Kanso <[email protected]>
Reviewed-by: Dmitry Gozman <[email protected]>
Reviewed-by: David Trainor <[email protected]>
Cr-Commit-Position: refs/heads/master@{#636034}
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 76b498f..59b230c 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -4918,6 +4918,7 @@
       "../android/java/src/org/chromium/chrome/browser/autofill_assistant/overlay/AssistantOverlayModel.java",
       "../android/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestDelegate.java",
       "../android/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestModel.java",
+      "../android/java/src/org/chromium/chrome/browser/background_sync/BackgroundSyncBackgroundTask.java",
       "../android/java/src/org/chromium/chrome/browser/background_sync/BackgroundSyncBackgroundTaskScheduler.java",
       "../android/java/src/org/chromium/chrome/browser/banners/AppBannerManager.java",
       "../android/java/src/org/chromium/chrome/browser/banners/AppBannerUiDelegateAndroid.java",
diff --git a/chrome/browser/android/background_sync_launcher_android.cc b/chrome/browser/android/background_sync_launcher_android.cc
index 7b182c6..8eaedf25 100644
--- a/chrome/browser/android/background_sync_launcher_android.cc
+++ b/chrome/browser/android/background_sync_launcher_android.cc
@@ -4,10 +4,19 @@
 
 #include "chrome/browser/android/background_sync_launcher_android.h"
 
+#include <utility>
+
+#include "base/android/callback_android.h"
+#include "base/barrier_closure.h"
 #include "base/feature_list.h"
 #include "chrome/browser/android/chrome_feature_list.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "content/public/browser/background_sync_context.h"
+#include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/storage_partition.h"
 #include "jni/BackgroundSyncBackgroundTaskScheduler_jni.h"
+#include "jni/BackgroundSyncBackgroundTask_jni.h"
 #include "jni/BackgroundSyncLauncher_jni.h"
 
 using content::BrowserThread;
@@ -24,6 +33,18 @@
 }  // namespace
 
 // static
+void JNI_BackgroundSyncBackgroundTask_FireBackgroundSyncEvents(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& j_runnable) {
+  if (!base::FeatureList::IsEnabled(
+          chrome::android::kBackgroundTaskSchedulerForBackgroundSync)) {
+    return;
+  }
+
+  BackgroundSyncLauncherAndroid::Get()->FireBackgroundSyncEvents(j_runnable);
+}
+
+// static
 BackgroundSyncLauncherAndroid* BackgroundSyncLauncherAndroid::Get() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
@@ -39,6 +60,22 @@
   Get()->LaunchBrowserIfStoppedImpl(launch_when_next_online, min_delay_ms);
 }
 
+// static
+void BackgroundSyncLauncherAndroid::SetPlayServicesVersionCheckDisabledForTests(
+    bool disabled) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  disable_play_services_version_check_for_tests = disabled;
+}
+
+// static
+bool BackgroundSyncLauncherAndroid::ShouldDisableBackgroundSync() {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  if (disable_play_services_version_check_for_tests)
+    return false;
+  return Java_BackgroundSyncLauncher_shouldDisableBackgroundSync(
+      base::android::AttachCurrentThread());
+}
+
 void BackgroundSyncLauncherAndroid::LaunchBrowserIfStoppedImpl(
     bool launch_when_next_online,
     int64_t min_delay_ms) {
@@ -59,21 +96,57 @@
       launch_when_next_online, min_delay_ms);
 }
 
-// static
-void BackgroundSyncLauncherAndroid::SetPlayServicesVersionCheckDisabledForTests(
-    bool disabled) {
+void BackgroundSyncLauncherAndroid::FireBackgroundSyncEvents(
+    const base::android::JavaParamRef<jobject>& j_runnable) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  disable_play_services_version_check_for_tests = disabled;
+
+  auto* profile = ProfileManager::GetLastUsedProfile();
+  DCHECK(profile);
+
+  int num_partitions = 0;
+  content::BrowserContext::ForEachStoragePartition(
+      profile, base::BindRepeating(
+                   [](int* num_partitions,
+                      content::StoragePartition* storage_partition) {
+                     (*num_partitions)++;
+                   },
+                   &num_partitions));
+
+  // This class is a singleton, which is only destructed on program exit.
+  // Therefore, use of base::Unretained(this) is safe.
+  base::RepeatingClosure done_closure = base::BarrierClosure(
+      num_partitions,
+      base::BindOnce(base::android::RunRunnableAndroid,
+                     base::android::ScopedJavaGlobalRef<jobject>(j_runnable)));
+
+  content::BrowserContext::ForEachStoragePartition(
+      profile,
+      base::BindRepeating(&BackgroundSyncLauncherAndroid::
+                              FireBackgroundSyncEventsForStoragePartition,
+                          base::Unretained(this), done_closure));
 }
 
-// static
-bool BackgroundSyncLauncherAndroid::ShouldDisableBackgroundSync() {
+void BackgroundSyncLauncherAndroid::FireBackgroundSyncEventsForStoragePartition(
+    base::OnceClosure done_closure,
+    content::StoragePartition* storage_partition) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  if (disable_play_services_version_check_for_tests) {
-    return false;
+
+  content::BackgroundSyncContext* sync_context =
+      storage_partition->GetBackgroundSyncContext();
+  if (!sync_context) {
+    std::move(done_closure).Run();
+    return;
   }
-  return Java_BackgroundSyncLauncher_shouldDisableBackgroundSync(
-      base::android::AttachCurrentThread());
+
+  sync_context->FireBackgroundSyncEventsForStoragePartition(
+      storage_partition, std::move(done_closure));
+}
+
+void BackgroundSyncLauncherAndroid::OnFiredBackgroundSyncEvents(
+    base::android::ScopedJavaGlobalRef<jobject> j_runnable) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  base::android::RunRunnableAndroid(j_runnable);
 }
 
 BackgroundSyncLauncherAndroid::BackgroundSyncLauncherAndroid() {
diff --git a/chrome/browser/android/background_sync_launcher_android.h b/chrome/browser/android/background_sync_launcher_android.h
index 0c93da7..1afb9bae 100644
--- a/chrome/browser/android/background_sync_launcher_android.h
+++ b/chrome/browser/android/background_sync_launcher_android.h
@@ -10,9 +10,14 @@
 #include <set>
 
 #include "base/android/jni_android.h"
+#include "base/callback_forward.h"
 #include "base/lazy_instance.h"
 #include "base/macros.h"
 
+namespace content {
+class StoragePartition;
+}  // namespace content
+
 // The BackgroundSyncLauncherAndroid singleton owns the Java
 // BackgroundSyncLauncher object and is used to register interest in starting
 // the browser the next time the device goes online. This class runs on the UI
@@ -30,6 +35,11 @@
   // updated before every test run. (https://crbug.com/514449)
   static void SetPlayServicesVersionCheckDisabledForTests(bool disabled);
 
+  // Fires all pending Background Sync events across all storage partitions
+  // for the last used profile.
+  void FireBackgroundSyncEvents(
+      const base::android::JavaParamRef<jobject>& j_runnable);
+
  private:
   friend struct base::LazyInstanceTraitsBase<BackgroundSyncLauncherAndroid>;
 
@@ -39,11 +49,17 @@
 
   void LaunchBrowserIfStoppedImpl(bool launch_when_next_online,
                                   int64_t min_delay_ms);
+  void FireBackgroundSyncEventsForStoragePartition(
+      base::OnceClosure done_closure,
+      content::StoragePartition* storage_partition);
+  void OnFiredBackgroundSyncEvents(
+      base::android::ScopedJavaGlobalRef<jobject> j_runnable);
 
   base::android::ScopedJavaGlobalRef<jobject>
       java_gcm_network_manager_launcher_;
   base::android::ScopedJavaGlobalRef<jobject>
       java_background_sync_background_task_scheduler_launcher_;
+
   DISALLOW_COPY_AND_ASSIGN(BackgroundSyncLauncherAndroid);
 };