Skip to content

Commit

Permalink
[BackgroundSync] Launch the browser on Android when next online
Browse files Browse the repository at this point in the history
On Android devices BackgroundSync needs to launch the browser the next time the device goes online if a one-shot sync is registered. This CL adds an Android Receiver and Service (BackgroundSyncLauncherService) to listen to connectvity events and launch the browser. It also provides a BackgroundSyncLauncher JNI class that C++ can interact with to register interest in launching in the background.

This feature is experimental and behind a flag.

Note that the components_tests.gyp change (to add content_java) is because content::StoragePartition creates a BackgroundSyncManager which immediately talks to java therefore the content java classes are needed for testing.

BUG=479665

Review URL: https://codereview.chromium.org/1140813006

Cr-Commit-Position: refs/heads/master@{#331826}
  • Loading branch information
jkarlin authored and Commit bot committed May 28, 2015
1 parent 5fc6422 commit 6970b0a
Show file tree
Hide file tree
Showing 19 changed files with 584 additions and 0 deletions.
9 changes: 9 additions & 0 deletions chrome/android/java_staging/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,15 @@ by a child template that "extends" this file.
</intent-filter>
</receiver>

<!-- Service Worker Background Sync service listener -->
<service android:name="org.chromium.content.browser.BackgroundSyncLauncherService"
android:exported="false" />
<receiver android:name="org.chromium.content.browser.BackgroundSyncLauncherService$Receiver">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>

<service android:name="org.chromium.chrome.browser.prerender.ChromePrerenderService"
android:exported="true"
tools:ignore="ExportedService" />
Expand Down
9 changes: 9 additions & 0 deletions chrome/android/shell/java/AndroidManifest.xml.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,15 @@
</intent-filter>
</receiver>

<!-- Service Worker Background Sync service listener -->
<service android:name="org.chromium.content.browser.BackgroundSyncLauncherService"
android:exported="false" />
<receiver android:name="org.chromium.content.browser.BackgroundSyncLauncherService$Receiver">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>

<provider android:name="org.chromium.chrome.browser.ChromeBrowserProvider"
android:authorities="org.chromium.chrome.shell"
android:exported="true" />
Expand Down
4 changes: 4 additions & 0 deletions components/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,10 @@ test("components_unittests") {
]
data_deps = [ ":components_tests_pak" ]

if (is_android) {
deps += [ "//content/public/android:content_java" ]
}

if (!is_android && !is_ios) {
deps += [ "//components/proximity_auth:unit_tests" ]
}
Expand Down
1 change: 1 addition & 0 deletions components/components_tests.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -1028,6 +1028,7 @@
'dependencies': [
'components.gyp:cronet_static',
'components.gyp:data_reduction_proxy_content',
'../content/content.gyp:content_java',
'../testing/android/native_test.gyp:native_test_native_code',
],
'dependencies!': [
Expand Down
73 changes: 73 additions & 0 deletions content/browser/android/background_sync_launcher_android.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/browser/android/background_sync_launcher_android.h"

#include "content/public/browser/browser_thread.h"
#include "jni/BackgroundSyncLauncher_jni.h"

namespace content {

namespace {
base::LazyInstance<BackgroundSyncLauncherAndroid> g_background_sync_launcher =
LAZY_INSTANCE_INITIALIZER;
}

// static
BackgroundSyncLauncherAndroid* BackgroundSyncLauncherAndroid::Get() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);

return g_background_sync_launcher.Pointer();
}

// static
void BackgroundSyncLauncherAndroid::LaunchBrowserWhenNextOnline(
const BackgroundSyncManager* registrant,
bool launch_when_next_online) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);

Get()->LaunchBrowserWhenNextOnlineImpl(registrant, launch_when_next_online);
}

void BackgroundSyncLauncherAndroid::LaunchBrowserWhenNextOnlineImpl(
const BackgroundSyncManager* registrant,
bool launch_when_next_online) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);

bool was_launching = !launch_when_next_online_registrants_.empty();

if (launch_when_next_online)
launch_when_next_online_registrants_.insert(registrant);
else
launch_when_next_online_registrants_.erase(registrant);

bool now_launching = !launch_when_next_online_registrants_.empty();
if (was_launching != now_launching) {
JNIEnv* env = base::android::AttachCurrentThread();
Java_BackgroundSyncLauncher_setLaunchWhenNextOnline(
env, java_launcher_.obj(), now_launching);
}
}

// static
bool BackgroundSyncLauncherAndroid::RegisterLauncher(JNIEnv* env) {
return RegisterNativesImpl(env);
}

BackgroundSyncLauncherAndroid::BackgroundSyncLauncherAndroid() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);

JNIEnv* env = base::android::AttachCurrentThread();
java_launcher_.Reset(Java_BackgroundSyncLauncher_create(
env, base::android::GetApplicationContext()));
}

BackgroundSyncLauncherAndroid::~BackgroundSyncLauncherAndroid() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);

JNIEnv* env = base::android::AttachCurrentThread();
Java_BackgroundSyncLauncher_destroy(env, java_launcher_.obj());
}

} // namespace content
57 changes: 57 additions & 0 deletions content/browser/android/background_sync_launcher_android.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CONTENT_BROWSER_ANDROID_BACKGROUND_SYNC_LAUNCHER_ANDROID_H_
#define CONTENT_BROWSER_ANDROID_BACKGROUND_SYNC_LAUNCHER_ANDROID_H_

#include <set>

#include "base/android/jni_android.h"
#include "base/lazy_instance.h"
#include "base/macros.h"
#include "content/common/content_export.h"

namespace content {

class BackgroundSyncManager;

// 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
// thread.
class CONTENT_EXPORT BackgroundSyncLauncherAndroid {
public:
static BackgroundSyncLauncherAndroid* Get();

// Register the |registrant|'s interest (or disinterest) in starting the
// browser the next time the device goes online after the browser has closed.
// |registrant| is used to count the number of interested objects and is not
// accessed, therefore it is okay for |registrant| to be deleted before this
// class. Interest is reset the next time the BackgroundSyncLauncherAndroid is
// created (browser restart). The caller can remove interest in launching the
// browser by calling with |launch_when_next_online| set to false.
static void LaunchBrowserWhenNextOnline(
const BackgroundSyncManager* registrant,
bool launch_when_next_online);

static bool RegisterLauncher(JNIEnv* env);

private:
friend struct base::DefaultLazyInstanceTraits<BackgroundSyncLauncherAndroid>;

// Constructor and destructor marked private to enforce singleton
BackgroundSyncLauncherAndroid();
~BackgroundSyncLauncherAndroid();

void LaunchBrowserWhenNextOnlineImpl(const BackgroundSyncManager* registrant,
bool launch_when_next_online);

std::set<const BackgroundSyncManager*> launch_when_next_online_registrants_;
base::android::ScopedJavaGlobalRef<jobject> java_launcher_;
DISALLOW_COPY_AND_ASSIGN(BackgroundSyncLauncherAndroid);
};

} // namespace content

#endif // CONTENT_BROWSER_ANDROID_BACKGROUND_SYNC_LAUNCHER_ANDROID_H_
3 changes: 3 additions & 0 deletions content/browser/android/browser_jni_registrar.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "base/android/jni_registrar.h"
#include "content/browser/accessibility/browser_accessibility_android.h"
#include "content/browser/accessibility/browser_accessibility_manager_android.h"
#include "content/browser/android/background_sync_launcher_android.h"
#include "content/browser/android/browser_startup_controller.h"
#include "content/browser/android/child_process_launcher_android.h"
#include "content/browser/android/composited_touch_handle_drawable.h"
Expand Down Expand Up @@ -45,6 +46,8 @@ namespace {
base::android::RegistrationMethod kContentRegisteredMethods[] = {
{"AndroidLocationApiAdapter",
content::AndroidLocationApiAdapter::RegisterGeolocationService},
{"BackgroundSyncLauncherAndroid",
content::BackgroundSyncLauncherAndroid::RegisterLauncher},
{"BrowserAccessibilityManager",
content::RegisterBrowserAccessibilityManager},
{"BrowserStartupController", content::RegisterBrowserStartupController},
Expand Down
38 changes: 38 additions & 0 deletions content/browser/background_sync/background_sync_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
#include "content/browser/service_worker/service_worker_storage.h"
#include "content/public/browser/browser_thread.h"

#if defined(OS_ANDROID)
#include "content/browser/android/background_sync_launcher_android.h"
#endif

namespace {
const char kBackgroundSyncUserDataKey[] = "BackgroundSyncUserData";
}
Expand Down Expand Up @@ -642,6 +646,38 @@ bool BackgroundSyncManager::IsRegistrationReadyToFire(
return network_observer_->NetworkSufficient(registration.network_state);
}

void BackgroundSyncManager::SchedulePendingRegistrations() {
bool keep_browser_alive_for_one_shot = false;

for (const auto& sw_id_and_registrations : sw_to_registrations_map_) {
for (const auto& key_and_registration :
sw_id_and_registrations.second.registration_map) {
const BackgroundSyncRegistration& registration =
key_and_registration.second;
if (registration.sync_state == SYNC_STATE_PENDING) {
if (registration.periodicity == SYNC_ONE_SHOT) {
keep_browser_alive_for_one_shot = true;
} else {
// TODO(jkarlin): Support keeping the browser alive for periodic
// syncs.
}
}
}
}

#if defined OS_ANDROID
// TODO(jkarlin): Use the context's path instead of the 'this' pointer as an
// identifier. See crbug.com/489705.
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&BackgroundSyncLauncherAndroid::LaunchBrowserWhenNextOnline,
this, keep_browser_alive_for_one_shot));
#else

// TODO(jkarlin): Toggle Chrome's background mode.
#endif
}

void BackgroundSyncManager::FireReadyEvents() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);

Expand Down Expand Up @@ -696,6 +732,8 @@ void BackgroundSyncManager::FireReadyEventsImpl(const base::Closure& callback) {
weak_ptr_factory_.GetWeakPtr(), sw_id_and_key.second,
registration->id, barrier_closure));
}

SchedulePendingRegistrations();
}

