Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(339)

Unified Diff: third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/AndroidInvalidationClientImpl.java

Issue 1162033004: Pull cacheinvalidations code directory into chromium repo. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/AndroidInvalidationClientImpl.java
diff --git a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/AndroidInvalidationClientImpl.java b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/AndroidInvalidationClientImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..a6cecb1a0d3ee0c1bc4dbf4b2684e85a72126976
--- /dev/null
+++ b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/AndroidInvalidationClientImpl.java
@@ -0,0 +1,260 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.ipc.invalidation.ticl.android2;
+
+import com.google.ipc.invalidation.external.client.InvalidationClient;
+import com.google.ipc.invalidation.external.client.InvalidationListener;
+import com.google.ipc.invalidation.external.client.SystemResources;
+import com.google.ipc.invalidation.external.client.SystemResources.Logger;
+import com.google.ipc.invalidation.external.client.types.AckHandle;
+import com.google.ipc.invalidation.external.client.types.ErrorInfo;
+import com.google.ipc.invalidation.external.client.types.Invalidation;
+import com.google.ipc.invalidation.external.client.types.ObjectId;
+import com.google.ipc.invalidation.ticl.InvalidationClientCore;
+import com.google.ipc.invalidation.ticl.ProtoWrapperConverter;
+import com.google.ipc.invalidation.ticl.android2.ProtocolIntents.ListenerUpcalls;
+import com.google.ipc.invalidation.ticl.proto.AndroidService.AndroidTiclState;
+import com.google.ipc.invalidation.ticl.proto.Client.AckHandleP;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.ApplicationClientIdP;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.ClientConfigP;
+import com.google.ipc.invalidation.util.Preconditions;
+import com.google.ipc.invalidation.util.ProtoWrapper.ValidationException;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Random;
+
+
+/**
+ * Android specialization of {@link InvalidationClientCore}. Configures the internal scheduler of
+ * the provided resources with references to the recurring tasks in the Ticl and also provides
+ * an {@link InvalidationListener} instance to the Ticl that will forward upcalls to the
+ * actual application listener using {@link Intent}s.
+ * <p>
+ * This class requires that {@code SystemResources} {@code Storage} implementations be synchronous.
+ * I.e., they must invoke their callbacks inline. We require this because it is very difficult
+ * to handle asynchrony in an Android {@code IntentService}. Every async point requires marshalling
+ * the Ticl state to disk. Additionally, we must be able to resume processing where we left off;
+ * i.e., we must be able to (morally) save the value of the program counter. Intents, unlike Java
+ * callbacks, do not implicitly save the PC value, so we need to manually encode it in Intent
+ * data. This is extremely awkward, so we avoid asynchrony in the storage API.
+ *
+ */
+class AndroidInvalidationClientImpl extends InvalidationClientCore {
+ /** Class implementing the application listener stub (allows overriding default for tests). */
+ static Class<? extends Service> listenerServiceClassForTest = null;
+
+ /**
+ * {@link InvalidationListener} implementation that forwards all calls to a remote listener
+ * using Android intents.
+ */
+ static class IntentForwardingListener implements InvalidationListener {
+
+ /** Android system context. */
+ private final Context context;
+
+ /** Logger from Ticl resources. */
+ private final Logger logger;
+
+ IntentForwardingListener(Context context, Logger logger) {
+ this.context = Preconditions.checkNotNull(context);
+ this.logger = Preconditions.checkNotNull(logger);
+ }
+
+ // All calls are implemented by marshalling the arguments to an Intent and sending the Intent
+ // to the application.
+
+ @Override
+ public void ready(InvalidationClient client) {
+ issueIntent(context, ListenerUpcalls.newReadyIntent());
+ }
+
+ @Override
+ public void invalidate(InvalidationClient client, Invalidation invalidation,
+ AckHandle ackHandle) {
+ try {
+ AckHandleP ackHandleP = AckHandleP.parseFrom(ackHandle.getHandleData());
+ issueIntent(context, ListenerUpcalls.newInvalidateIntent(
+ ProtoWrapperConverter.convertToInvalidationProto(invalidation), ackHandleP));
+ } catch (ValidationException exception) {
+ // Log and drop invalid call.
+ logBadAckHandle("invalidate", ackHandle);
+ }
+ }
+
+ @Override
+ public void invalidateUnknownVersion(InvalidationClient client, ObjectId objectId,
+ AckHandle ackHandle) {
+ try {
+ AckHandleP ackHandleP = AckHandleP.parseFrom(ackHandle.getHandleData());
+ issueIntent(context, ListenerUpcalls.newInvalidateUnknownIntent(
+ ProtoWrapperConverter.convertToObjectIdProto(objectId), ackHandleP));
+ } catch (ValidationException exception) {
+ // Log and drop invalid call.
+ logBadAckHandle("invalidateUnknownVersion", ackHandle);
+ }
+ }
+
+ @Override
+ public void invalidateAll(InvalidationClient client, AckHandle ackHandle) {
+ try {
+ AckHandleP ackHandleP = AckHandleP.parseFrom(ackHandle.getHandleData());
+ issueIntent(context, ListenerUpcalls.newInvalidateAllIntent(ackHandleP));
+ } catch (ValidationException exception) {
+ // Log and drop invalid call.
+ logBadAckHandle("invalidateAll", ackHandle);
+ }
+ }
+
+ @Override
+ public void informRegistrationStatus(
+ InvalidationClient client, ObjectId objectId, RegistrationState regState) {
+ Intent intent = ListenerUpcalls.newRegistrationStatusIntent(
+ ProtoWrapperConverter.convertToObjectIdProto(objectId),
+ regState == RegistrationState.REGISTERED);
+ issueIntent(context, intent);
+ }
+
+ @Override
+ public void informRegistrationFailure(InvalidationClient client, ObjectId objectId,
+ boolean isTransient, String errorMessage) {
+ issueIntent(context, ListenerUpcalls.newRegistrationFailureIntent(
+ ProtoWrapperConverter.convertToObjectIdProto(objectId), isTransient, errorMessage));
+ }
+
+ @Override
+ public void reissueRegistrations(InvalidationClient client, byte[] prefix, int prefixLength) {
+ issueIntent(context, ListenerUpcalls.newReissueRegistrationsIntent(prefix, prefixLength));
+ }
+
+ @Override
+ public void informError(InvalidationClient client, ErrorInfo errorInfo) {
+ issueIntent(context, ListenerUpcalls.newErrorIntent(errorInfo));
+ }
+
+ /**
+ * Sends {@code intent} to the real listener via the listener intent service class.
+ */
+ static void issueIntent(Context context, Intent intent) {
+ intent.setClassName(context, (listenerServiceClassForTest != null) ?
+ listenerServiceClassForTest.getName() :
+ new AndroidTiclManifest(context).getListenerServiceClass());
+ context.startService(intent);
+ }
+
+ /**
+ * Logs a warning that a listener upcall to {@code method} has been dropped because
+ * {@code unparseableHandle} could not be parsed.
+ */
+ private void logBadAckHandle(String method, AckHandle unparseableHandle) {
+ logger.warning("Dropping call to %s; could not parse ack handle data %s",
+ method, Arrays.toString(unparseableHandle.getHandleData()));
+ }
+ }
+
+ /**
+ * Unique identifier for this Ticl. This is used to ensure that scheduler intents for other Ticls
+ * are not incorrectly delivered to this instance.
+ */
+ private final long schedulingId;
+
+ /**
+ * Creates a fresh instance.
+ *
+ * @param context Android system context
+ * @param resources Ticl resources to use
+ * @param random random number generator for the Ticl
+ * @param clientType type of the Ticl
+ * @param clientName unique application name for the Ticl
+ * @param config configuration to use
+ */
+ AndroidInvalidationClientImpl(Context context, SystemResources resources, Random random,
+ int clientType, byte[] clientName, ClientConfigP config) {
+ super(resources, random, clientType, clientName, config, getApplicationName(context),
+ new IntentForwardingListener(context, resources.getLogger()));
+ this.schedulingId = resources.getInternalScheduler().getCurrentTimeMs();
+ resources.getLogger().fine("Create new Ticl scheduling id: %s", schedulingId);
+ initializeSchedulerWithRecurringTasks();
+ }
+
+ /**
+ * Creates an instance with state restored from {@code marshalledState}. Other parameters are as
+ * in {@link InvalidationClientCore}.
+ */
+ AndroidInvalidationClientImpl(Context context, SystemResources resources, Random random,
+ AndroidTiclState marshalledState) {
+ super(resources,
+ random,
+ marshalledState.getMetadata().getClientType(),
+ marshalledState.getMetadata().getClientName().getByteArray(),
+ marshalledState.getMetadata().getClientConfig(),
+ getApplicationName(context),
+ marshalledState.getTiclState(),
+ new IntentForwardingListener(context, resources.getLogger()));
+ this.schedulingId = marshalledState.getMetadata().getTiclId();
+ initializeSchedulerWithRecurringTasks();
+ }
+
+ /** Returns the name of the application using the Ticl. */
+ private static String getApplicationName(Context context) {
+ return context.getPackageName();
+ }
+
+ /**
+ * Provides the internal scheduler with references to each of the recurring tasks that can be
+ * executed.
+ */
+ private void initializeSchedulerWithRecurringTasks() {
+ if (!(getResources().getInternalScheduler() instanceof AndroidInternalScheduler)) {
+ throw new IllegalStateException("Scheduler must be an AndroidInternalScheduler, not "
+ + getResources().getInternalScheduler());
+ }
+ AndroidInternalScheduler scheduler =
+ (AndroidInternalScheduler) getResources().getInternalScheduler();
+ for (Map.Entry<String, Runnable> entry : getRecurringTasks().entrySet()) {
+ scheduler.registerTask(entry.getKey(), entry.getValue());
+ }
+ }
+
+ /** Returns the scheduling id of this Ticl. */
+ long getSchedulingId() {
+ return schedulingId;
+ }
+
+ // This method appears to serve no purpose, since it's just a delegation to the superclass method
+ // with the same access level (protected). However, protected also implies package access, so what
+ // this is doing is making this method visible to TiclStateManager.
+ @Override
+ protected ApplicationClientIdP getApplicationClientIdP() {
+ return super.getApplicationClientIdP();
+ }
+
+ // Similar rationale as getApplicationClientIdP.
+ @Override
+ protected ClientConfigP getConfig() {
+ return super.getConfig();
+ }
+
+ // Similar rationale as getApplicationClientIdP.
+ @Override
+ protected boolean isStarted() {
+ return super.isStarted();
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698