Skip to content

Commit

Permalink
Massive refactor of the Android invalidation code.
Browse files Browse the repository at this point in the history
We want the invalidations code to exist as a component
independent of sync (see bug). This CL seeks to move toward
that for the Android invalidations codebase.

Generally, things moved from //chrome/browser/invalidation
to //components/invalidation, even if git didn't mark them
as moves.

To accomplish this, I had to unify where the JNI occurred.
In Java, InvalidationService was renamed to
InvalidationClientService as the class that communicates
with GCM.

A new InvalidationService class was introduced to handle JNI
and other Java entry points to the component. Several
methods from ProfileSyncService and InvalidationController
moved to it.

InvalidationController is now the bridge between sync and
the invalidation component, and has no JNI nor C++
counterpart.

InvalidationServiceFactory was added to assist in the
creation and management of InvalidationService objects
across the JNI boundary.

BUG=259559

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

Cr-Commit-Position: refs/heads/master@{#297202}
  • Loading branch information
maxbogue authored and Commit bot committed Sep 29, 2014
1 parent 1c629b0 commit b8d6efc
Show file tree
Hide file tree
Showing 42 changed files with 868 additions and 694 deletions.
1 change: 1 addition & 0 deletions chrome/android/DEPS
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
include_rules = [
"+components/invalidation",
"+jni",
]
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,11 @@

import org.chromium.base.ApplicationState;
import org.chromium.base.ApplicationStatus;
import org.chromium.base.CalledByNative;
import org.chromium.base.VisibleForTesting;
import org.chromium.components.invalidation.InvalidationClientService;
import org.chromium.sync.internal_api.pub.base.ModelType;
import org.chromium.sync.notifier.InvalidationClientNameProvider;
import org.chromium.sync.notifier.InvalidationIntentProtocol;
import org.chromium.sync.notifier.InvalidationPreferences;
import org.chromium.sync.notifier.InvalidationService;
import org.chromium.sync.notifier.SyncStatusHelper;

import java.util.Set;
Expand All @@ -42,7 +40,7 @@ public class InvalidationController implements ApplicationStatus.ApplicationStat
public void setRegisteredTypes(Account account, boolean allTypes, Set<ModelType> types) {
Intent registerIntent =
InvalidationIntentProtocol.createRegisterIntent(account, allTypes, types);
registerIntent.setClass(mContext, InvalidationService.class);
registerIntent.setClass(mContext, InvalidationClientService.class);
mContext.startService(registerIntent);
}

Expand All @@ -62,37 +60,19 @@ public void refreshRegisteredTypes(Set<ModelType> types) {
setRegisteredTypes(account, allTypes, types);
}

/**
* Sets object ids for which the client should register for notification. This is intended for
* registering non-Sync types; Sync types are registered with {@code setRegisteredTypes}.
*
* @param objectSources The sources of the objects.
* @param objectNames The names of the objects.
*/
@CalledByNative
public void setRegisteredObjectIds(int[] objectSources, String[] objectNames) {
InvalidationPreferences invalidationPreferences = new InvalidationPreferences(mContext);
Account account = invalidationPreferences.getSavedSyncedAccount();
Intent registerIntent =
InvalidationIntentProtocol.createRegisterIntent(
account, objectSources, objectNames);
registerIntent.setClass(mContext, InvalidationService.class);
mContext.startService(registerIntent);
}

/**
* Starts the invalidation client.
*/
public void start() {
Intent intent = new Intent(mContext, InvalidationService.class);
Intent intent = new Intent(mContext, InvalidationClientService.class);
mContext.startService(intent);
}

/**
* Stops the invalidation client.
*/
public void stop() {
Intent intent = new Intent(mContext, InvalidationService.class);
Intent intent = new Intent(mContext, InvalidationClientService.class);
intent.putExtra(InvalidationIntentProtocol.EXTRA_STOP, true);
mContext.startService(intent);
}
Expand All @@ -102,7 +82,6 @@ public void stop() {
*
* Calling this method will create the instance if it does not yet exist.
*/
@CalledByNative
public static InvalidationController get(Context context) {
synchronized (LOCK) {
if (sInstance == null) {
Expand Down Expand Up @@ -133,16 +112,4 @@ public void onApplicationStateChange(int newState) {
}
}
}

/**
* Fetches the Invalidator client name.
*
* Note that there is a naming discrepancy here. In C++, we refer to the invalidation client
* identifier that is unique for every invalidation client instance in an account as the client
* ID. In Java, we call it the client name.
*/
@CalledByNative
public byte[] getInvalidatorClientId() {
return InvalidationClientNameProvider.get().getInvalidatorClientName();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright 2014 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.chrome.browser.invalidation;

import android.content.Context;

import org.chromium.base.JNINamespace;
import org.chromium.base.ThreadUtils;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.components.invalidation.InvalidationService;

import java.util.HashMap;
import java.util.Map;

/**
* InvalidationServiceFactory maps Profiles to instances of
* {@link InvalidationService} instances. Each {@link Profile} will at most
* have one instance of this service. If the service does not already exist,
* it will be created on the first access.
*/
@JNINamespace("invalidation")
public final class InvalidationServiceFactory {

private static final Map<Profile, InvalidationService> sServiceMap =
new HashMap<Profile, InvalidationService>();

private InvalidationServiceFactory() {}

/**
* Returns Java InvalidationService for the given Profile.
*/
public static InvalidationService getForProfile(Profile profile) {
ThreadUtils.assertOnUiThread();
InvalidationService service = sServiceMap.get(profile);
if (service == null) {
service = nativeGetForProfile(profile);
sServiceMap.put(profile, service);
}
return service;
}

public static InvalidationService getForTest(Context context) {
return nativeGetForTest(context);
}

private static native InvalidationService nativeGetForProfile(Profile profile);
private static native InvalidationService nativeGetForTest(Context context);
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
import org.chromium.base.ThreadUtils;
import org.chromium.base.VisibleForTesting;
import org.chromium.base.library_loader.ProcessInitException;
import org.chromium.chrome.browser.invalidation.InvalidationServiceFactory;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.content.browser.BrowserStartupController;

import java.util.concurrent.Semaphore;
Expand Down Expand Up @@ -167,12 +169,13 @@ public void onFailure() {

@VisibleForTesting
public void requestSync(int objectSource, String objectId, long version, String payload) {
ProfileSyncService.get(mApplication)
InvalidationServiceFactory.getForProfile(Profile.getLastUsedProfile())
.requestSyncFromNativeChrome(objectSource, objectId, version, payload);
}

@VisibleForTesting
public void requestSyncForAllTypes() {
ProfileSyncService.get(mApplication).requestSyncFromNativeChromeForAllTypes();
InvalidationServiceFactory.getForProfile(Profile.getLastUsedProfile())
.requestSyncFromNativeChromeForAllTypes();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import org.chromium.base.ThreadUtils;
import org.chromium.base.VisibleForTesting;
import org.chromium.chrome.browser.identity.UniqueIdentificationGenerator;
import org.chromium.chrome.browser.invalidation.InvalidationServiceFactory;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.sync.internal_api.pub.SyncDecryptionPassphraseType;
import org.chromium.sync.internal_api.pub.base.ModelType;

Expand All @@ -35,8 +37,11 @@
*/
public class ProfileSyncService {

/**
* Listener for the underlying sync status.
*/
public interface SyncStateChangedListener {
// Invoked when the underlying sync status has changed.
// Invoked when the status has changed.
public void syncStateChanged();
}

Expand Down Expand Up @@ -138,25 +143,13 @@ public void syncSignInWithAuthToken(String account, String authToken) {
syncSignIn(account);
}

public void requestSyncFromNativeChrome(
int objectSource, String objectId, long version, String payload) {
ThreadUtils.assertOnUiThread();
nativeNudgeSyncer(
mNativeProfileSyncServiceAndroid, objectSource, objectId, version, payload);
}

// TODO(maxbogue): Remove once downstream use is removed. See http://crbug.com/259559.
// Callers should use InvalidationService.requestSyncFromNativeChromeForAllTypes() instead.
@Deprecated
public void requestSyncFromNativeChromeForAllTypes() {
ThreadUtils.assertOnUiThread();
nativeNudgeSyncerForAllTypes(mNativeProfileSyncServiceAndroid);
}

/**
* Nudge the syncer to start a new sync cycle.
*/
@VisibleForTesting
public void requestSyncCycleForTest() {
ThreadUtils.assertOnUiThread();
requestSyncFromNativeChromeForAllTypes();
InvalidationServiceFactory.getForProfile(Profile.getLastUsedProfile())
.requestSyncFromNativeChromeForAllTypes();
}

public String querySyncStatus() {
Expand Down Expand Up @@ -545,10 +538,6 @@ private static String modelTypeSelectionToStringForTest(long modelTypeSelection)
}

// Native methods
private native void nativeNudgeSyncer(
long nativeProfileSyncServiceAndroid, int objectSource, String objectId, long version,
String payload);
private native void nativeNudgeSyncerForAllTypes(long nativeProfileSyncServiceAndroid);
private native long nativeInit();
private native void nativeEnableSync(long nativeProfileSyncServiceAndroid);
private native void nativeDisableSync(long nativeProfileSyncServiceAndroid);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright 2014 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.chrome.browser.invalidation;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;

import org.chromium.base.test.util.AdvancedMockContext;

import java.util.ArrayList;
import java.util.List;

/**
* Mock context that saves all intents given to {@code startService}.
*/
public class IntentSavingContext extends AdvancedMockContext {
private final List<Intent> mStartedIntents = new ArrayList<Intent>();

IntentSavingContext(Context targetContext) {
super(targetContext);
}

@Override
public ComponentName startService(Intent intent) {
mStartedIntents.add(intent);
return new ComponentName(this, getClass());
}

int getNumStartedIntents() {
return mStartedIntents.size();
}

Intent getStartedIntent(int idx) {
return mStartedIntents.get(idx);
}

@Override
public PackageManager getPackageManager() {
return getBaseContext().getPackageManager();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,19 @@

import android.accounts.Account;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.test.InstrumentationTestCase;
import android.test.suitebuilder.annotation.SmallTest;

import com.google.ipc.invalidation.external.client.types.ObjectId;

import org.chromium.base.ActivityState;
import org.chromium.base.ApplicationState;
import org.chromium.base.ApplicationStatus;
import org.chromium.base.CollectionUtil;
import org.chromium.base.test.util.AdvancedMockContext;
import org.chromium.base.test.util.Feature;
import org.chromium.components.invalidation.InvalidationClientService;
import org.chromium.sync.internal_api.pub.base.ModelType;
import org.chromium.sync.notifier.InvalidationIntentProtocol;
import org.chromium.sync.notifier.InvalidationPreferences;
import org.chromium.sync.notifier.InvalidationService;
import org.chromium.sync.notifier.SyncStatusHelper;
import org.chromium.sync.signin.AccountManagerHelper;
import org.chromium.sync.signin.ChromeSigninController;
Expand Down Expand Up @@ -288,67 +282,13 @@ public void setRegisteredTypes(
assertEquals(true, resultAllTypes.get());
}

@SmallTest
@Feature({"Sync"})
public void testSetRegisteredObjectIds() {
InvalidationController controller = new InvalidationController(mContext);
ObjectId bookmark = ModelType.BOOKMARK.toObjectId();
controller.setRegisteredObjectIds(new int[] {1, 2, bookmark.getSource()},
new String[] {"a", "b", new String(bookmark.getName())});
assertEquals(1, mContext.getNumStartedIntents());

// Validate destination.
Intent intent = mContext.getStartedIntent(0);
validateIntentComponent(intent);
assertEquals(InvalidationIntentProtocol.ACTION_REGISTER, intent.getAction());

// Validate registered object ids. The bookmark object should not be registered since it is
// a Sync type.
assertNull(intent.getStringArrayListExtra(
InvalidationIntentProtocol.EXTRA_REGISTERED_TYPES));
Set<ObjectId> objectIds = InvalidationIntentProtocol.getRegisteredObjectIds(intent);
assertEquals(2, objectIds.size());
assertTrue(objectIds.contains(ObjectId.newInstance(1, "a".getBytes())));
assertTrue(objectIds.contains(ObjectId.newInstance(2, "b".getBytes())));
}

/**
* Asserts that {@code intent} is destined for the correct component.
*/
private static void validateIntentComponent(Intent intent) {
assertNotNull(intent.getComponent());
assertEquals(InvalidationService.class.getName(),
assertEquals(InvalidationClientService.class.getName(),
intent.getComponent().getClassName());
}

/**
* Mock context that saves all intents given to {@code startService}.
*/
private static class IntentSavingContext extends AdvancedMockContext {
private final List<Intent> mStartedIntents = new ArrayList<Intent>();

IntentSavingContext(Context targetContext) {
super(targetContext);
}

@Override
public ComponentName startService(Intent intent) {
mStartedIntents.add(intent);
return new ComponentName(this, getClass());
}

int getNumStartedIntents() {
return mStartedIntents.size();
}

Intent getStartedIntent(int idx) {
return mStartedIntents.get(idx);
}

@Override
public PackageManager getPackageManager() {
return getBaseContext().getPackageManager();
}
}

}
Loading

0 comments on commit b8d6efc

Please sign in to comment.