void BackgroundSyncManager::FireReadyEventsDidFindRegistration(
Expand Down
6 changes: 6 additions & 0 deletions content/browser/background_sync/background_sync_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,12 @@ class CONTENT_EXPORT BackgroundSyncManager
bool IsRegistrationReadyToFire(
const BackgroundSyncRegistration& registration);

// Schedules pending registrations to run in the future. For one-shots this
// means keeping the browser alive so that network connectivity events can be
// seen (on Android the browser is instead woken up the next time it goes
// online). For periodic syncs this means creating an alarm.
void SchedulePendingRegistrations();

// FireReadyEvents and callbacks
void FireReadyEvents();
void FireReadyEventsImpl(const base::Closure& callback);
Expand Down
1 change: 1 addition & 0 deletions content/content.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,7 @@
'../ui/android/ui_android.gyp:ui_java',
'../ui/touch_selection/ui_touch_selection.gyp:selection_event_type_java',
'../ui/touch_selection/ui_touch_selection.gyp:touch_handle_orientation_java',
'../third_party/android_tools/android_tools.gyp:android_support_v13_javalib',
'../third_party/WebKit/public/blink_headers.gyp:blink_headers_java',
'common_aidl',
'console_message_level_java',
Expand Down
2 changes: 2 additions & 0 deletions content/content_browser.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,8 @@
'browser/accessibility/one_shot_accessibility_tree_search.cc',
'browser/accessibility/one_shot_accessibility_tree_search.h',
'browser/android/animation_utils.h',
'browser/android/background_sync_launcher_android.cc',
'browser/android/background_sync_launcher_android.h',
'browser/android/browser_jni_registrar.cc',
'browser/android/browser_jni_registrar.h',
'browser/android/browser_startup_controller.cc',
Expand Down
1 change: 1 addition & 0 deletions content/content_jni.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
'public/android/java/src/org/chromium/content/app/ChildProcessService.java',
'public/android/java/src/org/chromium/content/app/ContentMain.java',
'public/android/java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityManager.java',
'public/android/java/src/org/chromium/content/browser/BackgroundSyncLauncher.java',
'public/android/java/src/org/chromium/content/browser/BrowserStartupController.java',
'public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java',
'public/android/java/src/org/chromium/content/browser/ContentReadbackHandler.java',
Expand Down
1 change: 1 addition & 0 deletions content/public/android/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ android_library("content_java") {
"//media/midi:midi_java",
"//mojo/android:system_java",
"//net/android:net_java",
"//third_party/android_tools:android_support_v13_java",
"//third_party/mojo/src/mojo/public/java:bindings",
"//third_party/mojo/src/mojo/public/java:system",
"//ui/android:ui_java",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.content.browser;

import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;

import org.chromium.base.CalledByNative;
import org.chromium.base.JNINamespace;
import org.chromium.base.VisibleForTesting;

/**
* The {@link BackgroundSyncLauncher} singleton is created and owned by the C++ browser. It
* registers interest in waking up the browser the next time the device goes online after the
*browser closes via the {@link #setLaunchWhenNextOnline} method.
*
* Thread model: This class is to be run on the UI thread only.
*/
@JNINamespace("content")
public class BackgroundSyncLauncher {
static final String PREF_BACKGROUND_SYNC_LAUNCH_NEXT_ONLINE = "bgsync_launch_next_online";

// The instance of BackgroundSyncLauncher currently owned by a C++
// BackgroundSyncLauncherAndroid, if any. If it is non-null then the browser is running.
private static BackgroundSyncLauncher sInstance;

private final SharedPreferences mSharedPreferences;

/**
* Create a BackgroundSyncLauncher object, which is owned by C++.
* @param context The app context.
*/
@VisibleForTesting
@CalledByNative
protected static BackgroundSyncLauncher create(Context context) {
if (sInstance != null) {
throw new IllegalStateException("Already instantiated");
}

sInstance = new BackgroundSyncLauncher(context);
return sInstance;
}

/**
* Called when the C++ counterpart is deleted.
*/
@VisibleForTesting
@CalledByNative
protected void destroy() {
assert sInstance == this;
sInstance = null;
}

/**
* Set interest (or disinterest) in launching the browser the next time the device goes online
* after the browser closes. On creation of the {@link BackgroundSyncLauncher} class (on browser
* start) this value is reset to false.
*/
@VisibleForTesting
@CalledByNative
protected void setLaunchWhenNextOnline(boolean shouldLaunch) {
mSharedPreferences.edit()
.putBoolean(PREF_BACKGROUND_SYNC_LAUNCH_NEXT_ONLINE, shouldLaunch)
.apply();
}

/**
* Returns whether the browser should be launched when the device next goes online.
* This is set by C++ and reset to false each time {@link BackgroundSyncLauncher}'s singleton is
* created (the native browser is started).
* @param sharedPreferences The shared preferences.
*/
protected static boolean shouldLaunchWhenNextOnline(SharedPreferences sharedPreferences) {
return sharedPreferences.getBoolean(PREF_BACKGROUND_SYNC_LAUNCH_NEXT_ONLINE, false);
}

/**
* True if the native browser has started and created an instance of {@link
* BackgroundSyncLauncher}.
*/
protected static boolean hasInstance() {
return sInstance != null;
}

private BackgroundSyncLauncher(Context context) {
mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
setLaunchWhenNextOnline(false);
}
}
Loading

0 comments on commit 6970b0a

Please sign in to comment.