Commit 5bcb5287 authored by Tanja Gornak's avatar Tanja Gornak Committed by Commit Bot

[Tango->FCM] Make lazyness work for the new invalidations

Currently messages are not persisted for the FCM invalidations, because
the sender id for which invaliations are marked lazy mismatches the id
received in the incoming messages. In addition, messages are replayed
before app handler is knows, so they aren't passed to it.

This patch implements the fix.

Bug: 882887, 944484
Change-Id: I6f53d65488f196f76dedc0b8ae23f9889d5c13a5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1533875Reviewed-by: default avatarMikel Astiz <mastiz@chromium.org>
Reviewed-by: default avatarPeter Beverloo <peter@chromium.org>
Commit-Queue: Tatiana Gornak <melandory@chromium.org>
Cr-Commit-Position: refs/heads/master@{#644773}
parent 0d13d015
...@@ -53,22 +53,38 @@ public class GCMDriver { ...@@ -53,22 +53,38 @@ public class GCMDriver {
throw new IllegalStateException("Already instantiated"); throw new IllegalStateException("Already instantiated");
} }
sInstance = new GCMDriver(nativeGCMDriverAndroid); sInstance = new GCMDriver(nativeGCMDriverAndroid);
// Don't bother to read the stored messages unless there are actually return sInstance;
// messages persisted on disk. Calling }
// LazySubscriptionsManager.hasPersistedMessages() should be a cheap way
// to avoid unnecessary disk reads. /**
* Called when our C++ counterpart is deleted. Clear the handle to our
* native C++ object, ensuring it's never called.
*/
@CalledByNative
private void destroy() {
assert sInstance == this;
sInstance = null;
mNativeGCMDriverAndroid = 0;
}
@CalledByNative
private void replayPersistedMessages(final String appId) {
if (LazySubscriptionsManager.hasPersistedMessages()) { if (LazySubscriptionsManager.hasPersistedMessages()) {
long time = SystemClock.elapsedRealtime(); long time = SystemClock.elapsedRealtime();
Set<String> lazySubscriptionIds = LazySubscriptionsManager.getLazySubscriptionIds(); Set<String> lazySubscriptionIds = LazySubscriptionsManager.getLazySubscriptionIds();
boolean hasRemainingMessages = false;
for (String id : lazySubscriptionIds) { for (String id : lazySubscriptionIds) {
if (!id.startsWith(appId)) {
hasRemainingMessages = (LazySubscriptionsManager.readMessages(id).length != 0);
continue;
}
GCMMessage[] messages = LazySubscriptionsManager.readMessages(id); GCMMessage[] messages = LazySubscriptionsManager.readMessages(id);
for (GCMMessage message : messages) { for (GCMMessage message : messages) {
dispatchMessage(message); dispatchMessage(message);
} }
LazySubscriptionsManager.deletePersistedMessagesForSubscriptionId(id); LazySubscriptionsManager.deletePersistedMessagesForSubscriptionId(id);
} }
LazySubscriptionsManager.storeHasPersistedMessages(/*hasPersistedMessages=*/false); LazySubscriptionsManager.storeHasPersistedMessages(hasRemainingMessages);
long duration = SystemClock.elapsedRealtime() - time; long duration = SystemClock.elapsedRealtime() - time;
// Call RecordHistogram.recordTimesHistogram() on a background thread to avoid expensive // Call RecordHistogram.recordTimesHistogram() on a background thread to avoid expensive
// JNI calls in the critical path. // JNI calls in the critical path.
...@@ -77,18 +93,6 @@ public class GCMDriver { ...@@ -77,18 +93,6 @@ public class GCMDriver {
"PushMessaging.TimeToReadPersistedMessages", duration); "PushMessaging.TimeToReadPersistedMessages", duration);
}); });
} }
return sInstance;
}
/**
* Called when our C++ counterpart is deleted. Clear the handle to our
* native C++ object, ensuring it's never called.
*/
@CalledByNative
private void destroy() {
assert sInstance == this;
sInstance = null;
mNativeGCMDriverAndroid = 0;
} }
@CalledByNative @CalledByNative
...@@ -110,8 +114,7 @@ public class GCMDriver { ...@@ -110,8 +114,7 @@ public class GCMDriver {
nativeOnRegisterFinished(mNativeGCMDriverAndroid, appId, registrationId, nativeOnRegisterFinished(mNativeGCMDriverAndroid, appId, registrationId,
!registrationId.isEmpty()); !registrationId.isEmpty());
} }
} }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} }
@CalledByNative @CalledByNative
......
...@@ -33,6 +33,8 @@ public class LazySubscriptionsManager { ...@@ -33,6 +33,8 @@ public class LazySubscriptionsManager {
private static final String HAS_PERSISTED_MESSAGES_KEY = "has_persisted_messages"; private static final String HAS_PERSISTED_MESSAGES_KEY = "has_persisted_messages";
private static final String PREF_PACKAGE = private static final String PREF_PACKAGE =
"org.chromium.components.gcm_driver.lazy_subscriptions"; "org.chromium.components.gcm_driver.lazy_subscriptions";
private static final String INVALIDATION_APP_ID = "com.google.chrome.fcm.invalidations";
private static final String INVALIDATION_SENDER_ID = "8181035976";
// The max number of most recent messages queued per lazy subscription until // The max number of most recent messages queued per lazy subscription until
// Chrome is foregrounded. // Chrome is foregrounded.
...@@ -78,7 +80,11 @@ public class LazySubscriptionsManager { ...@@ -78,7 +80,11 @@ public class LazySubscriptionsManager {
* @return The unique identifier for the subscription. * @return The unique identifier for the subscription.
*/ */
public static String buildSubscriptionUniqueId(final String appId, final String senderId) { public static String buildSubscriptionUniqueId(final String appId, final String senderId) {
return appId + senderId; if (appId.equals(INVALIDATION_APP_ID)) {
return appId + INVALIDATION_SENDER_ID;
} else {
return appId + senderId;
}
} }
/** /**
......
...@@ -123,6 +123,16 @@ void GCMDriverAndroid::OnSignedIn() { ...@@ -123,6 +123,16 @@ void GCMDriverAndroid::OnSignedIn() {
void GCMDriverAndroid::OnSignedOut() { void GCMDriverAndroid::OnSignedOut() {
} }
void GCMDriverAndroid::AddAppHandler(const std::string& app_id,
GCMAppHandler* handler) {
GCMDriver::AddAppHandler(app_id, handler);
JNIEnv* env = AttachCurrentThread();
// TODO(melandory, mamir): check if messages were persisted
// and only then go to java.
Java_GCMDriver_replayPersistedMessages(env, java_ref_,
ConvertUTF8ToJavaString(env, app_id));
}
void GCMDriverAndroid::AddConnectionObserver(GCMConnectionObserver* observer) { void GCMDriverAndroid::AddConnectionObserver(GCMConnectionObserver* observer) {
} }
......
...@@ -80,6 +80,8 @@ class GCMDriverAndroid : public GCMDriver, ...@@ -80,6 +80,8 @@ class GCMDriverAndroid : public GCMDriver,
InstanceIDHandler* GetInstanceIDHandlerInternal() override; InstanceIDHandler* GetInstanceIDHandlerInternal() override;
void AddHeartbeatInterval(const std::string& scope, int interval_ms) override; void AddHeartbeatInterval(const std::string& scope, int interval_ms) override;
void RemoveHeartbeatInterval(const std::string& scope) override; void RemoveHeartbeatInterval(const std::string& scope) override;
void AddAppHandler(const std::string& app_id,
GCMAppHandler* handler) override;
// GCMStatsRecorder::Delegate implementation: // GCMStatsRecorder::Delegate implementation:
void OnActivityRecorded() override; void OnActivityRecorded() override;
......
...@@ -50,6 +50,8 @@ void FCMInvalidationListener::Start( ...@@ -50,6 +50,8 @@ void FCMInvalidationListener::Start(
base::BindRepeating(&FCMInvalidationListener::InformTokenReceived, base::BindRepeating(&FCMInvalidationListener::InformTokenReceived,
weak_factory_.GetWeakPtr())); weak_factory_.GetWeakPtr()));
subscription_channel_state_ = SubscriptionChannelState::ENABLED; subscription_channel_state_ = SubscriptionChannelState::ENABLED;
network_channel_->StartListening();
EmitStateChange(); EmitStateChange();
DoRegistrationUpdate(); DoRegistrationUpdate();
} }
...@@ -192,6 +194,7 @@ void FCMInvalidationListener::Stop() { ...@@ -192,6 +194,7 @@ void FCMInvalidationListener::Stop() {
per_user_topic_registration_manager_->RemoveObserver(this); per_user_topic_registration_manager_->RemoveObserver(this);
} }
per_user_topic_registration_manager_.reset(); per_user_topic_registration_manager_.reset();
network_channel_->StopListening();
subscription_channel_state_ = SubscriptionChannelState::NOT_STARTED; subscription_channel_state_ = SubscriptionChannelState::NOT_STARTED;
fcm_network_state_ = FcmChannelState::NOT_STARTED; fcm_network_state_ = FcmChannelState::NOT_STARTED;
......
...@@ -38,6 +38,12 @@ const char kPayload2[] = "payload2"; ...@@ -38,6 +38,12 @@ const char kPayload2[] = "payload2";
const int64_t kVersion1 = 1LL; const int64_t kVersion1 = 1LL;
const int64_t kVersion2 = 2LL; const int64_t kVersion2 = 2LL;
class TestFCMSyncNetworkChannel : public FCMSyncNetworkChannel {
public:
void StartListening() override {}
void StopListening() override {}
};
// Fake delegate that keeps track of invalidation counts, payloads, // Fake delegate that keeps track of invalidation counts, payloads,
// and state. // and state.
class FakeDelegate : public FCMInvalidationListener::Delegate { class FakeDelegate : public FCMInvalidationListener::Delegate {
...@@ -173,7 +179,7 @@ class FCMInvalidationListenerTest : public testing::Test { ...@@ -173,7 +179,7 @@ class FCMInvalidationListenerTest : public testing::Test {
kPreferencesTopic_("PREFERENCE"), kPreferencesTopic_("PREFERENCE"),
kExtensionsTopic_("EXTENSION"), kExtensionsTopic_("EXTENSION"),
kAppsTopic_("APP"), kAppsTopic_("APP"),
fcm_sync_network_channel_(new FCMSyncNetworkChannel()), fcm_sync_network_channel_(new TestFCMSyncNetworkChannel()),
listener_(base::WrapUnique(fcm_sync_network_channel_)), listener_(base::WrapUnique(fcm_sync_network_channel_)),
fake_delegate_(&listener_) {} fake_delegate_(&listener_) {}
......
...@@ -239,12 +239,13 @@ void FCMInvalidationService::StartInvalidator() { ...@@ -239,12 +239,13 @@ void FCMInvalidationService::StartInvalidator() {
// We should start listening before requesting the id, because // We should start listening before requesting the id, because
// valid id is only generated, once there is an app handler // valid id is only generated, once there is an app handler
// for the app. StartListening registers the app handler. // for the app. StartListening registers the app handler.
network->StartListening(); // We should create invalidator first, because it registers the handler
PopulateClientID(); // for the incoming messages, which is crutial on Android, because on the
// startup cached messages might exists.
invalidator_ = std::make_unique<syncer::FCMInvalidator>( invalidator_ = std::make_unique<syncer::FCMInvalidator>(
std::move(network), identity_provider_, pref_service_, loader_factory_, std::move(network), identity_provider_, pref_service_, loader_factory_,
parse_json_, kInvalidationGCMSenderId); parse_json_, kInvalidationGCMSenderId);
PopulateClientID();
invalidator_->RegisterHandler(this); invalidator_->RegisterHandler(this);
DoUpdateRegisteredIdsIfNeeded(); DoUpdateRegisteredIdsIfNeeded();
} }
......
...@@ -28,6 +28,12 @@ namespace syncer { ...@@ -28,6 +28,12 @@ namespace syncer {
namespace { namespace {
class TestFCMSyncNetworkChannel : public FCMSyncNetworkChannel {
public:
void StartListening() override {}
void StopListening() override {}
};
class FCMInvalidatorTestDelegate { class FCMInvalidatorTestDelegate {
public: public:
FCMInvalidatorTestDelegate() { FCMInvalidatorTestDelegate() {
...@@ -41,7 +47,7 @@ class FCMInvalidatorTestDelegate { ...@@ -41,7 +47,7 @@ class FCMInvalidatorTestDelegate {
const std::string&, const std::string&,
const base::WeakPtr<InvalidationStateTracker>&) { const base::WeakPtr<InvalidationStateTracker>&) {
DCHECK(!invalidator_); DCHECK(!invalidator_);
auto network_channel = std::make_unique<FCMSyncNetworkChannel>(); auto network_channel = std::make_unique<TestFCMSyncNetworkChannel>();
identity_provider_ = identity_provider_ =
std::make_unique<invalidation::ProfileIdentityProvider>( std::make_unique<invalidation::ProfileIdentityProvider>(
identity_test_env_.identity_manager()); identity_test_env_.identity_manager());
......
...@@ -93,6 +93,9 @@ FCMNetworkHandler::~FCMNetworkHandler() { ...@@ -93,6 +93,9 @@ FCMNetworkHandler::~FCMNetworkHandler() {
} }
void FCMNetworkHandler::StartListening() { void FCMNetworkHandler::StartListening() {
if (IsListening()) {
StopListening();
}
// Adding ourselves as Handler means start listening. // Adding ourselves as Handler means start listening.
// Being the listener is pre-requirement for token operations. // Being the listener is pre-requirement for token operations.
gcm_driver_->AddAppHandler(app_id_, this); gcm_driver_->AddAppHandler(app_id_, this);
......
...@@ -66,11 +66,13 @@ class FCMNetworkHandler : public gcm::GCMAppHandler, ...@@ -66,11 +66,13 @@ class FCMNetworkHandler : public gcm::GCMAppHandler,
~FCMNetworkHandler() override; ~FCMNetworkHandler() override;
void StartListening();
void StopListening();
bool IsListening() const; bool IsListening() const;
void UpdateChannelState(FcmChannelState state); void UpdateChannelState(FcmChannelState state);
// FCMSyncNetworkChannel overrides.
void StartListening() override;
void StopListening() override;
// GCMAppHandler overrides. // GCMAppHandler overrides.
void ShutdownHandler() override; void ShutdownHandler() override;
void OnStoreReset() override; void OnStoreReset() override;
......
...@@ -31,6 +31,9 @@ class FCMSyncNetworkChannel : public NetworkChannel { ...@@ -31,6 +31,9 @@ class FCMSyncNetworkChannel : public NetworkChannel {
FCMSyncNetworkChannel(); FCMSyncNetworkChannel();
~FCMSyncNetworkChannel() override; ~FCMSyncNetworkChannel() override;
virtual void StartListening() = 0;
virtual void StopListening() = 0;
void SetMessageReceiver(MessageCallback incoming_receiver) override; void SetMessageReceiver(MessageCallback incoming_receiver) override;
void SetTokenReceiver(TokenCallback token_receiver) override; void SetTokenReceiver(TokenCallback token_receiver) override;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment