Android cache invalidation client release August 2014

* Switching from lite to nano protos
* AckCache suppressing duplicate invalidations
* Removing deprecated code



git-svn-id: http://google-cache-invalidation-api.googlecode.com/svn/trunk/src@336 1cc9d426-c294-39be-ba72-c0199ca0f247
diff --git a/example-app-build/AndroidManifest.xml b/example-app-build/AndroidManifest.xml
index c2673e9..9a2a4db 100644
--- a/example-app-build/AndroidManifest.xml
+++ b/example-app-build/AndroidManifest.xml
@@ -7,7 +7,7 @@
   Merger manifest:
     java/com/google/ipc/invalidation/examples/android2/AndroidManifest.xml
   Mergee manifests:
-    blaze-out/gcc-4.X.Y-crosstool-v17-hybrid-grtev3-k8-fastbuild/bin/java/com/google/ipc/invalidation/external/client/contrib/android_listener_manifest/AndroidManifest.xml
+    blaze-out/gcc-4.X.Y-crosstool-v17-hybrid-grtev3-k8-opt/bin/java/com/google/ipc/invalidation/external/client/contrib/android_listener_manifest/AndroidManifest.xml
   -->
   <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="14"/>
   <!-- Declare and use permission allowing this application to receive GCM
@@ -37,13 +37,13 @@
         <action android:name="com.google.ipc.invalidation.AUTH_TOKEN_REQUEST"/>
       </intent-filter>
     </service>
-    <!-- Merged from file: blaze-out/gcc-4.X.Y-crosstool-v17-hybrid-grtev3-k8-fastbuild/bin/java/com/google/ipc/invalidation/external/client/contrib/android_listener_manifest/AndroidManifest.xml -->
+    <!-- Merged from file: blaze-out/gcc-4.X.Y-crosstool-v17-hybrid-grtev3-k8-opt/bin/java/com/google/ipc/invalidation/external/client/contrib/android_listener_manifest/AndroidManifest.xml -->
     <!-- Receiver for scheduler alarms. -->
     <receiver android:exported="false" android:name="com.google.ipc.invalidation.external.client.contrib.AndroidListener$AlarmReceiver"/>
-    <!-- Merged from file: blaze-out/gcc-4.X.Y-crosstool-v17-hybrid-grtev3-k8-fastbuild/bin/java/com/google/ipc/invalidation/external/client/contrib/android_listener_manifest/AndroidManifest.xml -->
+    <!-- Merged from file: blaze-out/gcc-4.X.Y-crosstool-v17-hybrid-grtev3-k8-opt/bin/java/com/google/ipc/invalidation/external/client/contrib/android_listener_manifest/AndroidManifest.xml -->
     <!-- Receiver for scheduler alarms. -->
     <receiver android:exported="false" android:name="com.google.ipc.invalidation.ticl.android2.AndroidInternalScheduler$AlarmReceiver"/>
-    <!-- Merged from file: blaze-out/gcc-4.X.Y-crosstool-v17-hybrid-grtev3-k8-fastbuild/bin/java/com/google/ipc/invalidation/external/client/contrib/android_listener_manifest/AndroidManifest.xml -->
+    <!-- Merged from file: blaze-out/gcc-4.X.Y-crosstool-v17-hybrid-grtev3-k8-opt/bin/java/com/google/ipc/invalidation/external/client/contrib/android_listener_manifest/AndroidManifest.xml -->
     <!-- GCM Broadcast Receiver -->
     <receiver android:exported="true" android:name="com.google.ipc.invalidation.external.client.contrib.MultiplexingGcmListener$GCMReceiver" android:permission="com.google.android.c2dm.permission.SEND">
       <intent-filter>
@@ -52,41 +52,41 @@
         <category android:name="com.google.ipc.invalidation.ticl.android2"/>
       </intent-filter>
     </receiver>
-    <!-- Merged from file: blaze-out/gcc-4.X.Y-crosstool-v17-hybrid-grtev3-k8-fastbuild/bin/java/com/google/ipc/invalidation/external/client/contrib/android_listener_manifest/AndroidManifest.xml -->
+    <!-- Merged from file: blaze-out/gcc-4.X.Y-crosstool-v17-hybrid-grtev3-k8-opt/bin/java/com/google/ipc/invalidation/external/client/contrib/android_listener_manifest/AndroidManifest.xml -->
     <!-- Merged from file: java/com/google/ipc/invalidation/external/client/android2/AndroidManifest.xml -->
     <receiver android:exported="false" android:name="com.google.ipc.invalidation.ticl.android2.channel.AndroidMessageReceiverService$Receiver">
       <intent-filter>
         <action android:name="com.google.ipc.invalidation.gcmmplex.EVENT"/>
       </intent-filter>
     </receiver>
-    <!-- Merged from file: blaze-out/gcc-4.X.Y-crosstool-v17-hybrid-grtev3-k8-fastbuild/bin/java/com/google/ipc/invalidation/external/client/contrib/android_listener_manifest/AndroidManifest.xml -->
+    <!-- Merged from file: blaze-out/gcc-4.X.Y-crosstool-v17-hybrid-grtev3-k8-opt/bin/java/com/google/ipc/invalidation/external/client/contrib/android_listener_manifest/AndroidManifest.xml -->
     <!-- Ticl service. -->
     <service android:exported="false" android:name="com.google.ipc.invalidation.ticl.android2.TiclService"/>
-    <!-- Merged from file: blaze-out/gcc-4.X.Y-crosstool-v17-hybrid-grtev3-k8-fastbuild/bin/java/com/google/ipc/invalidation/external/client/contrib/android_listener_manifest/AndroidManifest.xml -->
+    <!-- Merged from file: blaze-out/gcc-4.X.Y-crosstool-v17-hybrid-grtev3-k8-opt/bin/java/com/google/ipc/invalidation/external/client/contrib/android_listener_manifest/AndroidManifest.xml -->
     <!-- Ticl sender. -->
     <service android:exported="false" android:name="com.google.ipc.invalidation.ticl.android2.channel.AndroidMessageSenderService"/>
-    <!-- Merged from file: blaze-out/gcc-4.X.Y-crosstool-v17-hybrid-grtev3-k8-fastbuild/bin/java/com/google/ipc/invalidation/external/client/contrib/android_listener_manifest/AndroidManifest.xml -->
+    <!-- Merged from file: blaze-out/gcc-4.X.Y-crosstool-v17-hybrid-grtev3-k8-opt/bin/java/com/google/ipc/invalidation/external/client/contrib/android_listener_manifest/AndroidManifest.xml -->
     <!-- GCM multiplexer -->
     <service android:exported="false" android:name="com.google.ipc.invalidation.external.client.contrib.MultiplexingGcmListener">
       <meta-data android:name="sender_ids" android:value="[email protected]"/>
     </service>
-    <!-- Merged from file: blaze-out/gcc-4.X.Y-crosstool-v17-hybrid-grtev3-k8-fastbuild/bin/java/com/google/ipc/invalidation/external/client/contrib/android_listener_manifest/AndroidManifest.xml -->
+    <!-- Merged from file: blaze-out/gcc-4.X.Y-crosstool-v17-hybrid-grtev3-k8-opt/bin/java/com/google/ipc/invalidation/external/client/contrib/android_listener_manifest/AndroidManifest.xml -->
     <!-- Invalidation service multiplexed GCM receiver -->
     <service android:enabled="true" android:exported="false" android:name="com.google.ipc.invalidation.ticl.android2.channel.AndroidMessageReceiverService"/>
   </application>
-  <!-- Merged from file: blaze-out/gcc-4.X.Y-crosstool-v17-hybrid-grtev3-k8-fastbuild/bin/java/com/google/ipc/invalidation/external/client/contrib/android_listener_manifest/AndroidManifest.xml -->
+  <!-- Merged from file: blaze-out/gcc-4.X.Y-crosstool-v17-hybrid-grtev3-k8-opt/bin/java/com/google/ipc/invalidation/external/client/contrib/android_listener_manifest/AndroidManifest.xml -->
   <!-- App receives GCM messages. -->
   <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>
-  <!-- Merged from file: blaze-out/gcc-4.X.Y-crosstool-v17-hybrid-grtev3-k8-fastbuild/bin/java/com/google/ipc/invalidation/external/client/contrib/android_listener_manifest/AndroidManifest.xml -->
+  <!-- Merged from file: blaze-out/gcc-4.X.Y-crosstool-v17-hybrid-grtev3-k8-opt/bin/java/com/google/ipc/invalidation/external/client/contrib/android_listener_manifest/AndroidManifest.xml -->
   <!-- GCM connects to Google Services. -->
   <uses-permission android:name="android.permission.INTERNET"/>
-  <!-- Merged from file: blaze-out/gcc-4.X.Y-crosstool-v17-hybrid-grtev3-k8-fastbuild/bin/java/com/google/ipc/invalidation/external/client/contrib/android_listener_manifest/AndroidManifest.xml -->
+  <!-- Merged from file: blaze-out/gcc-4.X.Y-crosstool-v17-hybrid-grtev3-k8-opt/bin/java/com/google/ipc/invalidation/external/client/contrib/android_listener_manifest/AndroidManifest.xml -->
   <!-- GCM requires a Google account. -->
   <uses-permission android:name="android.permission.GET_ACCOUNTS"/>
-  <!-- Merged from file: blaze-out/gcc-4.X.Y-crosstool-v17-hybrid-grtev3-k8-fastbuild/bin/java/com/google/ipc/invalidation/external/client/contrib/android_listener_manifest/AndroidManifest.xml -->
+  <!-- Merged from file: blaze-out/gcc-4.X.Y-crosstool-v17-hybrid-grtev3-k8-opt/bin/java/com/google/ipc/invalidation/external/client/contrib/android_listener_manifest/AndroidManifest.xml -->
   <!-- Merged from file: java/com/google/ipc/invalidation/external/client/android2/AndroidManifest.xml -->
   <uses-permission android:name="android.permission.USE_CREDENTIALS"/>
-  <!-- Merged from file: blaze-out/gcc-4.X.Y-crosstool-v17-hybrid-grtev3-k8-fastbuild/bin/java/com/google/ipc/invalidation/external/client/contrib/android_listener_manifest/AndroidManifest.xml -->
+  <!-- Merged from file: blaze-out/gcc-4.X.Y-crosstool-v17-hybrid-grtev3-k8-opt/bin/java/com/google/ipc/invalidation/external/client/contrib/android_listener_manifest/AndroidManifest.xml -->
   <!-- Keeps the processor from sleeping when a message is received. -->
   <uses-permission android:name="android.permission.WAKE_LOCK"/>
 </manifest>
diff --git a/example-app-build/generate_protos.sh b/example-app-build/generate_protos.sh
index 71b5d8e..b7461f8 100755
--- a/example-app-build/generate_protos.sh
+++ b/example-app-build/generate_protos.sh
@@ -17,6 +17,6 @@
 # client into the generated-protos/ directory.
 TOOL=${PROTOC- `which protoc`}
 mkdir -p generated-protos/
-$TOOL --java_out=generated-protos/ ../proto/* --proto_path=../proto/
+$TOOL --javanano_out=optional_field_style=reftypes:generated-protos/ ../proto/* --proto_path=../proto/
 EXAMPLE_PATH=../java/com/google/ipc/invalidation/examples/android2
-$TOOL --java_out=generated-protos/ $EXAMPLE_PATH/example_listener.proto --proto_path=$EXAMPLE_PATH
\ No newline at end of file
+$TOOL --java_out=generated-protos/ $EXAMPLE_PATH/example_listener.proto --proto_path=$EXAMPLE_PATH
diff --git a/example-app-build/libs/protobuf-java-2.3.0-nano.jar b/example-app-build/libs/protobuf-java-2.3.0-nano.jar
new file mode 100644
index 0000000..b51536a
--- /dev/null
+++ b/example-app-build/libs/protobuf-java-2.3.0-nano.jar
Binary files differ
diff --git a/example-app-build/libs/protobuf-java-2.4.1-lite.jar b/example-app-build/libs/protobuf-java-2.4.1-lite.jar
deleted file mode 100644
index 5ad584f..0000000
--- a/example-app-build/libs/protobuf-java-2.4.1-lite.jar
+++ /dev/null
Binary files differ
diff --git a/java/com/google/ipc/invalidation/common/BaseCommonInvalidationConstants.java b/java/com/google/ipc/invalidation/common/BaseCommonInvalidationConstants.java
new file mode 100644
index 0000000..4244c2e
--- /dev/null
+++ b/java/com/google/ipc/invalidation/common/BaseCommonInvalidationConstants.java
@@ -0,0 +1,40 @@
+/*
+ * 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.common;
+
+/** Various constants common to  clients and servers used in version 2 of the Ticl. */
+public class BaseCommonInvalidationConstants {
+  /** Major version of the client library. */
+  public static final int CLIENT_MAJOR_VERSION = 3;
+
+  /**
+   * Minor version of the client library, defined to be equal to the datestamp of the build
+   * (e.g. 20130401).
+   */
+  public static final int CLIENT_MINOR_VERSION = BuildConstants.BUILD_DATESTAMP;
+
+  /** Major version of the protocol between the client and the server. */
+  public static final int PROTOCOL_MAJOR_VERSION = 3;
+
+  /** Minor version of the protocol between the client and the server. */
+  public static final int PROTOCOL_MINOR_VERSION = 2;
+
+  /** Major version of the client config. */
+  public static final int CONFIG_MAJOR_VERSION = 3;
+
+  /** Minor version of the client config. */
+  public static final int CONFIG_MINOR_VERSION = 2;
+}
diff --git a/java/com/google/ipc/invalidation/common/BuildConstants.java b/java/com/google/ipc/invalidation/common/BuildConstants.java
index d689354..a8a3a65 100644
--- a/java/com/google/ipc/invalidation/common/BuildConstants.java
+++ b/java/com/google/ipc/invalidation/common/BuildConstants.java
@@ -33,5 +33,5 @@
 
 /** Build constant definitions. */
 class BuildConstants {
-  static final int BUILD_DATESTAMP = 20140204;
+  static final int BUILD_DATESTAMP = 20140825;
 }
diff --git a/java/com/google/ipc/invalidation/common/ClientProtocolAccessor.java b/java/com/google/ipc/invalidation/common/ClientProtocolAccessor.java
deleted file mode 100644
index 976e227..0000000
--- a/java/com/google/ipc/invalidation/common/ClientProtocolAccessor.java
+++ /dev/null
@@ -1,1796 +0,0 @@
-/*
- * 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.
- */
-// GENERATED CODE. DO NOT EDIT. (But isn't it pretty?)
-package com.google.ipc.invalidation.common;
-
-import com.google.common.base.Preconditions;
-import com.google.ipc.invalidation.common.ProtoValidator.Accessor;
-
-import com.google.ipc.invalidation.common.ProtoValidator.Descriptor;
-
-import com.google.protobuf.MessageLite;
-
-import com.google.protos.ipc.invalidation.ClientProtocol.ApplicationClientIdP;
-import com.google.protos.ipc.invalidation.ClientProtocol.ClientConfigP;
-import com.google.protos.ipc.invalidation.ClientProtocol.ClientHeader;
-import com.google.protos.ipc.invalidation.ClientProtocol.ClientToServerMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.ClientVersion;
-import com.google.protos.ipc.invalidation.ClientProtocol.ConfigChangeMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.ErrorMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.InfoMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.InfoRequestMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.InitializeMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.InvalidationMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.InvalidationP;
-import com.google.protos.ipc.invalidation.ClientProtocol.ObjectIdP;
-import com.google.protos.ipc.invalidation.ClientProtocol.PropertyRecord;
-import com.google.protos.ipc.invalidation.ClientProtocol.ProtocolHandlerConfigP;
-import com.google.protos.ipc.invalidation.ClientProtocol.ProtocolVersion;
-import com.google.protos.ipc.invalidation.ClientProtocol.RateLimitP;
-import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationP;
-import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationStatus;
-import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationStatusMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationSubtree;
-import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationSummary;
-import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationSyncMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationSyncRequestMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.ServerHeader;
-import com.google.protos.ipc.invalidation.ClientProtocol.ServerToClientMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.StatusP;
-import com.google.protos.ipc.invalidation.ClientProtocol.TokenControlMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.Version;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Set;
-
-/** Class providing access to fields of protocol buffers in a generic way without using Java reflection. */
-public class ClientProtocolAccessor {
-  /** Class to access fields in {@link ApplicationClientIdP} protos. */
-  public static class ApplicationClientIdPAccessor implements Accessor {
-    private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-      Arrays.<String>asList(
-        "client_type",
-        "client_name"
-      ));
-    
-    public static final Descriptor CLIENT_TYPE = new Descriptor("client_type");
-    public static final Descriptor CLIENT_NAME = new Descriptor("client_name");
-    
-    /** Returns whether {@code field} is present in {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public boolean hasField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      ApplicationClientIdP message = (ApplicationClientIdP) rawMessage;
-      if (field == CLIENT_TYPE) {
-        return message.hasClientType();
-      }
-      if (field == CLIENT_NAME) {
-        return message.hasClientName();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    /** Returns the {@code field} from {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public Object getField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      ApplicationClientIdP message = (ApplicationClientIdP) rawMessage;
-      if (field == CLIENT_TYPE) {
-        return message.getClientType();
-      }
-      if (field == CLIENT_NAME) {
-        return message.getClientName();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    @Override
-    public Set<String> getAllFieldNames() {
-      return ALL_FIELD_NAMES;
-    }
-  }
-  public static final ApplicationClientIdPAccessor APPLICATION_CLIENT_ID_P_ACCESSOR = new ApplicationClientIdPAccessor();
-  
-  /** Class to access fields in {@link ClientConfigP} protos. */
-  public static class ClientConfigPAccessor implements Accessor {
-    private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-      Arrays.<String>asList(
-        "version",
-        "network_timeout_delay_ms",
-        "write_retry_delay_ms",
-        "heartbeat_interval_ms",
-        "perf_counter_delay_ms",
-        "max_exponential_backoff_factor",
-        "smear_percent",
-        "is_transient",
-        "initial_persistent_heartbeat_delay_ms",
-        "protocol_handler_config",
-        "channel_supports_offline_delivery",
-        "offline_heartbeat_threshold_ms",
-        "allow_suppression"
-      ));
-    
-    public static final Descriptor VERSION = new Descriptor("version");
-    public static final Descriptor NETWORK_TIMEOUT_DELAY_MS = new Descriptor("network_timeout_delay_ms");
-    public static final Descriptor WRITE_RETRY_DELAY_MS = new Descriptor("write_retry_delay_ms");
-    public static final Descriptor HEARTBEAT_INTERVAL_MS = new Descriptor("heartbeat_interval_ms");
-    public static final Descriptor PERF_COUNTER_DELAY_MS = new Descriptor("perf_counter_delay_ms");
-    public static final Descriptor MAX_EXPONENTIAL_BACKOFF_FACTOR = new Descriptor("max_exponential_backoff_factor");
-    public static final Descriptor SMEAR_PERCENT = new Descriptor("smear_percent");
-    public static final Descriptor IS_TRANSIENT = new Descriptor("is_transient");
-    public static final Descriptor INITIAL_PERSISTENT_HEARTBEAT_DELAY_MS = new Descriptor("initial_persistent_heartbeat_delay_ms");
-    public static final Descriptor PROTOCOL_HANDLER_CONFIG = new Descriptor("protocol_handler_config");
-    public static final Descriptor CHANNEL_SUPPORTS_OFFLINE_DELIVERY = new Descriptor("channel_supports_offline_delivery");
-    public static final Descriptor OFFLINE_HEARTBEAT_THRESHOLD_MS = new Descriptor("offline_heartbeat_threshold_ms");
-    public static final Descriptor ALLOW_SUPPRESSION = new Descriptor("allow_suppression");
-    
-    /** Returns whether {@code field} is present in {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public boolean hasField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      ClientConfigP message = (ClientConfigP) rawMessage;
-      if (field == VERSION) {
-        return message.hasVersion();
-      }
-      if (field == NETWORK_TIMEOUT_DELAY_MS) {
-        return message.hasNetworkTimeoutDelayMs();
-      }
-      if (field == WRITE_RETRY_DELAY_MS) {
-        return message.hasWriteRetryDelayMs();
-      }
-      if (field == HEARTBEAT_INTERVAL_MS) {
-        return message.hasHeartbeatIntervalMs();
-      }
-      if (field == PERF_COUNTER_DELAY_MS) {
-        return message.hasPerfCounterDelayMs();
-      }
-      if (field == MAX_EXPONENTIAL_BACKOFF_FACTOR) {
-        return message.hasMaxExponentialBackoffFactor();
-      }
-      if (field == SMEAR_PERCENT) {
-        return message.hasSmearPercent();
-      }
-      if (field == IS_TRANSIENT) {
-        return message.hasIsTransient();
-      }
-      if (field == INITIAL_PERSISTENT_HEARTBEAT_DELAY_MS) {
-        return message.hasInitialPersistentHeartbeatDelayMs();
-      }
-      if (field == PROTOCOL_HANDLER_CONFIG) {
-        return message.hasProtocolHandlerConfig();
-      }
-      if (field == CHANNEL_SUPPORTS_OFFLINE_DELIVERY) {
-        return message.hasChannelSupportsOfflineDelivery();
-      }
-      if (field == OFFLINE_HEARTBEAT_THRESHOLD_MS) {
-        return message.hasOfflineHeartbeatThresholdMs();
-      }
-      if (field == ALLOW_SUPPRESSION) {
-        return message.hasAllowSuppression();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    /** Returns the {@code field} from {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public Object getField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      ClientConfigP message = (ClientConfigP) rawMessage;
-      if (field == VERSION) {
-        return message.getVersion();
-      }
-      if (field == NETWORK_TIMEOUT_DELAY_MS) {
-        return message.getNetworkTimeoutDelayMs();
-      }
-      if (field == WRITE_RETRY_DELAY_MS) {
-        return message.getWriteRetryDelayMs();
-      }
-      if (field == HEARTBEAT_INTERVAL_MS) {
-        return message.getHeartbeatIntervalMs();
-      }
-      if (field == PERF_COUNTER_DELAY_MS) {
-        return message.getPerfCounterDelayMs();
-      }
-      if (field == MAX_EXPONENTIAL_BACKOFF_FACTOR) {
-        return message.getMaxExponentialBackoffFactor();
-      }
-      if (field == SMEAR_PERCENT) {
-        return message.getSmearPercent();
-      }
-      if (field == IS_TRANSIENT) {
-        return message.getIsTransient();
-      }
-      if (field == INITIAL_PERSISTENT_HEARTBEAT_DELAY_MS) {
-        return message.getInitialPersistentHeartbeatDelayMs();
-      }
-      if (field == PROTOCOL_HANDLER_CONFIG) {
-        return message.getProtocolHandlerConfig();
-      }
-      if (field == CHANNEL_SUPPORTS_OFFLINE_DELIVERY) {
-        return message.getChannelSupportsOfflineDelivery();
-      }
-      if (field == OFFLINE_HEARTBEAT_THRESHOLD_MS) {
-        return message.getOfflineHeartbeatThresholdMs();
-      }
-      if (field == ALLOW_SUPPRESSION) {
-        return message.getAllowSuppression();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    @Override
-    public Set<String> getAllFieldNames() {
-      return ALL_FIELD_NAMES;
-    }
-  }
-  public static final ClientConfigPAccessor CLIENT_CONFIG_P_ACCESSOR = new ClientConfigPAccessor();
-  
-  /** Class to access fields in {@link ClientHeader} protos. */
-  public static class ClientHeaderAccessor implements Accessor {
-    private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-      Arrays.<String>asList(
-        "protocol_version",
-        "client_token",
-        "registration_summary",
-        "client_time_ms",
-        "max_known_server_time_ms",
-        "message_id",
-        "client_type"
-      ));
-    
-    public static final Descriptor PROTOCOL_VERSION = new Descriptor("protocol_version");
-    public static final Descriptor CLIENT_TOKEN = new Descriptor("client_token");
-    public static final Descriptor REGISTRATION_SUMMARY = new Descriptor("registration_summary");
-    public static final Descriptor CLIENT_TIME_MS = new Descriptor("client_time_ms");
-    public static final Descriptor MAX_KNOWN_SERVER_TIME_MS = new Descriptor("max_known_server_time_ms");
-    public static final Descriptor MESSAGE_ID = new Descriptor("message_id");
-    public static final Descriptor CLIENT_TYPE = new Descriptor("client_type");
-    
-    /** Returns whether {@code field} is present in {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public boolean hasField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      ClientHeader message = (ClientHeader) rawMessage;
-      if (field == PROTOCOL_VERSION) {
-        return message.hasProtocolVersion();
-      }
-      if (field == CLIENT_TOKEN) {
-        return message.hasClientToken();
-      }
-      if (field == REGISTRATION_SUMMARY) {
-        return message.hasRegistrationSummary();
-      }
-      if (field == CLIENT_TIME_MS) {
-        return message.hasClientTimeMs();
-      }
-      if (field == MAX_KNOWN_SERVER_TIME_MS) {
-        return message.hasMaxKnownServerTimeMs();
-      }
-      if (field == MESSAGE_ID) {
-        return message.hasMessageId();
-      }
-      if (field == CLIENT_TYPE) {
-        return message.hasClientType();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    /** Returns the {@code field} from {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public Object getField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      ClientHeader message = (ClientHeader) rawMessage;
-      if (field == PROTOCOL_VERSION) {
-        return message.getProtocolVersion();
-      }
-      if (field == CLIENT_TOKEN) {
-        return message.getClientToken();
-      }
-      if (field == REGISTRATION_SUMMARY) {
-        return message.getRegistrationSummary();
-      }
-      if (field == CLIENT_TIME_MS) {
-        return message.getClientTimeMs();
-      }
-      if (field == MAX_KNOWN_SERVER_TIME_MS) {
-        return message.getMaxKnownServerTimeMs();
-      }
-      if (field == MESSAGE_ID) {
-        return message.getMessageId();
-      }
-      if (field == CLIENT_TYPE) {
-        return message.getClientType();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    @Override
-    public Set<String> getAllFieldNames() {
-      return ALL_FIELD_NAMES;
-    }
-  }
-  public static final ClientHeaderAccessor CLIENT_HEADER_ACCESSOR = new ClientHeaderAccessor();
-  
-  /** Class to access fields in {@link ClientToServerMessage} protos. */
-  public static class ClientToServerMessageAccessor implements Accessor {
-    private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-      Arrays.<String>asList(
-        "header",
-        "initialize_message",
-        "registration_message",
-        "registration_sync_message",
-        "invalidation_ack_message",
-        "info_message"
-      ));
-    
-    public static final Descriptor HEADER = new Descriptor("header");
-    public static final Descriptor INITIALIZE_MESSAGE = new Descriptor("initialize_message");
-    public static final Descriptor REGISTRATION_MESSAGE = new Descriptor("registration_message");
-    public static final Descriptor REGISTRATION_SYNC_MESSAGE = new Descriptor("registration_sync_message");
-    public static final Descriptor INVALIDATION_ACK_MESSAGE = new Descriptor("invalidation_ack_message");
-    public static final Descriptor INFO_MESSAGE = new Descriptor("info_message");
-    
-    /** Returns whether {@code field} is present in {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public boolean hasField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      ClientToServerMessage message = (ClientToServerMessage) rawMessage;
-      if (field == HEADER) {
-        return message.hasHeader();
-      }
-      if (field == INITIALIZE_MESSAGE) {
-        return message.hasInitializeMessage();
-      }
-      if (field == REGISTRATION_MESSAGE) {
-        return message.hasRegistrationMessage();
-      }
-      if (field == REGISTRATION_SYNC_MESSAGE) {
-        return message.hasRegistrationSyncMessage();
-      }
-      if (field == INVALIDATION_ACK_MESSAGE) {
-        return message.hasInvalidationAckMessage();
-      }
-      if (field == INFO_MESSAGE) {
-        return message.hasInfoMessage();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    /** Returns the {@code field} from {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public Object getField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      ClientToServerMessage message = (ClientToServerMessage) rawMessage;
-      if (field == HEADER) {
-        return message.getHeader();
-      }
-      if (field == INITIALIZE_MESSAGE) {
-        return message.getInitializeMessage();
-      }
-      if (field == REGISTRATION_MESSAGE) {
-        return message.getRegistrationMessage();
-      }
-      if (field == REGISTRATION_SYNC_MESSAGE) {
-        return message.getRegistrationSyncMessage();
-      }
-      if (field == INVALIDATION_ACK_MESSAGE) {
-        return message.getInvalidationAckMessage();
-      }
-      if (field == INFO_MESSAGE) {
-        return message.getInfoMessage();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    @Override
-    public Set<String> getAllFieldNames() {
-      return ALL_FIELD_NAMES;
-    }
-  }
-  public static final ClientToServerMessageAccessor CLIENT_TO_SERVER_MESSAGE_ACCESSOR = new ClientToServerMessageAccessor();
-  
-  /** Class to access fields in {@link ClientVersion} protos. */
-  public static class ClientVersionAccessor implements Accessor {
-    private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-      Arrays.<String>asList(
-        "version",
-        "platform",
-        "language",
-        "application_info"
-      ));
-    
-    public static final Descriptor VERSION = new Descriptor("version");
-    public static final Descriptor PLATFORM = new Descriptor("platform");
-    public static final Descriptor LANGUAGE = new Descriptor("language");
-    public static final Descriptor APPLICATION_INFO = new Descriptor("application_info");
-    
-    /** Returns whether {@code field} is present in {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public boolean hasField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      ClientVersion message = (ClientVersion) rawMessage;
-      if (field == VERSION) {
-        return message.hasVersion();
-      }
-      if (field == PLATFORM) {
-        return message.hasPlatform();
-      }
-      if (field == LANGUAGE) {
-        return message.hasLanguage();
-      }
-      if (field == APPLICATION_INFO) {
-        return message.hasApplicationInfo();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    /** Returns the {@code field} from {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public Object getField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      ClientVersion message = (ClientVersion) rawMessage;
-      if (field == VERSION) {
-        return message.getVersion();
-      }
-      if (field == PLATFORM) {
-        return message.getPlatform();
-      }
-      if (field == LANGUAGE) {
-        return message.getLanguage();
-      }
-      if (field == APPLICATION_INFO) {
-        return message.getApplicationInfo();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    @Override
-    public Set<String> getAllFieldNames() {
-      return ALL_FIELD_NAMES;
-    }
-  }
-  public static final ClientVersionAccessor CLIENT_VERSION_ACCESSOR = new ClientVersionAccessor();
-  
-  /** Class to access fields in {@link ConfigChangeMessage} protos. */
-  public static class ConfigChangeMessageAccessor implements Accessor {
-    private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-      Arrays.<String>asList(
-        "next_message_delay_ms"
-      ));
-    
-    public static final Descriptor NEXT_MESSAGE_DELAY_MS = new Descriptor("next_message_delay_ms");
-    
-    /** Returns whether {@code field} is present in {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public boolean hasField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      ConfigChangeMessage message = (ConfigChangeMessage) rawMessage;
-      if (field == NEXT_MESSAGE_DELAY_MS) {
-        return message.hasNextMessageDelayMs();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    /** Returns the {@code field} from {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public Object getField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      ConfigChangeMessage message = (ConfigChangeMessage) rawMessage;
-      if (field == NEXT_MESSAGE_DELAY_MS) {
-        return message.getNextMessageDelayMs();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    @Override
-    public Set<String> getAllFieldNames() {
-      return ALL_FIELD_NAMES;
-    }
-  }
-  public static final ConfigChangeMessageAccessor CONFIG_CHANGE_MESSAGE_ACCESSOR = new ConfigChangeMessageAccessor();
-  
-  /** Class to access fields in {@link ErrorMessage} protos. */
-  public static class ErrorMessageAccessor implements Accessor {
-    private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-      Arrays.<String>asList(
-        "code",
-        "description"
-      ));
-    
-    public static final Descriptor CODE = new Descriptor("code");
-    public static final Descriptor DESCRIPTION = new Descriptor("description");
-    
-    /** Returns whether {@code field} is present in {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public boolean hasField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      ErrorMessage message = (ErrorMessage) rawMessage;
-      if (field == CODE) {
-        return message.hasCode();
-      }
-      if (field == DESCRIPTION) {
-        return message.hasDescription();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    /** Returns the {@code field} from {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public Object getField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      ErrorMessage message = (ErrorMessage) rawMessage;
-      if (field == CODE) {
-        return message.getCode();
-      }
-      if (field == DESCRIPTION) {
-        return message.getDescription();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    @Override
-    public Set<String> getAllFieldNames() {
-      return ALL_FIELD_NAMES;
-    }
-  }
-  public static final ErrorMessageAccessor ERROR_MESSAGE_ACCESSOR = new ErrorMessageAccessor();
-  
-  /** Class to access fields in {@link InfoMessage} protos. */
-  public static class InfoMessageAccessor implements Accessor {
-    private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-      Arrays.<String>asList(
-        "client_version",
-        "config_parameter",
-        "performance_counter",
-        "server_registration_summary_requested",
-        "client_config"
-      ));
-    
-    public static final Descriptor CLIENT_VERSION = new Descriptor("client_version");
-    public static final Descriptor CONFIG_PARAMETER = new Descriptor("config_parameter");
-    public static final Descriptor PERFORMANCE_COUNTER = new Descriptor("performance_counter");
-    public static final Descriptor SERVER_REGISTRATION_SUMMARY_REQUESTED = new Descriptor("server_registration_summary_requested");
-    public static final Descriptor CLIENT_CONFIG = new Descriptor("client_config");
-    
-    /** Returns whether {@code field} is present in {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public boolean hasField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      InfoMessage message = (InfoMessage) rawMessage;
-      if (field == CLIENT_VERSION) {
-        return message.hasClientVersion();
-      }
-      if (field == CONFIG_PARAMETER) {
-        return message.getConfigParameterCount() > 0;
-      }
-      if (field == PERFORMANCE_COUNTER) {
-        return message.getPerformanceCounterCount() > 0;
-      }
-      if (field == SERVER_REGISTRATION_SUMMARY_REQUESTED) {
-        return message.hasServerRegistrationSummaryRequested();
-      }
-      if (field == CLIENT_CONFIG) {
-        return message.hasClientConfig();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    /** Returns the {@code field} from {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public Object getField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      InfoMessage message = (InfoMessage) rawMessage;
-      if (field == CLIENT_VERSION) {
-        return message.getClientVersion();
-      }
-      if (field == CONFIG_PARAMETER) {
-        return message.getConfigParameterList();
-      }
-      if (field == PERFORMANCE_COUNTER) {
-        return message.getPerformanceCounterList();
-      }
-      if (field == SERVER_REGISTRATION_SUMMARY_REQUESTED) {
-        return message.getServerRegistrationSummaryRequested();
-      }
-      if (field == CLIENT_CONFIG) {
-        return message.getClientConfig();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    @Override
-    public Set<String> getAllFieldNames() {
-      return ALL_FIELD_NAMES;
-    }
-  }
-  public static final InfoMessageAccessor INFO_MESSAGE_ACCESSOR = new InfoMessageAccessor();
-  
-  /** Class to access fields in {@link InfoRequestMessage} protos. */
-  public static class InfoRequestMessageAccessor implements Accessor {
-    private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-      Arrays.<String>asList(
-        "info_type"
-      ));
-    
-    public static final Descriptor INFO_TYPE = new Descriptor("info_type");
-    
-    /** Returns whether {@code field} is present in {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public boolean hasField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      InfoRequestMessage message = (InfoRequestMessage) rawMessage;
-      if (field == INFO_TYPE) {
-        return message.getInfoTypeCount() > 0;
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    /** Returns the {@code field} from {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public Object getField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      InfoRequestMessage message = (InfoRequestMessage) rawMessage;
-      if (field == INFO_TYPE) {
-        return message.getInfoTypeList();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    @Override
-    public Set<String> getAllFieldNames() {
-      return ALL_FIELD_NAMES;
-    }
-  }
-  public static final InfoRequestMessageAccessor INFO_REQUEST_MESSAGE_ACCESSOR = new InfoRequestMessageAccessor();
-  
-  /** Class to access fields in {@link InitializeMessage} protos. */
-  public static class InitializeMessageAccessor implements Accessor {
-    private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-      Arrays.<String>asList(
-        "client_type",
-        "nonce",
-        "application_client_id",
-        "digest_serialization_type"
-      ));
-    
-    public static final Descriptor CLIENT_TYPE = new Descriptor("client_type");
-    public static final Descriptor NONCE = new Descriptor("nonce");
-    public static final Descriptor APPLICATION_CLIENT_ID = new Descriptor("application_client_id");
-    public static final Descriptor DIGEST_SERIALIZATION_TYPE = new Descriptor("digest_serialization_type");
-    
-    /** Returns whether {@code field} is present in {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public boolean hasField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      InitializeMessage message = (InitializeMessage) rawMessage;
-      if (field == CLIENT_TYPE) {
-        return message.hasClientType();
-      }
-      if (field == NONCE) {
-        return message.hasNonce();
-      }
-      if (field == APPLICATION_CLIENT_ID) {
-        return message.hasApplicationClientId();
-      }
-      if (field == DIGEST_SERIALIZATION_TYPE) {
-        return message.hasDigestSerializationType();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    /** Returns the {@code field} from {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public Object getField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      InitializeMessage message = (InitializeMessage) rawMessage;
-      if (field == CLIENT_TYPE) {
-        return message.getClientType();
-      }
-      if (field == NONCE) {
-        return message.getNonce();
-      }
-      if (field == APPLICATION_CLIENT_ID) {
-        return message.getApplicationClientId();
-      }
-      if (field == DIGEST_SERIALIZATION_TYPE) {
-        return message.getDigestSerializationType();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    @Override
-    public Set<String> getAllFieldNames() {
-      return ALL_FIELD_NAMES;
-    }
-  }
-  public static final InitializeMessageAccessor INITIALIZE_MESSAGE_ACCESSOR = new InitializeMessageAccessor();
-  
-  /** Class to access fields in {@link InvalidationMessage} protos. */
-  public static class InvalidationMessageAccessor implements Accessor {
-    private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-      Arrays.<String>asList(
-        "invalidation"
-      ));
-    
-    public static final Descriptor INVALIDATION = new Descriptor("invalidation");
-    
-    /** Returns whether {@code field} is present in {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public boolean hasField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      InvalidationMessage message = (InvalidationMessage) rawMessage;
-      if (field == INVALIDATION) {
-        return message.getInvalidationCount() > 0;
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    /** Returns the {@code field} from {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public Object getField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      InvalidationMessage message = (InvalidationMessage) rawMessage;
-      if (field == INVALIDATION) {
-        return message.getInvalidationList();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    @Override
-    public Set<String> getAllFieldNames() {
-      return ALL_FIELD_NAMES;
-    }
-  }
-  public static final InvalidationMessageAccessor INVALIDATION_MESSAGE_ACCESSOR = new InvalidationMessageAccessor();
-  
-  /** Class to access fields in {@link InvalidationP} protos. */
-  public static class InvalidationPAccessor implements Accessor {
-    private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-      Arrays.<String>asList(
-        "object_id",
-        "is_known_version",
-        "version",
-        "is_trickle_restart",
-        "payload",
-        "bridge_arrival_time_ms_deprecated"
-      ));
-    
-    public static final Descriptor OBJECT_ID = new Descriptor("object_id");
-    public static final Descriptor IS_KNOWN_VERSION = new Descriptor("is_known_version");
-    public static final Descriptor VERSION = new Descriptor("version");
-    public static final Descriptor IS_TRICKLE_RESTART = new Descriptor("is_trickle_restart");
-    public static final Descriptor PAYLOAD = new Descriptor("payload");
-    public static final Descriptor BRIDGE_ARRIVAL_TIME_MS_DEPRECATED = new Descriptor("bridge_arrival_time_ms_deprecated");
-    
-    /** Returns whether {@code field} is present in {@code message}. */
-    @Override
-    @SuppressWarnings({ "deprecation", "unchecked" })
-    public boolean hasField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      InvalidationP message = (InvalidationP) rawMessage;
-      if (field == OBJECT_ID) {
-        return message.hasObjectId();
-      }
-      if (field == IS_KNOWN_VERSION) {
-        return message.hasIsKnownVersion();
-      }
-      if (field == VERSION) {
-        return message.hasVersion();
-      }
-      if (field == IS_TRICKLE_RESTART) {
-        return message.hasIsTrickleRestart();
-      }
-      if (field == PAYLOAD) {
-        return message.hasPayload();
-      }
-      if (field == BRIDGE_ARRIVAL_TIME_MS_DEPRECATED) {
-        return message.hasBridgeArrivalTimeMsDeprecated();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    /** Returns the {@code field} from {@code message}. */
-    @Override
-    @SuppressWarnings({ "deprecation", "unchecked" })
-    public Object getField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      InvalidationP message = (InvalidationP) rawMessage;
-      if (field == OBJECT_ID) {
-        return message.getObjectId();
-      }
-      if (field == IS_KNOWN_VERSION) {
-        return message.getIsKnownVersion();
-      }
-      if (field == VERSION) {
-        return message.getVersion();
-      }
-      if (field == IS_TRICKLE_RESTART) {
-        return message.getIsTrickleRestart();
-      }
-      if (field == PAYLOAD) {
-        return message.getPayload();
-      }
-      if (field == BRIDGE_ARRIVAL_TIME_MS_DEPRECATED) {
-        return message.getBridgeArrivalTimeMsDeprecated();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    @Override
-    public Set<String> getAllFieldNames() {
-      return ALL_FIELD_NAMES;
-    }
-  }
-  public static final InvalidationPAccessor INVALIDATION_P_ACCESSOR = new InvalidationPAccessor();
-  
-  /** Class to access fields in {@link ObjectIdP} protos. */
-  public static class ObjectIdPAccessor implements Accessor {
-    private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-      Arrays.<String>asList(
-        "source",
-        "name"
-      ));
-    
-    public static final Descriptor SOURCE = new Descriptor("source");
-    public static final Descriptor NAME = new Descriptor("name");
-    
-    /** Returns whether {@code field} is present in {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public boolean hasField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      ObjectIdP message = (ObjectIdP) rawMessage;
-      if (field == SOURCE) {
-        return message.hasSource();
-      }
-      if (field == NAME) {
-        return message.hasName();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    /** Returns the {@code field} from {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public Object getField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      ObjectIdP message = (ObjectIdP) rawMessage;
-      if (field == SOURCE) {
-        return message.getSource();
-      }
-      if (field == NAME) {
-        return message.getName();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    @Override
-    public Set<String> getAllFieldNames() {
-      return ALL_FIELD_NAMES;
-    }
-  }
-  public static final ObjectIdPAccessor OBJECT_ID_P_ACCESSOR = new ObjectIdPAccessor();
-  
-  /** Class to access fields in {@link PropertyRecord} protos. */
-  public static class PropertyRecordAccessor implements Accessor {
-    private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-      Arrays.<String>asList(
-        "name",
-        "value"
-      ));
-    
-    public static final Descriptor NAME = new Descriptor("name");
-    public static final Descriptor VALUE = new Descriptor("value");
-    
-    /** Returns whether {@code field} is present in {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public boolean hasField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      PropertyRecord message = (PropertyRecord) rawMessage;
-      if (field == NAME) {
-        return message.hasName();
-      }
-      if (field == VALUE) {
-        return message.hasValue();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    /** Returns the {@code field} from {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public Object getField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      PropertyRecord message = (PropertyRecord) rawMessage;
-      if (field == NAME) {
-        return message.getName();
-      }
-      if (field == VALUE) {
-        return message.getValue();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    @Override
-    public Set<String> getAllFieldNames() {
-      return ALL_FIELD_NAMES;
-    }
-  }
-  public static final PropertyRecordAccessor PROPERTY_RECORD_ACCESSOR = new PropertyRecordAccessor();
-  
-  /** Class to access fields in {@link ProtocolHandlerConfigP} protos. */
-  public static class ProtocolHandlerConfigPAccessor implements Accessor {
-    private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-      Arrays.<String>asList(
-        "batching_delay_ms",
-        "rate_limit"
-      ));
-    
-    public static final Descriptor BATCHING_DELAY_MS = new Descriptor("batching_delay_ms");
-    public static final Descriptor RATE_LIMIT = new Descriptor("rate_limit");
-    
-    /** Returns whether {@code field} is present in {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public boolean hasField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      ProtocolHandlerConfigP message = (ProtocolHandlerConfigP) rawMessage;
-      if (field == BATCHING_DELAY_MS) {
-        return message.hasBatchingDelayMs();
-      }
-      if (field == RATE_LIMIT) {
-        return message.getRateLimitCount() > 0;
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    /** Returns the {@code field} from {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public Object getField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      ProtocolHandlerConfigP message = (ProtocolHandlerConfigP) rawMessage;
-      if (field == BATCHING_DELAY_MS) {
-        return message.getBatchingDelayMs();
-      }
-      if (field == RATE_LIMIT) {
-        return message.getRateLimitList();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    @Override
-    public Set<String> getAllFieldNames() {
-      return ALL_FIELD_NAMES;
-    }
-  }
-  public static final ProtocolHandlerConfigPAccessor PROTOCOL_HANDLER_CONFIG_P_ACCESSOR = new ProtocolHandlerConfigPAccessor();
-  
-  /** Class to access fields in {@link ProtocolVersion} protos. */
-  public static class ProtocolVersionAccessor implements Accessor {
-    private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-      Arrays.<String>asList(
-        "version"
-      ));
-    
-    public static final Descriptor VERSION = new Descriptor("version");
-    
-    /** Returns whether {@code field} is present in {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public boolean hasField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      ProtocolVersion message = (ProtocolVersion) rawMessage;
-      if (field == VERSION) {
-        return message.hasVersion();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    /** Returns the {@code field} from {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public Object getField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      ProtocolVersion message = (ProtocolVersion) rawMessage;
-      if (field == VERSION) {
-        return message.getVersion();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    @Override
-    public Set<String> getAllFieldNames() {
-      return ALL_FIELD_NAMES;
-    }
-  }
-  public static final ProtocolVersionAccessor PROTOCOL_VERSION_ACCESSOR = new ProtocolVersionAccessor();
-  
-  /** Class to access fields in {@link RateLimitP} protos. */
-  public static class RateLimitPAccessor implements Accessor {
-    private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-      Arrays.<String>asList(
-        "window_ms",
-        "count"
-      ));
-    
-    public static final Descriptor WINDOW_MS = new Descriptor("window_ms");
-    public static final Descriptor COUNT = new Descriptor("count");
-    
-    /** Returns whether {@code field} is present in {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public boolean hasField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      RateLimitP message = (RateLimitP) rawMessage;
-      if (field == WINDOW_MS) {
-        return message.hasWindowMs();
-      }
-      if (field == COUNT) {
-        return message.hasCount();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    /** Returns the {@code field} from {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public Object getField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      RateLimitP message = (RateLimitP) rawMessage;
-      if (field == WINDOW_MS) {
-        return message.getWindowMs();
-      }
-      if (field == COUNT) {
-        return message.getCount();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    @Override
-    public Set<String> getAllFieldNames() {
-      return ALL_FIELD_NAMES;
-    }
-  }
-  public static final RateLimitPAccessor RATE_LIMIT_P_ACCESSOR = new RateLimitPAccessor();
-  
-  /** Class to access fields in {@link RegistrationMessage} protos. */
-  public static class RegistrationMessageAccessor implements Accessor {
-    private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-      Arrays.<String>asList(
-        "registration"
-      ));
-    
-    public static final Descriptor REGISTRATION = new Descriptor("registration");
-    
-    /** Returns whether {@code field} is present in {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public boolean hasField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      RegistrationMessage message = (RegistrationMessage) rawMessage;
-      if (field == REGISTRATION) {
-        return message.getRegistrationCount() > 0;
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    /** Returns the {@code field} from {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public Object getField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      RegistrationMessage message = (RegistrationMessage) rawMessage;
-      if (field == REGISTRATION) {
-        return message.getRegistrationList();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    @Override
-    public Set<String> getAllFieldNames() {
-      return ALL_FIELD_NAMES;
-    }
-  }
-  public static final RegistrationMessageAccessor REGISTRATION_MESSAGE_ACCESSOR = new RegistrationMessageAccessor();
-  
-  /** Class to access fields in {@link RegistrationP} protos. */
-  public static class RegistrationPAccessor implements Accessor {
-    private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-      Arrays.<String>asList(
-        "object_id",
-        "op_type"
-      ));
-    
-    public static final Descriptor OBJECT_ID = new Descriptor("object_id");
-    public static final Descriptor OP_TYPE = new Descriptor("op_type");
-    
-    /** Returns whether {@code field} is present in {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public boolean hasField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      RegistrationP message = (RegistrationP) rawMessage;
-      if (field == OBJECT_ID) {
-        return message.hasObjectId();
-      }
-      if (field == OP_TYPE) {
-        return message.hasOpType();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    /** Returns the {@code field} from {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public Object getField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      RegistrationP message = (RegistrationP) rawMessage;
-      if (field == OBJECT_ID) {
-        return message.getObjectId();
-      }
-      if (field == OP_TYPE) {
-        return message.getOpType();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    @Override
-    public Set<String> getAllFieldNames() {
-      return ALL_FIELD_NAMES;
-    }
-  }
-  public static final RegistrationPAccessor REGISTRATION_P_ACCESSOR = new RegistrationPAccessor();
-  
-  /** Class to access fields in {@link RegistrationStatus} protos. */
-  public static class RegistrationStatusAccessor implements Accessor {
-    private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-      Arrays.<String>asList(
-        "registration",
-        "status"
-      ));
-    
-    public static final Descriptor REGISTRATION = new Descriptor("registration");
-    public static final Descriptor STATUS = new Descriptor("status");
-    
-    /** Returns whether {@code field} is present in {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public boolean hasField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      RegistrationStatus message = (RegistrationStatus) rawMessage;
-      if (field == REGISTRATION) {
-        return message.hasRegistration();
-      }
-      if (field == STATUS) {
-        return message.hasStatus();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    /** Returns the {@code field} from {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public Object getField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      RegistrationStatus message = (RegistrationStatus) rawMessage;
-      if (field == REGISTRATION) {
-        return message.getRegistration();
-      }
-      if (field == STATUS) {
-        return message.getStatus();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    @Override
-    public Set<String> getAllFieldNames() {
-      return ALL_FIELD_NAMES;
-    }
-  }
-  public static final RegistrationStatusAccessor REGISTRATION_STATUS_ACCESSOR = new RegistrationStatusAccessor();
-  
-  /** Class to access fields in {@link RegistrationStatusMessage} protos. */
-  public static class RegistrationStatusMessageAccessor implements Accessor {
-    private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-      Arrays.<String>asList(
-        "registration_status"
-      ));
-    
-    public static final Descriptor REGISTRATION_STATUS = new Descriptor("registration_status");
-    
-    /** Returns whether {@code field} is present in {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public boolean hasField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      RegistrationStatusMessage message = (RegistrationStatusMessage) rawMessage;
-      if (field == REGISTRATION_STATUS) {
-        return message.getRegistrationStatusCount() > 0;
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    /** Returns the {@code field} from {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public Object getField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      RegistrationStatusMessage message = (RegistrationStatusMessage) rawMessage;
-      if (field == REGISTRATION_STATUS) {
-        return message.getRegistrationStatusList();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    @Override
-    public Set<String> getAllFieldNames() {
-      return ALL_FIELD_NAMES;
-    }
-  }
-  public static final RegistrationStatusMessageAccessor REGISTRATION_STATUS_MESSAGE_ACCESSOR = new RegistrationStatusMessageAccessor();
-  
-  /** Class to access fields in {@link RegistrationSubtree} protos. */
-  public static class RegistrationSubtreeAccessor implements Accessor {
-    private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-      Arrays.<String>asList(
-        "registered_object"
-      ));
-    
-    public static final Descriptor REGISTERED_OBJECT = new Descriptor("registered_object");
-    
-    /** Returns whether {@code field} is present in {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public boolean hasField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      RegistrationSubtree message = (RegistrationSubtree) rawMessage;
-      if (field == REGISTERED_OBJECT) {
-        return message.getRegisteredObjectCount() > 0;
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    /** Returns the {@code field} from {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public Object getField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      RegistrationSubtree message = (RegistrationSubtree) rawMessage;
-      if (field == REGISTERED_OBJECT) {
-        return message.getRegisteredObjectList();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    @Override
-    public Set<String> getAllFieldNames() {
-      return ALL_FIELD_NAMES;
-    }
-  }
-  public static final RegistrationSubtreeAccessor REGISTRATION_SUBTREE_ACCESSOR = new RegistrationSubtreeAccessor();
-  
-  /** Class to access fields in {@link RegistrationSummary} protos. */
-  public static class RegistrationSummaryAccessor implements Accessor {
-    private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-      Arrays.<String>asList(
-        "num_registrations",
-        "registration_digest"
-      ));
-    
-    public static final Descriptor NUM_REGISTRATIONS = new Descriptor("num_registrations");
-    public static final Descriptor REGISTRATION_DIGEST = new Descriptor("registration_digest");
-    
-    /** Returns whether {@code field} is present in {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public boolean hasField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      RegistrationSummary message = (RegistrationSummary) rawMessage;
-      if (field == NUM_REGISTRATIONS) {
-        return message.hasNumRegistrations();
-      }
-      if (field == REGISTRATION_DIGEST) {
-        return message.hasRegistrationDigest();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    /** Returns the {@code field} from {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public Object getField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      RegistrationSummary message = (RegistrationSummary) rawMessage;
-      if (field == NUM_REGISTRATIONS) {
-        return message.getNumRegistrations();
-      }
-      if (field == REGISTRATION_DIGEST) {
-        return message.getRegistrationDigest();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    @Override
-    public Set<String> getAllFieldNames() {
-      return ALL_FIELD_NAMES;
-    }
-  }
-  public static final RegistrationSummaryAccessor REGISTRATION_SUMMARY_ACCESSOR = new RegistrationSummaryAccessor();
-  
-  /** Class to access fields in {@link RegistrationSyncMessage} protos. */
-  public static class RegistrationSyncMessageAccessor implements Accessor {
-    private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-      Arrays.<String>asList(
-        "subtree"
-      ));
-    
-    public static final Descriptor SUBTREE = new Descriptor("subtree");
-    
-    /** Returns whether {@code field} is present in {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public boolean hasField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      RegistrationSyncMessage message = (RegistrationSyncMessage) rawMessage;
-      if (field == SUBTREE) {
-        return message.getSubtreeCount() > 0;
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    /** Returns the {@code field} from {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public Object getField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      RegistrationSyncMessage message = (RegistrationSyncMessage) rawMessage;
-      if (field == SUBTREE) {
-        return message.getSubtreeList();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    @Override
-    public Set<String> getAllFieldNames() {
-      return ALL_FIELD_NAMES;
-    }
-  }
-  public static final RegistrationSyncMessageAccessor REGISTRATION_SYNC_MESSAGE_ACCESSOR = new RegistrationSyncMessageAccessor();
-  
-  /** Class to access fields in {@link RegistrationSyncRequestMessage} protos. */
-  public static class RegistrationSyncRequestMessageAccessor implements Accessor {
-    private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-      Arrays.<String>asList(
-      ));
-    
-    
-    /** Returns whether {@code field} is present in {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public boolean hasField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      RegistrationSyncRequestMessage message = (RegistrationSyncRequestMessage) rawMessage;
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    /** Returns the {@code field} from {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public Object getField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      RegistrationSyncRequestMessage message = (RegistrationSyncRequestMessage) rawMessage;
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    @Override
-    public Set<String> getAllFieldNames() {
-      return ALL_FIELD_NAMES;
-    }
-  }
-  public static final RegistrationSyncRequestMessageAccessor REGISTRATION_SYNC_REQUEST_MESSAGE_ACCESSOR = new RegistrationSyncRequestMessageAccessor();
-  
-  /** Class to access fields in {@link ServerHeader} protos. */
-  public static class ServerHeaderAccessor implements Accessor {
-    private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-      Arrays.<String>asList(
-        "protocol_version",
-        "client_token",
-        "registration_summary",
-        "server_time_ms",
-        "message_id"
-      ));
-    
-    public static final Descriptor PROTOCOL_VERSION = new Descriptor("protocol_version");
-    public static final Descriptor CLIENT_TOKEN = new Descriptor("client_token");
-    public static final Descriptor REGISTRATION_SUMMARY = new Descriptor("registration_summary");
-    public static final Descriptor SERVER_TIME_MS = new Descriptor("server_time_ms");
-    public static final Descriptor MESSAGE_ID = new Descriptor("message_id");
-    
-    /** Returns whether {@code field} is present in {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public boolean hasField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      ServerHeader message = (ServerHeader) rawMessage;
-      if (field == PROTOCOL_VERSION) {
-        return message.hasProtocolVersion();
-      }
-      if (field == CLIENT_TOKEN) {
-        return message.hasClientToken();
-      }
-      if (field == REGISTRATION_SUMMARY) {
-        return message.hasRegistrationSummary();
-      }
-      if (field == SERVER_TIME_MS) {
-        return message.hasServerTimeMs();
-      }
-      if (field == MESSAGE_ID) {
-        return message.hasMessageId();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    /** Returns the {@code field} from {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public Object getField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      ServerHeader message = (ServerHeader) rawMessage;
-      if (field == PROTOCOL_VERSION) {
-        return message.getProtocolVersion();
-      }
-      if (field == CLIENT_TOKEN) {
-        return message.getClientToken();
-      }
-      if (field == REGISTRATION_SUMMARY) {
-        return message.getRegistrationSummary();
-      }
-      if (field == SERVER_TIME_MS) {
-        return message.getServerTimeMs();
-      }
-      if (field == MESSAGE_ID) {
-        return message.getMessageId();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    @Override
-    public Set<String> getAllFieldNames() {
-      return ALL_FIELD_NAMES;
-    }
-  }
-  public static final ServerHeaderAccessor SERVER_HEADER_ACCESSOR = new ServerHeaderAccessor();
-  
-  /** Class to access fields in {@link ServerToClientMessage} protos. */
-  public static class ServerToClientMessageAccessor implements Accessor {
-    private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-      Arrays.<String>asList(
-        "header",
-        "token_control_message",
-        "invalidation_message",
-        "registration_status_message",
-        "registration_sync_request_message",
-        "config_change_message",
-        "info_request_message",
-        "error_message"
-      ));
-    
-    public static final Descriptor HEADER = new Descriptor("header");
-    public static final Descriptor TOKEN_CONTROL_MESSAGE = new Descriptor("token_control_message");
-    public static final Descriptor INVALIDATION_MESSAGE = new Descriptor("invalidation_message");
-    public static final Descriptor REGISTRATION_STATUS_MESSAGE = new Descriptor("registration_status_message");
-    public static final Descriptor REGISTRATION_SYNC_REQUEST_MESSAGE = new Descriptor("registration_sync_request_message");
-    public static final Descriptor CONFIG_CHANGE_MESSAGE = new Descriptor("config_change_message");
-    public static final Descriptor INFO_REQUEST_MESSAGE = new Descriptor("info_request_message");
-    public static final Descriptor ERROR_MESSAGE = new Descriptor("error_message");
-    
-    /** Returns whether {@code field} is present in {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public boolean hasField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      ServerToClientMessage message = (ServerToClientMessage) rawMessage;
-      if (field == HEADER) {
-        return message.hasHeader();
-      }
-      if (field == TOKEN_CONTROL_MESSAGE) {
-        return message.hasTokenControlMessage();
-      }
-      if (field == INVALIDATION_MESSAGE) {
-        return message.hasInvalidationMessage();
-      }
-      if (field == REGISTRATION_STATUS_MESSAGE) {
-        return message.hasRegistrationStatusMessage();
-      }
-      if (field == REGISTRATION_SYNC_REQUEST_MESSAGE) {
-        return message.hasRegistrationSyncRequestMessage();
-      }
-      if (field == CONFIG_CHANGE_MESSAGE) {
-        return message.hasConfigChangeMessage();
-      }
-      if (field == INFO_REQUEST_MESSAGE) {
-        return message.hasInfoRequestMessage();
-      }
-      if (field == ERROR_MESSAGE) {
-        return message.hasErrorMessage();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    /** Returns the {@code field} from {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public Object getField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      ServerToClientMessage message = (ServerToClientMessage) rawMessage;
-      if (field == HEADER) {
-        return message.getHeader();
-      }
-      if (field == TOKEN_CONTROL_MESSAGE) {
-        return message.getTokenControlMessage();
-      }
-      if (field == INVALIDATION_MESSAGE) {
-        return message.getInvalidationMessage();
-      }
-      if (field == REGISTRATION_STATUS_MESSAGE) {
-        return message.getRegistrationStatusMessage();
-      }
-      if (field == REGISTRATION_SYNC_REQUEST_MESSAGE) {
-        return message.getRegistrationSyncRequestMessage();
-      }
-      if (field == CONFIG_CHANGE_MESSAGE) {
-        return message.getConfigChangeMessage();
-      }
-      if (field == INFO_REQUEST_MESSAGE) {
-        return message.getInfoRequestMessage();
-      }
-      if (field == ERROR_MESSAGE) {
-        return message.getErrorMessage();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    @Override
-    public Set<String> getAllFieldNames() {
-      return ALL_FIELD_NAMES;
-    }
-  }
-  public static final ServerToClientMessageAccessor SERVER_TO_CLIENT_MESSAGE_ACCESSOR = new ServerToClientMessageAccessor();
-  
-  /** Class to access fields in {@link StatusP} protos. */
-  public static class StatusPAccessor implements Accessor {
-    private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-      Arrays.<String>asList(
-        "code",
-        "description"
-      ));
-    
-    public static final Descriptor CODE = new Descriptor("code");
-    public static final Descriptor DESCRIPTION = new Descriptor("description");
-    
-    /** Returns whether {@code field} is present in {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public boolean hasField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      StatusP message = (StatusP) rawMessage;
-      if (field == CODE) {
-        return message.hasCode();
-      }
-      if (field == DESCRIPTION) {
-        return message.hasDescription();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    /** Returns the {@code field} from {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public Object getField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      StatusP message = (StatusP) rawMessage;
-      if (field == CODE) {
-        return message.getCode();
-      }
-      if (field == DESCRIPTION) {
-        return message.getDescription();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    @Override
-    public Set<String> getAllFieldNames() {
-      return ALL_FIELD_NAMES;
-    }
-  }
-  public static final StatusPAccessor STATUS_P_ACCESSOR = new StatusPAccessor();
-  
-  /** Class to access fields in {@link TokenControlMessage} protos. */
-  public static class TokenControlMessageAccessor implements Accessor {
-    private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-      Arrays.<String>asList(
-        "new_token"
-      ));
-    
-    public static final Descriptor NEW_TOKEN = new Descriptor("new_token");
-    
-    /** Returns whether {@code field} is present in {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public boolean hasField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      TokenControlMessage message = (TokenControlMessage) rawMessage;
-      if (field == NEW_TOKEN) {
-        return message.hasNewToken();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    /** Returns the {@code field} from {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public Object getField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      TokenControlMessage message = (TokenControlMessage) rawMessage;
-      if (field == NEW_TOKEN) {
-        return message.getNewToken();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    @Override
-    public Set<String> getAllFieldNames() {
-      return ALL_FIELD_NAMES;
-    }
-  }
-  public static final TokenControlMessageAccessor TOKEN_CONTROL_MESSAGE_ACCESSOR = new TokenControlMessageAccessor();
-  
-  /** Class to access fields in {@link Version} protos. */
-  public static class VersionAccessor implements Accessor {
-    private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-      Arrays.<String>asList(
-        "major_version",
-        "minor_version"
-      ));
-    
-    public static final Descriptor MAJOR_VERSION = new Descriptor("major_version");
-    public static final Descriptor MINOR_VERSION = new Descriptor("minor_version");
-    
-    /** Returns whether {@code field} is present in {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public boolean hasField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      Version message = (Version) rawMessage;
-      if (field == MAJOR_VERSION) {
-        return message.hasMajorVersion();
-      }
-      if (field == MINOR_VERSION) {
-        return message.hasMinorVersion();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    /** Returns the {@code field} from {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public Object getField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      Version message = (Version) rawMessage;
-      if (field == MAJOR_VERSION) {
-        return message.getMajorVersion();
-      }
-      if (field == MINOR_VERSION) {
-        return message.getMinorVersion();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    @Override
-    public Set<String> getAllFieldNames() {
-      return ALL_FIELD_NAMES;
-    }
-  }
-  public static final VersionAccessor VERSION_ACCESSOR = new VersionAccessor();
-  
-}
diff --git a/java/com/google/ipc/invalidation/common/CommonInvalidationConstants2.java b/java/com/google/ipc/invalidation/common/CommonInvalidationConstants2.java
deleted file mode 100644
index 4cca6ec..0000000
--- a/java/com/google/ipc/invalidation/common/CommonInvalidationConstants2.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * 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.common;
-
-import com.google.protobuf.ByteString;
-import com.google.protos.ipc.invalidation.ClientProtocol.ObjectIdP;
-import com.google.protos.ipc.invalidation.ClientProtocol.ProtocolVersion;
-import com.google.protos.ipc.invalidation.ClientProtocol.Version;
-import com.google.protos.ipc.invalidation.Types.ClientType;
-import com.google.protos.ipc.invalidation.Types.ObjectSource;
-
-/**
- * Various constants common to  clients and servers used in version 2 of the Ticl.
- *
- */
-public class CommonInvalidationConstants2 {
-
-  /** Major version of the client library. */
-  public static final int CLIENT_MAJOR_VERSION = 3;
-
-  /**
-   * Minor version of the client library, defined to be equal to the datestamp of the build
-   * (e.g. 20130401).
-   */
-  public static final int CLIENT_MINOR_VERSION = BuildConstants.BUILD_DATESTAMP;
-
-  /** Major version of the protocol between the client and the server. */
-  public static final int PROTOCOL_MAJOR_VERSION = 3;
-
-  /** Minor version of the protocol between the client and the server. */
-  public static final int PROTOCOL_MINOR_VERSION = 2;
-
-  /** Major version of the client config. */
-  public static final int CONFIG_MAJOR_VERSION = 3;
-
-  /** Minor version of the client config. */
-  public static final int CONFIG_MINOR_VERSION = 2;
-
-  /** Version of the protocol currently being used by the client/server for v2 clients. */
-  public static final ProtocolVersion PROTOCOL_VERSION = ProtocolVersion.newBuilder()
-      .setVersion(CommonProtos2.newVersion(PROTOCOL_MAJOR_VERSION, PROTOCOL_MINOR_VERSION)).build();
-
-  /** Version of the protocol currently being used by the client/server for v1 clients. */
-  public static final ProtocolVersion PROTOCOL_VERSION_V1 = ProtocolVersion.newBuilder()
-      .setVersion(CommonProtos2.newVersion(2, 0)).build();
-
-  /** Version of the client currently being used by the client. */
-  public static final Version CLIENT_VERSION_VALUE =
-      CommonProtos2.newVersion(CLIENT_MAJOR_VERSION, CLIENT_MINOR_VERSION);
-
-  /** The value of ObjectSource.Type from types.proto. Must be kept in sync with that file. */
-  public static final int INTERNAL_OBJECT_SOURCE_TYPE = ObjectSource.Type.INTERNAL.getNumber();
-
-  /** The value of ObjectSource.Type from types.proto. Must be kept in sync with that file. */
-  public static final int TEST_OBJECT_SOURCE_TYPE = ObjectSource.Type.TEST.getNumber();
-
-  /** The value of ClientType.Type from types.proto. Must be kept in sync with that file. */
-  public static final int INTERNAL_CLIENT_TYPE = ClientType.Type.INTERNAL.getNumber();
-
-  /** The value of ClientType.Type from types.proto. Must be kept in sync with that file. */
-  public static final int TEST_CLIENT_TYPE = ClientType.Type.TEST.getNumber();
-
-  /** Object id used to trigger a refresh of all cached objects ("invalidate-all"). */
-  public static final ObjectIdP ALL_OBJECT_ID = ObjectIdP.newBuilder()
-      .setName(ByteString.EMPTY)
-      .setSource(INTERNAL_OBJECT_SOURCE_TYPE)
-      .build();
-}
diff --git a/java/com/google/ipc/invalidation/common/CommonProtoStrings2.java b/java/com/google/ipc/invalidation/common/CommonProtoStrings2.java
deleted file mode 100644
index fc7ebf7..0000000
--- a/java/com/google/ipc/invalidation/common/CommonProtoStrings2.java
+++ /dev/null
@@ -1,650 +0,0 @@
-/*
- * 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.common;
-
-import com.google.common.base.Receiver;
-import com.google.ipc.invalidation.util.Bytes;
-import com.google.ipc.invalidation.util.LazyString;
-import com.google.ipc.invalidation.util.TextBuilder;
-import com.google.protobuf.ByteString;
-import com.google.protos.ipc.invalidation.ClientProtocol.ApplicationClientIdP;
-import com.google.protos.ipc.invalidation.ClientProtocol.ClientHeader;
-import com.google.protos.ipc.invalidation.ClientProtocol.ClientToServerMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.ConfigChangeMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.ErrorMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.InfoMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.InfoRequestMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.InitializeMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.InvalidationMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.InvalidationP;
-import com.google.protos.ipc.invalidation.ClientProtocol.ObjectIdP;
-import com.google.protos.ipc.invalidation.ClientProtocol.PropertyRecord;
-import com.google.protos.ipc.invalidation.ClientProtocol.ProtocolVersion;
-import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationP;
-import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationStatus;
-import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationStatusMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationSubtree;
-import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationSummary;
-import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationSyncMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationSyncRequestMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.ServerHeader;
-import com.google.protos.ipc.invalidation.ClientProtocol.ServerToClientMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.StatusP;
-import com.google.protos.ipc.invalidation.ClientProtocol.TokenControlMessage;
-
-import java.util.Collection;
-
-
-/**
- * Utilities to make it easier/cleaner/shorter for printing and converting protobufs to strings in
- * . This class exposes methods to return objects such that their toString method returns a
- * compact representation of the proto. These methods can be used in the Ticl
- *
- */
-public class CommonProtoStrings2 {
-
-  //
-  // Implementation notes: The following methods return the object as mentioned above for different
-  // protos. Each method (except for a couple of them) essentially calls a private static method
-  // that uses a TextBuilder to construct the final string. Each method has the following spec:
-  // Returns a compact string representation for {@code <parameter-name>} for logging
-  //
-
-  /** See spec in implementation notes. */
-  public static Object toLazyCompactString(final ByteString byteString) {
-    if (byteString == null) {
-      return null;
-    }
-    return new Object() {
-      @Override
-      public String toString() {
-        return Bytes.toString(byteString.toByteArray());
-      }
-    };
-  }
-
-  /** See spec in implementation notes. */
-  public static Object toLazyCompactString(final byte[] bytes) {
-    if (bytes == null) {
-      return null;
-    }
-    return new Object() {
-      @Override
-      public String toString() {
-        return Bytes.toString(bytes);
-      }
-    };
-  }
-
-  /** See spec in implementation notes. */
-  public static Object toLazyCompactString(final ObjectIdP objectId) {
-    return LazyString.toLazyCompactString(objectId, new Receiver<TextBuilder>() {
-      @Override
-      public void accept(TextBuilder builder) {
-        toCompactString(builder, objectId);
-      }
-    });
-  }
-
-  /** See spec in implementation notes. */
-  public static Object toLazyCompactString(final InvalidationP invalidation) {
-    return LazyString.toLazyCompactString(invalidation, new Receiver<TextBuilder>() {
-      @Override
-      public void accept(TextBuilder builder) {
-        toCompactString(builder, invalidation);
-      }
-    });
-  }
-
-  /** See spec in implementation notes. */
-  public static Object toLazyCompactString(final RegistrationP registration) {
-    return LazyString.toLazyCompactString(registration, new Receiver<TextBuilder>() {
-      @Override
-      public void accept(TextBuilder builder) {
-        toCompactString(builder, registration);
-      }
-    });
-  }
-
-  /** See spec in implementation notes. */
-  public static Object toLazyCompactString(final ApplicationClientIdP applicationId) {
-    return LazyString.toLazyCompactString(applicationId, new Receiver<TextBuilder>() {
-      @Override
-      public void accept(TextBuilder builder) {
-        toCompactString(builder, applicationId);
-      }
-    });
-  }
-
-  /** See spec in implementation notes. */
-  public static Object toLazyCompactString(final RegistrationSummary regSummary) {
-    return LazyString.toLazyCompactString(regSummary, new Receiver<TextBuilder>() {
-      @Override
-      public void accept(TextBuilder builder) {
-        toCompactString(builder, regSummary);
-      }
-    });
-  }
-
-  /** See spec in implementation notes. */
-  public static Object toLazyCompactString(final InfoMessage infoMessage) {
-    return LazyString.toLazyCompactString(infoMessage, new Receiver<TextBuilder>() {
-      @Override
-      public void accept(TextBuilder builder) {
-        toCompactString(builder, infoMessage);
-      }
-    });
-  }
-
-  /** See spec in implementation notes. */
-  public static Object toLazyCompactString(final RegistrationSyncMessage syncMessage) {
-    return LazyString.toLazyCompactString(syncMessage, new Receiver<TextBuilder>() {
-      @Override
-      public void accept(TextBuilder builder) {
-        toCompactString(builder, syncMessage);
-      }
-    });
-  }
-
-  /** See spec in implementation notes and toCompactString for ClientToServerMessage. */
-  public static Object toLazyCompactString(final ClientToServerMessage message,
-      final boolean printHighFrequencyMessages) {
-    return LazyString.toLazyCompactString(message, new Receiver<TextBuilder>() {
-      @Override
-      public void accept(TextBuilder builder) {
-        toCompactString(builder, message, printHighFrequencyMessages);
-      }
-    });
-  }
-
-  /** See spec in implementation notes and toCompactString for ServerToClientMessage. */
-  public static Object toLazyCompactString(final ServerToClientMessage message,
-      final boolean printHighFrequencyMessages) {
-    return LazyString.toLazyCompactString(message, new Receiver<TextBuilder>() {
-      @Override
-      public void accept(TextBuilder builder) {
-        toCompactString(builder, message, printHighFrequencyMessages);
-      }
-    });
-  }
-
-
-  /** See spec in implementation notes. */
-  public static Object toLazyCompactStringForObjectIds(
-      final Collection<ObjectIdP> objectIds) {
-    return LazyString.toLazyCompactString(objectIds, new Receiver<TextBuilder>() {
-      @Override
-      public void accept(TextBuilder builder) {
-        toCompactStringForObjectIds(builder, objectIds);
-      }
-    });
-  }
-
-  /** See spec in implementation notes. */
-  public static Object toLazyCompactStringForInvalidations(
-      final Collection<InvalidationP> invalidations) {
-    return LazyString.toLazyCompactString(invalidations, new Receiver<TextBuilder>() {
-      @Override
-      public void accept(TextBuilder builder) {
-        toCompactStringForInvalidations(builder, invalidations);
-      }
-    });
-  }
-
-  /** See spec in implementation notes. */
-  public static Object toLazyCompactStringForRegistrations(
-      final Collection<RegistrationP> registrations) {
-    return LazyString.toLazyCompactString(registrations, new Receiver<TextBuilder>() {
-      @Override
-      public void accept(TextBuilder builder) {
-        toCompactStringForRegistrations(builder, registrations);
-      }
-    });
-  }
-
-  //
-  // Implementation notes: The following helper methods do the actual conversion of the proto into
-  // the compact representation in the given builder. Each method has the following spec:
-  // Adds a compact representation for {@code <parameter-name>} to {@code builder} and
-  // returns {@code builder}.
-  // TODO: Look into building indirection tables for the collections to avoid
-  // code duplication.
-  //
-
-  /** See spec in implementation notes. */
-  public static TextBuilder toCompactString(TextBuilder builder, ByteString byteString) {
-    if (byteString == null) {
-      return builder;
-    }
-    return Bytes.toCompactString(builder, byteString.toByteArray());
-  }
-
-  /** See spec in implementation notes. */
-  public static TextBuilder toCompactString(TextBuilder builder, ObjectIdP objectId) {
-    if (objectId == null) {
-      return builder;
-    }
-    builder.appendFormat("(Obj: %s, ", objectId.getSource());
-    toCompactString(builder, objectId.getName());
-    builder.append(')');
-    return builder;
-  }
-
-  /** See spec in implementation notes. */
-  public static TextBuilder toCompactString(TextBuilder builder,
-      InvalidationP invalidation) {
-    if (invalidation == null) {
-      return builder;
-    }
-    builder.append("(Inv: ");
-    toCompactString(builder, invalidation.getObjectId());
-    builder.append(", ");
-    if (invalidation.getIsTrickleRestart()) {
-      builder.append("<");
-    }
-    builder.append(invalidation.getVersion());
-    if (invalidation.hasPayload()) {
-      builder.append(", P:");
-      toCompactString(builder, invalidation.getPayload());
-    }
-    builder.append(')');
-    return builder;
-  }
-
- /** See spec in implementation notes. */
-  public static TextBuilder toCompactStringForInvalidations(TextBuilder builder,
-      final Collection<InvalidationP> invalidations) {
-    if (invalidations == null) {
-      return builder;
-    }
-    boolean first = true;
-    for (InvalidationP invalidation : invalidations) {
-      if (!first) {
-        builder.append(", ");
-      }
-      toCompactString(builder, invalidation);
-      first = false;
-    }
-    return builder;
-  }
-
-  /** See spec in implementation notes. */
-  public static TextBuilder toCompactString(TextBuilder builder, StatusP status) {
-    if (status == null) {
-      return builder;
-    }
-    builder.appendFormat("Status: %s", status.getCode());
-    if (status.hasDescription()) {
-      builder.appendFormat(", Desc: %s", status.getDescription());
-    }
-    return builder;
-  }
-
-
-  /** See spec in implementation notes. */
-  public static TextBuilder toCompactString(TextBuilder builder, RegistrationP regOp) {
-    if (regOp == null) {
-      return builder;
-    }
-    builder.appendFormat("RegOp: %s, ",
-        regOp.getOpType() == RegistrationP.OpType.REGISTER ? "R" : "U");
-    toCompactString(builder, regOp.getObjectId());
-    return builder;
-  }
-
-  public static TextBuilder toCompactString(TextBuilder builder,
-      RegistrationStatus regStatus) {
-    if (regStatus == null) {
-      return builder;
-    }
-    builder.append('<');
-    toCompactString(builder, regStatus.getRegistration());
-    builder.append(", ");
-    toCompactString(builder, regStatus.getStatus());
-    builder.append('>');
-    return builder;
-  }
-
-  /** See spec in implementation notes. */
-  public static TextBuilder toCompactStringForRegistrations(TextBuilder builder,
-      Collection<RegistrationP> registrations) {
-    if (registrations == null) {
-      return builder;
-    }
-
-    boolean first = true;
-    builder.append("RegOps: ");
-    for (RegistrationP registration : registrations) {
-      if (!first) {
-        builder.append(", ");
-      }
-      toCompactString(builder, registration);
-      first = false;
-    }
-    return builder;
-  }
-
-  /** See spec in implementation notes. */
-  public static TextBuilder toCompactStringForRegistrationStatuses(TextBuilder builder,
-      Collection<RegistrationStatus> registrationStatuses) {
-    if (registrationStatuses == null) {
-      return builder;
-    }
-
-    boolean first = true;
-    builder.append("RegOps: ");
-    for (RegistrationStatus registrationStatus : registrationStatuses) {
-      if (!first) {
-        builder.append(", ");
-      }
-      toCompactString(builder, registrationStatus);
-      first = false;
-    }
-    return builder;
-  }
-
-  /** See spec in implementation notes. */
-  public static TextBuilder toCompactStringForObjectIds(TextBuilder builder,
-      Collection<ObjectIdP> objectIds) {
-    if (objectIds == null) {
-      return builder;
-    }
-    boolean first = true;
-    builder.append("ObjectIds: ");
-    for (ObjectIdP objectId : objectIds) {
-      if (!first) {
-        builder.append(", ");
-      }
-      toCompactString(builder, objectId);
-      first = false;
-    }
-    return builder;
-  }
-
-  /** See spec in implementation notes. */
-  private static TextBuilder toCompactString(TextBuilder builder,
-      ApplicationClientIdP applicationClientId) {
-    if (applicationClientId == null) {
-      return builder;
-    }
-    builder.appendFormat("(Ceid: ");
-    toCompactString(builder, applicationClientId.getClientName());
-    builder.append(')');
-    return builder;
-  }
-
-  /** See spec in implementation notes. */
-  public static TextBuilder toCompactString(TextBuilder builder,
-      RegistrationSummary regSummary) {
-    if (regSummary == null) {
-      return builder;
-    }
-
-    builder.appendFormat("<RegSummary: Num = %d, Hash = ", regSummary.getNumRegistrations());
-    CommonProtoStrings2.toCompactString(builder, regSummary.getRegistrationDigest());
-    builder.append('>');
-    return builder;
-  }
-
-  public static TextBuilder toCompactString(TextBuilder builder,
-      ProtocolVersion protocolVersion) {
-    if (protocolVersion == null) {
-      return builder;
-    }
-    builder.appendFormat("%d.%d", protocolVersion.getVersion().getMajorVersion(),
-        protocolVersion.getVersion().getMinorVersion());
-    return builder;
-  }
-
-  // Print methods for every client-to-server message type.
-
-  /** See spec in implementation notes. */
-  public static TextBuilder toCompactString(TextBuilder builder, ClientHeader header) {
-    if (header == null) {
-      return builder;
-    }
-    builder.append("C2S: ");
-    toCompactString(builder, header.getProtocolVersion());
-    builder.appendFormat(", MsgId: %s, Num regs = %s, Token = ", header.getMessageId(),
-        header.getRegistrationSummary().getNumRegistrations());
-    toCompactString(builder, header.getClientToken());
-    return builder;
-  }
-
-  /** See spec in implementation notes. */
-  public static TextBuilder toCompactString(TextBuilder builder,
-      InitializeMessage initializeMessage) {
-    if (initializeMessage == null) {
-      return builder;
-    }
-    builder.appendFormat("InitMsg: Client Type: %d, ", initializeMessage.getClientType());
-    toCompactString(builder, initializeMessage.getApplicationClientId());
-    return builder;
-  }
-
-  /** See spec in implementation notes. */
-  public static TextBuilder toCompactString(TextBuilder builder,
-      RegistrationMessage registrationMessage) {
-    if (registrationMessage == null) {
-      return builder;
-    }
-    builder.appendFormat("RegMsg: ");
-    toCompactStringForRegistrations(builder, registrationMessage.getRegistrationList());
-    return builder;
-  }
-
-  /** See spec in implementation notes. */
-  public static TextBuilder toCompactString(TextBuilder builder,
-      RegistrationSyncMessage syncMessage) {
-    if (syncMessage == null) {
-      return builder;
-    }
-    RegistrationSubtree subtree = syncMessage.getSubtree(0);
-    builder.appendFormat("RegSyncMsg: Num regs: %d, Regs: ", subtree.getRegisteredObjectCount());
-    toCompactStringForObjectIds(builder, subtree.getRegisteredObjectList());
-    return builder;
-  }
-
-  /** See spec in implementation notes. */
-  public static TextBuilder toCompactString(TextBuilder builder,
-      InfoMessage infoMessage) {
-    if (infoMessage == null) {
-      return builder;
-    }
-    builder.appendFormat("InfoMsg: Platform = %s, Is_summary_requested = %s, Perf counters: ",
-        infoMessage.getClientVersion().getPlatform(),
-        infoMessage.getServerRegistrationSummaryRequested());
-    boolean first = true;
-    for (PropertyRecord record : infoMessage.getPerformanceCounterList()) {
-      if (!first) {
-        builder.append(", ");
-      }
-      builder.appendFormat("%s = %d", record.getName(), record.getValue());
-      first = false;
-    }
-    return builder;
-  }
-
-  /** See spec in implementation notes. */
-  public static TextBuilder toCompactString(TextBuilder builder,
-      InvalidationMessage invMessage) {
-    if (invMessage == null) {
-      return builder;
-    }
-    builder.appendFormat("InvMsg: ");
-    toCompactStringForInvalidations(builder, invMessage.getInvalidationList());
-    return builder;
-  }
-
-  // Print methods for every server-to-client message type.
-
-  public static TextBuilder toCompactString(TextBuilder builder, ServerHeader header) {
-    if (header == null) {
-      return builder;
-    }
-    builder.append("S2C: ");
-    toCompactString(builder, header.getProtocolVersion());
-    builder.appendFormat(", MsgId: %s, Num regs = %s, Token = ", header.getMessageId(),
-        header.getRegistrationSummary().getNumRegistrations());
-    toCompactString(builder, header.getClientToken());
-    return builder;
-  }
-
-  /** See spec in implementation notes. */
-  public static TextBuilder toCompactString(TextBuilder builder,
-      TokenControlMessage tokenControlMessage) {
-    if (tokenControlMessage == null) {
-      return builder;
-    }
-    builder.append("TokenMsg: ");
-    toCompactString(builder, tokenControlMessage.getNewToken());
-    return builder;
-  }
-
-  /** See spec in implementation notes. */
-  public static TextBuilder toCompactString(TextBuilder builder,
-      RegistrationStatusMessage regStatusMessage) {
-    if (regStatusMessage == null) {
-      return builder;
-    }
-    builder.append("RegStatusMsg: ");
-    toCompactStringForRegistrationStatuses(builder, regStatusMessage.getRegistrationStatusList());
-    return builder;
-  }
-
-  /** See spec in implementation notes. */
-  public static TextBuilder toCompactString(TextBuilder builder,
-      RegistrationSyncRequestMessage regSyncRequestMessage) {
-    if (regSyncRequestMessage == null) {
-      return builder;
-    }
-    builder.append("RegSyncRequestMsg: ");
-    return builder;
-  }
-
-  /** See spec in implementation notes. */
-  public static TextBuilder toCompactString(TextBuilder builder,
-      InfoRequestMessage infoRequestMessage) {
-    if (infoRequestMessage == null) {
-      return builder;
-    }
-    builder.append("InfoRequestMsg:");
-    return builder;
-  }
-
-  /** See spec in implementation notes. */
-  public static TextBuilder toCompactString(TextBuilder builder,
-      ConfigChangeMessage configChangeMessage) {
-    if (configChangeMessage == null) {
-      return builder;
-    }
-    builder.appendFormat("ConfigChangeMsg: %d", configChangeMessage.getNextMessageDelayMs());
-    return builder;
-  }
-
-  /** See spec in implementation notes. */
-  public static TextBuilder toCompactString(TextBuilder builder,
-      ErrorMessage errorMessage) {
-    if (errorMessage == null) {
-      return builder;
-    }
-    builder.appendFormat("ErrorMsg: %s, %s", errorMessage.getCode(), errorMessage.getDescription());
-    return builder;
-  }
-
-  /**
-   * If {@code printHighFrequencyMessages} is true, logs sub-messages that are exchanged at a high
-   * frequency between the client and the registrar, e.g., invalidation ack message, heartbeat
-   * message.
-   */
-  public static TextBuilder toCompactString(TextBuilder builder,
-      ClientToServerMessage msg, boolean printHighFrequencyMessages) {
-    // Print the header and any sub-messages in the message.
-
-    toCompactString(builder, msg.getHeader());
-    builder.append(',');
-
-    if (msg.hasInitializeMessage()) {
-      toCompactString(builder, msg.getInitializeMessage());
-      builder.append(',');
-    }
-    if (msg.hasRegistrationMessage()) {
-      toCompactString(builder, msg.getRegistrationMessage());
-      builder.append(',');
-    }
-    if (msg.hasRegistrationSyncMessage()) {
-      toCompactString(builder, msg.getRegistrationSyncMessage());
-      builder.append(',');
-    }
-    if (printHighFrequencyMessages && msg.hasInvalidationAckMessage()) {
-      toCompactString(builder, msg.getInvalidationAckMessage());
-      builder.append(',');
-    }
-    if (printHighFrequencyMessages && msg.hasInfoMessage()) {
-      toCompactString(builder, msg.getInfoMessage());
-      builder.append(',');
-    }
-    return builder;
-  }
-
-  /**
-   * If {@code printHighFrequencyMessages} is true, logs sub-messages that are exchanged at a high
-   * frequency between the client and the registrar (if they are the only messages present),
-   * e.g., invalidation message.
-   */
-  public static TextBuilder toCompactString(TextBuilder builder,
-      ServerToClientMessage msg, boolean printHighFrequencyMessages) {
-    // Print the header and any sub-messages in the message.
-
-    toCompactString(builder, msg.getHeader());
-    builder.append(',');
-
-    if (msg.hasTokenControlMessage()) {
-      toCompactString(builder, msg.getTokenControlMessage());
-      builder.append(',');
-    }
-    if (printHighFrequencyMessages && msg.hasInvalidationMessage()) {
-      toCompactString(builder, msg.getInvalidationMessage());
-      builder.append(',');
-    }
-    if (msg.hasErrorMessage()) {
-      toCompactString(builder, msg.getErrorMessage());
-      builder.append(',');
-    }
-    if (msg.hasRegistrationSyncRequestMessage()) {
-      toCompactString(builder, msg.getRegistrationSyncRequestMessage());
-      builder.append(',');
-    }
-    if (msg.hasRegistrationStatusMessage()) {
-      toCompactString(builder, msg.getRegistrationStatusMessage());
-      builder.append(',');
-    }
-    if (msg.hasInfoRequestMessage()) {
-      toCompactString(builder, msg.getInfoRequestMessage());
-      builder.append(',');
-    }
-    if (msg.hasConfigChangeMessage()) {
-      toCompactString(builder, msg.getConfigChangeMessage());
-      builder.append(',');
-    }
-    return builder;
-  }
-
-  private CommonProtoStrings2() { // To prevent instantiation
-  }
-}
diff --git a/java/com/google/ipc/invalidation/common/CommonProtos2.java b/java/com/google/ipc/invalidation/common/CommonProtos2.java
deleted file mode 100644
index 8c7bb4b..0000000
--- a/java/com/google/ipc/invalidation/common/CommonProtos2.java
+++ /dev/null
@@ -1,457 +0,0 @@
-/*
- * 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.common;
-
-import com.google.common.base.Preconditions;
-import com.google.protobuf.ByteString;
-import com.google.protos.ipc.invalidation.AndroidChannel;
-import com.google.protos.ipc.invalidation.ChannelCommon.NetworkEndpointId;
-import com.google.protos.ipc.invalidation.ChannelCommon.NetworkEndpointId.NetworkAddress;
-import com.google.protos.ipc.invalidation.Client.AckHandleP;
-import com.google.protos.ipc.invalidation.Client.PersistentStateBlob;
-import com.google.protos.ipc.invalidation.Client.PersistentTiclState;
-import com.google.protos.ipc.invalidation.ClientProtocol.ApplicationClientIdP;
-import com.google.protos.ipc.invalidation.ClientProtocol.ClientVersion;
-import com.google.protos.ipc.invalidation.ClientProtocol.ConfigChangeMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.ErrorMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.InfoRequestMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.InitializeMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.InitializeMessage.DigestSerializationType;
-import com.google.protos.ipc.invalidation.ClientProtocol.InvalidationMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.InvalidationP;
-import com.google.protos.ipc.invalidation.ClientProtocol.ObjectIdP;
-import com.google.protos.ipc.invalidation.ClientProtocol.PropertyRecord;
-import com.google.protos.ipc.invalidation.ClientProtocol.RateLimitP;
-import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationP;
-import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationStatus;
-import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationStatusMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationSubtree;
-import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationSummary;
-import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationSyncMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationSyncRequestMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.ServerHeader;
-import com.google.protos.ipc.invalidation.ClientProtocol.ServerToClientMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.StatusP;
-import com.google.protos.ipc.invalidation.ClientProtocol.TokenControlMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.Version;
-
-import java.util.Collection;
-import java.util.List;
-
-
-/**
- * Utilities for creating protocol buffers.
- *
- */
-public class CommonProtos2 {
-
-
-  /** Returns true iff status corresponds to success. */
-  public static boolean isSuccess(StatusP status) {
-    return status.getCode() == StatusP.Code.SUCCESS;
-  }
-
-  /** Returns true iff status corresponds to transient failure. */
-  public static boolean isTransientFailure(StatusP status) {
-    return status.getCode() == StatusP.Code.TRANSIENT_FAILURE;
-  }
-
-  /** Returns true iff status corresponds to permanent failure. */
-  public static boolean isPermanentFailure(StatusP status) {
-    return status.getCode() == StatusP.Code.PERMANENT_FAILURE;
-  }
-
-  // The following methods help in creating a protobuf object given its components. A Nullable
-  // parameter implies that the particular field will not be set for that proto.
-  // For the specs, please see the corresponding Proto file (to avoid inconsistency due to
-  // duplication).
-
-  public static Version newVersion(int majorVersion, int minorVersion) {
-    return Version.newBuilder().setMajorVersion(majorVersion).setMinorVersion(minorVersion).build();
-  }
-
-  public static ClientVersion newClientVersion(String platform, String language,
-      String applicationInfo) {
-    return ClientVersion.newBuilder()
-        .setVersion(CommonInvalidationConstants2.CLIENT_VERSION_VALUE)
-        .setPlatform(platform)
-        .setLanguage(language)
-        .setApplicationInfo(applicationInfo)
-        .build();
-  }
-
-  public static ObjectIdP newObjectIdP(int source, ByteString name) {
-    return ObjectIdP.newBuilder().setSource(source).setName(name).build();
-  }
-
-  public static ObjectIdP newObjectIdP(int source, byte[] name) {
-    return newObjectIdP(source, ByteString.copyFrom(name));
-  }
-
-  public static boolean isAllObjectId(ObjectIdP objectId) {
-    return (objectId != null) &&
-        (CommonInvalidationConstants2.ALL_OBJECT_ID.getSource() == objectId.getSource()) &&
-        (CommonInvalidationConstants2.ALL_OBJECT_ID.getName().equals(objectId.getName()));
-
-  }
-
-  public static RateLimitP newRateLimitP(int windowMs, int count) {
-    return RateLimitP.newBuilder()
-        .setWindowMs(windowMs)
-        .setCount(count)
-        .build();
-  }
-
-  public static ApplicationClientIdP newApplicationClientIdP(int clientType,
-      ByteString clientName) {
-    return ApplicationClientIdP.newBuilder()
-        .setClientType(clientType)
-        .setClientName(clientName)
-        .build();
-  }
-
-  public static InvalidationP newInvalidationP(ObjectIdP oid, long version,
-      TrickleState trickleState) {
-    return newInvalidationP(oid, version, trickleState, null);
-  }
-
-  public static InvalidationP newInvalidationP(ObjectIdP oid, long version,
-      TrickleState trickleState, ByteString payload) {
-    InvalidationP.Builder builder = InvalidationP.newBuilder()
-        .setObjectId(oid)
-        .setIsKnownVersion(true)
-        .setVersion(version)
-        .setIsTrickleRestart(trickleState == TrickleState.RESTART);
-    if (payload != null) {
-      builder.setPayload(payload);
-    }
-    return builder.build();
-  }
-
-  public static InvalidationP newInvalidationPForUnknownVersion(ObjectIdP oid,
-      long sequenceNumber) {
-    return InvalidationP.newBuilder()
-        .setObjectId(oid)
-        .setIsKnownVersion(false)
-        .setIsTrickleRestart(true)
-        .setVersion(sequenceNumber)
-        .build();
-  }
-
-  /**
-   * Returns an invalidation that is identical to {@code invalidation} but with the
-   * {@code is_trickle_restart} flag set to true. If the input {@invalidation} is already restarted,
-   * it is returned directly. Otherwise, a new invalidation is created.
-   */
-  public static InvalidationP toRestartedInvalidation(InvalidationP invalidation) {
-    if (invalidation.hasIsTrickleRestart() && invalidation.getIsTrickleRestart()) {
-      return invalidation;
-    }
-    return invalidation.toBuilder().setIsTrickleRestart(true).build();
-  }
-
-  /**
-   * Returns an invalidation that is identical to {@code invalidation} but with the
-   * {@code is_trickle_restart} flag set to false. If the input {@invalidation} is already
-   * a continuous invalidation, it is returned directly. Otherwise, a new invalidation is created.
-   */
-  public static InvalidationP toContinuousInvalidation(InvalidationP invalidation) {
-    if (invalidation.hasIsTrickleRestart() && !invalidation.getIsTrickleRestart()) {
-      return invalidation;
-    }
-    return invalidation.toBuilder().setIsTrickleRestart(false).build();
-  }
-
-  public static RegistrationP newRegistrationP(ObjectIdP oid, boolean isReg) {
-    RegistrationP registration = RegistrationP.newBuilder()
-        .setObjectId(oid)
-        .setOpType(isReg ? RegistrationP.OpType.REGISTER : RegistrationP.OpType.UNREGISTER)
-        .build();
-    return registration;
-  }
-
-  public static RegistrationP newRegistrationPForRegistration(ObjectIdP oid) {
-    return newRegistrationP(oid, true);
-  }
-
-  public static RegistrationP newRegistrationPForUnregistration(ObjectIdP oid) {
-    return newRegistrationP(oid, false);
-  }
-
-  public static StatusP newSuccessStatus() {
-    return StatusP.newBuilder().setCode(StatusP.Code.SUCCESS).build();
-  }
-
-  public static StatusP newFailureStatus(boolean isTransient, String description) {
-    return StatusP.newBuilder()
-        .setCode(isTransient ? StatusP.Code.TRANSIENT_FAILURE : StatusP.Code.PERMANENT_FAILURE)
-        .setDescription(description)
-        .build();
-  }
-
-  public static RegistrationSummary newRegistrationSummary(int numRegistrations, byte[] regDigest) {
-    RegistrationSummary regSummary = RegistrationSummary.newBuilder()
-      .setNumRegistrations(numRegistrations)
-      .setRegistrationDigest(ByteString.copyFrom(regDigest))
-      .build();
-    return regSummary;
-  }
-
-  public static RegistrationStatus newRegistrationStatus(RegistrationP registration,
-      StatusP status) {
-    return RegistrationStatus.newBuilder()
-            .setRegistration(registration)
-            .setStatus(status)
-            .build();
-  }
-
-  public static RegistrationStatus newSuccessRegistrationStatus(RegistrationP registration) {
-    return RegistrationStatus.newBuilder()
-            .setRegistration(registration)
-            .setStatus(newSuccessStatus())
-            .build();
-  }
-
-  public static RegistrationStatus newTransientFailureRegistrationStatus(
-      RegistrationP registration, String description) {
-    return RegistrationStatus.newBuilder()
-            .setRegistration(registration)
-            .setStatus(newFailureStatus(true, description))
-            .build();
-  }
-
-  public static PersistentTiclState newPersistentTiclState(ByteString clientToken,
-      long lastMessageSendTimeMs) {
-    return PersistentTiclState.newBuilder()
-        .setClientToken(clientToken)
-        .setLastMessageSendTimeMs(lastMessageSendTimeMs)
-        .build();
-  }
-
-  public static AckHandleP newAckHandleP(InvalidationP invalidation) {
-    return AckHandleP.newBuilder().setInvalidation(invalidation).build();
-  }
-
-  public static PersistentStateBlob newPersistentStateBlob(PersistentTiclState state,
-      ByteString mac) {
-    return PersistentStateBlob.newBuilder()
-        .setTiclState(state)
-        .setAuthenticationCode(mac)
-        .build();
-  }
-
-  // Methods to create ClientToServerMessages.
-
-  public static InitializeMessage newInitializeMessage(int clientType,
-      ApplicationClientIdP applicationClientId, ByteString nonce,
-      DigestSerializationType digestSerializationType) {
-    return InitializeMessage.newBuilder()
-        .setClientType(clientType)
-        .setApplicationClientId(applicationClientId)
-        .setDigestSerializationType(digestSerializationType)
-        .setNonce(nonce)
-        .build();
-  }
-
-  public static PropertyRecord newPropertyRecord(String name, int value) {
-    return PropertyRecord.newBuilder().setName(name).setValue(value).build();
-  }
-
-  // Methods to create ServerToClientMessages.
-
-  public static ServerHeader newServerHeader(ByteString clientToken, long currentTimeMs,
-      RegistrationSummary registrationSummary, String messageId) {
-    ServerHeader.Builder builder = ServerHeader.newBuilder()
-        .setProtocolVersion(CommonInvalidationConstants2.PROTOCOL_VERSION)
-        .setClientToken(clientToken)
-        .setServerTimeMs(currentTimeMs);
-    if (registrationSummary != null) {
-      builder.setRegistrationSummary(registrationSummary);
-    }
-    if (messageId != null) {
-      builder.setMessageId(messageId);
-    }
-    return builder.build();
-  }
-
-  public static ErrorMessage newErrorMessage(ErrorMessage.Code code, String description) {
-    return ErrorMessage.newBuilder()
-        .setCode(code)
-        .setDescription(description)
-        .build();
-  }
-
-  public static InvalidationMessage newInvalidationMessage(Iterable<InvalidationP> invalidations) {
-    return InvalidationMessage.newBuilder().addAllInvalidation(invalidations).build();
-  }
-
-  public static RegistrationSyncRequestMessage newRegistrationSyncRequestMessage() {
-    return RegistrationSyncRequestMessage.getDefaultInstance();
-  }
-
-  public static RegistrationSyncMessage newRegistrationSyncMessage(
-      List<RegistrationSubtree> subtrees) {
-    return RegistrationSyncMessage.newBuilder().addAllSubtree(subtrees).build();
-  }
-
-  public static RegistrationSubtree newRegistrationSubtree(List<ObjectIdP> registeredOids) {
-    return RegistrationSubtree.newBuilder().addAllRegisteredObject(registeredOids).build();
-  }
-
-  public static InfoRequestMessage newPerformanceCounterRequestMessage() {
-    return InfoRequestMessage.newBuilder()
-        .addInfoType(InfoRequestMessage.InfoType.GET_PERFORMANCE_COUNTERS)
-        .build();
-  }
-
-  public static ConfigChangeMessage newConfigChangeMessage(long nextMessageDelayMs) {
-    return ConfigChangeMessage.newBuilder().setNextMessageDelayMs(nextMessageDelayMs).build();
-  }
-
-  public static ServerToClientMessage newServerToClientMessage(ServerHeader scHeader) {
-    return ServerToClientMessage.newBuilder()
-        .setHeader(scHeader)
-        .build();
-  }
-
-  public static ServerToClientMessage.Builder newServerToClientMessage(ServerHeader scHeader,
-      TokenControlMessage tokenControlMessage) {
-    return ServerToClientMessage.newBuilder()
-        .setHeader(scHeader)
-        .setTokenControlMessage(tokenControlMessage);
-  }
-
-  public static ServerToClientMessage newServerToClientMessage(ServerHeader scHeader,
-      RegistrationSyncRequestMessage syncRequestionMessage) {
-    return ServerToClientMessage.newBuilder()
-        .setHeader(scHeader)
-        .setRegistrationSyncRequestMessage(syncRequestionMessage)
-        .build();
-  }
-
-  public static ServerToClientMessage newServerToClientMessage(ServerHeader scHeader,
-      InvalidationMessage invalidationMessage) {
-    return ServerToClientMessage.newBuilder()
-        .setHeader(scHeader)
-        .setInvalidationMessage(invalidationMessage)
-        .build();
-  }
-
-  public static ServerToClientMessage newServerToClientMessage(ServerHeader scHeader,
-      RegistrationStatusMessage registrationStatusMessage) {
-    return ServerToClientMessage.newBuilder()
-        .setHeader(scHeader)
-        .setRegistrationStatusMessage(registrationStatusMessage)
-        .build();
-  }
-
-  public static ServerToClientMessage newServerToClientMessage(ServerHeader scHeader,
-      InfoRequestMessage infoRequestMessage) {
-    return ServerToClientMessage.newBuilder()
-        .setHeader(scHeader)
-        .setInfoRequestMessage(infoRequestMessage)
-        .build();
-  }
-
-  public static ServerToClientMessage newServerToClientMessage(ServerHeader scHeader,
-      ConfigChangeMessage configChangeMessage) {
-    return ServerToClientMessage.newBuilder()
-        .setHeader(scHeader)
-        .setConfigChangeMessage(configChangeMessage)
-        .build();
-  }
-
-  public static ServerToClientMessage newServerToClientMessage(ServerHeader scHeader,
-      ErrorMessage errorMessage) {
-    return ServerToClientMessage.newBuilder()
-        .setHeader(scHeader)
-        .setErrorMessage(errorMessage)
-        .build();
-  }
-
-  /**
-   * Constructs a network endpoint id for an Android client with the given {@code registrationId},
-   * {@code clientKey}, and {@code packageName}.
-   */
-  public static NetworkEndpointId newAndroidEndpointId(String registrationId, String clientKey,
-      String packageName, Version channelVersion) {
-    Preconditions.checkNotNull(registrationId, "Null registration id");
-    Preconditions.checkNotNull(clientKey, "Null client key");
-    Preconditions.checkNotNull(packageName, "Null package name");
-    Preconditions.checkNotNull(channelVersion, "Null channel version");
-
-    AndroidChannel.EndpointId.Builder endpointBuilder = AndroidChannel.EndpointId.newBuilder()
-        .setC2DmRegistrationId(registrationId)
-        .setClientKey(clientKey)
-        .setPackageName(packageName)
-        .setChannelVersion(channelVersion);
-    return newNetworkEndpointId(NetworkAddress.ANDROID, endpointBuilder.build().toByteString());
-  }
-
-  public static NetworkEndpointId newNetworkEndpointId(NetworkAddress networkAddr,
-      ByteString clientAddr) {
-    return NetworkEndpointId.newBuilder()
-        .setNetworkAddress(networkAddr)
-        .setClientAddress(clientAddr)
-        .build();
-  }
-
-  /**
-   * Returns an endpoint id that is identical to the given {@code endpointId} except with
-   * {@link NetworkEndpointId#getIsOffline} set to {@code true}.
-   */
-  public static NetworkEndpointId endpointIdToOfflineEndpointId(NetworkEndpointId endpointId) {
-    // If the endpoint is already marked offline, there's no need to build a new one.
-    return isOnline(endpointId) ? endpointId.toBuilder().setIsOffline(true).build() : endpointId;
-  }
-
-  /**
-   * Indicates whether the optional {@code endpointId} is for an online client. If the id is
-   * {@code null}, it means the client has no endpoint associated with it and it is considered
-   * offline. If the endpoint is known, it is considered online if the {@code is_offline} field is
-   * not defined or if the field is {@code false}.
-   */
-  public static boolean isOnline(NetworkEndpointId endpointId) {
-    // NetworkEndpointId has an optional is_offline field. The client is online if the field's value
-    // is either undefined or false.
-    return (endpointId != null) && (!endpointId.hasIsOffline() || !endpointId.getIsOffline());
-  }
-
-  public static TokenControlMessage newTokenControlMessage(ByteString newToken) {
-    TokenControlMessage.Builder builder = TokenControlMessage.newBuilder();
-    if (newToken != null) {
-      builder.setNewToken(newToken);
-    }
-    return builder.build();
-  }
-
-  public static RegistrationStatusMessage newRegistrationStatusMessage(
-      Collection<RegistrationStatus> statuses) {
-    Preconditions.checkArgument(!statuses.isEmpty(), "Empty statuses");
-    return RegistrationStatusMessage.newBuilder().addAllRegistrationStatus(statuses).build();
-  }
-
-  public static RegistrationMessage newRegistrationMessage(
-      Collection<RegistrationP> registrations) {
-    Preconditions.checkArgument(!registrations.isEmpty(), "Empty registrations");
-    return RegistrationMessage.newBuilder().addAllRegistration(registrations).build();
-  }
-
-  private CommonProtos2() { // To prevent instantiation
-  }
-}
diff --git a/java/com/google/ipc/invalidation/common/ObjectIdDigestUtils.java b/java/com/google/ipc/invalidation/common/ObjectIdDigestUtils.java
index 710b05a..6762f4b 100644
--- a/java/com/google/ipc/invalidation/common/ObjectIdDigestUtils.java
+++ b/java/com/google/ipc/invalidation/common/ObjectIdDigestUtils.java
@@ -18,7 +18,6 @@
 
 import com.google.common.base.Preconditions;
 import com.google.ipc.invalidation.util.Bytes;
-import com.google.protos.ipc.invalidation.ClientProtocol.ObjectIdP;
 
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
@@ -88,16 +87,19 @@
     return new Bytes(digestFn.getDigest());
   }
 
-  /** Returns the digest of {@code objectId} using {@code digestFn}. */
+  /**
+   * Returns the digest for the object id with source {@code objectSource} and name
+   * {@code objectName} using {@code digestFn}.
+   */
   
-  public static Bytes getDigest(ObjectIdP objectId, DigestFunction digestFn) {
+  public static Bytes getDigest(int objectSource, byte[] objectName, DigestFunction digestFn) {
     digestFn.reset();
     ByteBuffer buffer = ByteBuffer.allocate(Integer.SIZE / 8).order(ByteOrder.LITTLE_ENDIAN);
-    buffer.putInt(objectId.getSource());
+    buffer.putInt(objectSource);
 
     // Little endian number for type followed by bytes.
     digestFn.update(buffer.array());
-    digestFn.update(objectId.getName().toByteArray());
+    digestFn.update(objectName);
     return new Bytes(digestFn.getDigest());
   }
 }
diff --git a/java/com/google/ipc/invalidation/common/ProtoValidator.java b/java/com/google/ipc/invalidation/common/ProtoValidator.java
deleted file mode 100644
index c14d3a2..0000000
--- a/java/com/google/ipc/invalidation/common/ProtoValidator.java
+++ /dev/null
@@ -1,296 +0,0 @@
-/*
- * 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.common;
-
-import com.google.common.base.Preconditions;
-import com.google.ipc.invalidation.common.ProtoValidator.FieldInfo.Presence;
-import com.google.ipc.invalidation.util.BaseLogger;
-import com.google.ipc.invalidation.util.TypedUtil;
-import com.google.protobuf.MessageLite;
-
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.NoSuchElementException;
-import java.util.Set;
-
-
-/**
- * Base class for writing protocol buffer validators. This is used in conjunction with
- * {@code ProtoAccessorGenerator}.
- *
- */
-public abstract class ProtoValidator {
-  /** Class providing access to protocol buffer fields in a generic way. */
-  public interface Accessor {
-    public boolean hasField(MessageLite message, Descriptor field);
-    public Object getField(MessageLite message, Descriptor field);
-    public Collection<String> getAllFieldNames();
-  }
-
-  /** Class naming a protocol buffer field in a generic way. */
-  public static class Descriptor {
-    private final String name;
-
-    public Descriptor(String name) {
-      this.name = name;
-    }
-    /** Returns the name of the described field. */
-    public String getName() {
-      return name;
-    }
-    @Override
-    public String toString() {
-      return "Descriptor for field " + name;
-    }
-  }
-
-  /** Describes how to validate a message. */
-  public static class MessageInfo {
-    /** Protocol buffer descriptor for the message. */
-    private final Accessor messageAccessor;
-
-    /** Information about required and optional fields in this message. */
-    private final Set<FieldInfo> fieldInfo = new HashSet<FieldInfo>();
-
-    private int numRequiredFields;
-
-    /**
-     * Constructs a message info.
-     *
-     * @param messageAccessor descriptor for the protocol buffer
-     * @param fields information about the fields
-     */
-    public MessageInfo(Accessor messageAccessor, FieldInfo... fields) {
-      // Track which fields in the message descriptor have not yet been covered by a FieldInfo.
-      // We'll use this to verify that we get a FieldInfo for every field.
-      Set<String> unusedDescriptors = new HashSet<String>();
-      unusedDescriptors.addAll(messageAccessor.getAllFieldNames());
-
-      this.messageAccessor = messageAccessor;
-      for (FieldInfo info : fields) {
-        // Lookup the field given the name in the FieldInfo.
-        boolean removed = TypedUtil.remove(unusedDescriptors, info.getFieldDescriptor().getName());
-        Preconditions.checkState(removed, "Bad field: %s", info.getFieldDescriptor().getName());
-
-        // Add the field info to the number -> info map.
-        fieldInfo.add(info);
-
-        if (info.getPresence() == Presence.REQUIRED) {
-          ++numRequiredFields;
-        }
-      }
-      Preconditions.checkState(unusedDescriptors.isEmpty(), "Not all fields specified in %s: %s",
-          messageAccessor, unusedDescriptors);
-    }
-
-    /** Returns the stored field information. */
-    protected Collection<FieldInfo> getAllFields() {
-      return fieldInfo;
-    }
-
-    /**
-     * Function called after the presence/absence of all fields in this message and its child
-     * messages have been verified. Should be overridden to enforce additional semantic constraints
-     * beyond field presence/absence if needed.
-     */
-    protected boolean postValidate(MessageLite message) {
-      return true;
-    }
-
-    /** Returns the number of required fields for messages of this type. */
-    public int getNumRequiredFields() {
-      return numRequiredFields;
-    }
-  }
-
-  /** Describes a field in a message. */
-  protected static class FieldInfo {
-    /**
-     * Whether the field is required or optional. A repeated field where at least one value
-     * must be set should use {@code REQUIRED}.
-     */
-    enum Presence {
-      REQUIRED,
-      OPTIONAL
-    }
-
-    /** Name of the field in the containing message. */
-    private final Descriptor fieldDescriptor;
-
-    /** Whether the field is required or optional. */
-    private final Presence presence;
-
-    /** If not {@code null}, message info describing how to validate the field. */
-    private final MessageInfo messageInfo;
-
-    /**
-     * Constructs an instance.
-     *
-     * @param fieldDescriptor identifier for the field
-     * @param presence required/optional
-     * @param messageInfo if not {@code null}, describes how to validate the field
-     */
-    FieldInfo(Descriptor fieldDescriptor, Presence presence,
-        MessageInfo messageInfo) {
-      this.fieldDescriptor = fieldDescriptor;
-      this.presence = presence;
-      this.messageInfo = messageInfo;
-    }
-
-    /** Returns the name of the field. */
-    public Descriptor getFieldDescriptor() {
-      return fieldDescriptor;
-    }
-
-    /** Returns the presence information for the field. */
-    Presence getPresence() {
-      return presence;
-    }
-
-    /** Returns the validation information for the field. */
-    MessageInfo getMessageInfo() {
-      return messageInfo;
-    }
-
-    /** Returns whether the field needs additional validation. */
-    boolean requiresAdditionalValidation() {
-      return messageInfo != null;
-    }
-
-    /**
-     * Returns a new instance describing a required field with name {@code fieldName} and validation
-     * specified by {@code messageInfo}.
-     */
-    public static FieldInfo newRequired(Descriptor fieldDescriptor, MessageInfo messageInfo) {
-      return new FieldInfo(fieldDescriptor, Presence.REQUIRED,
-          Preconditions.checkNotNull(messageInfo, "messageInfo cannot be null"));
-    }
-
-    /**
-     * Returns a new instance describing a required field with name {@code fieldName} and no
-     * additional validation.
-     */
-    public static FieldInfo newRequired(Descriptor fieldDescriptor) {
-      return new FieldInfo(fieldDescriptor, Presence.REQUIRED, null);
-    }
-
-    /**
-     * Returns a new instance describing an optional field with name {@code fieldName} and
-     * validation specified by {@code messageInfo}.
-     */
-    public static FieldInfo newOptional(Descriptor fieldDescriptor, MessageInfo messageInfo) {
-      return new FieldInfo(fieldDescriptor, Presence.OPTIONAL,
-          Preconditions.checkNotNull(messageInfo));
-    }
-
-    /**
-     * Returns a new instance describing an optional field with name {@code fieldName} and no
-     * additional validation.
-     */
-    public static FieldInfo newOptional(Descriptor fieldDescriptor) {
-      return new FieldInfo(fieldDescriptor, Presence.OPTIONAL, null);
-    }
-  }
-
-  /** Logger for errors */
-  protected final BaseLogger logger;
-
-  protected ProtoValidator(BaseLogger logger) {
-    this.logger = logger;
-  }
-
-  /**
-   * Returns an {@link Iterable} over the instance(s) of {@code field} in {@code message}. This
-   * provides a uniform way to handle both singleton and repeated fields in protocol buffers, which
-   * are accessed using different calls in the protocol buffer API.
-   */
-  @SuppressWarnings("unchecked")
-  
-  protected static <FieldType> Iterable<FieldType> getFieldIterable(final MessageLite message,
-      final Accessor messageAccessor, final Descriptor fieldDescriptor) {
-    final Object obj = messageAccessor.getField(message, fieldDescriptor);
-    if (obj instanceof List) {
-      return (List<FieldType>) obj;
-    } else {
-      // Otherwise, just use a singleton iterator.
-      return new Iterable<FieldType>() {
-        @Override
-        public Iterator<FieldType> iterator() {
-          return new Iterator<FieldType>() {
-            boolean done;
-            @Override
-            public boolean hasNext() {
-              return !done;
-            }
-
-            @Override
-            public FieldType next() {
-              if (done) {
-                throw new NoSuchElementException();
-              }
-              done = true;
-              return (FieldType) obj;
-            }
-
-            @Override
-            public void remove() {
-              throw new UnsupportedOperationException("Not allowed");
-            }
-          };
-        }
-      };
-    }
-  }
-
-  /**
-   * Returns whether {@code message} is valid.
-   * @param messageInfo specification of validity for {@code message}
-   */
-  
-  protected boolean checkMessage(MessageLite message, MessageInfo messageInfo) {
-    for (FieldInfo fieldInfo : messageInfo.getAllFields()) {
-      Descriptor fieldDescriptor = fieldInfo.getFieldDescriptor();
-      boolean isFieldPresent =
-          messageInfo.messageAccessor.hasField(message, fieldDescriptor);
-
-      // If the field must be present but isn't, fail.
-      if ((fieldInfo.getPresence() == FieldInfo.Presence.REQUIRED) && !(isFieldPresent)) {
-        logger.warning("Required field not set: %s", fieldInfo.getFieldDescriptor().getName());
-        return false;
-      }
-
-      // If the field is present and requires its own validation, validate it.
-      if (isFieldPresent && fieldInfo.requiresAdditionalValidation()) {
-        for (MessageLite subMessage : TiclMessageValidator2.<MessageLite>getFieldIterable(
-            message, messageInfo.messageAccessor, fieldDescriptor)) {
-          if (!checkMessage(subMessage, fieldInfo.getMessageInfo())) {
-            return false;
-          }
-        }
-      }
-    }
-
-    // Once we've validated all fields, post-validate this message.
-    if (!messageInfo.postValidate(message)) {
-      logger.info("Failed post-validation of message (%s): %s",
-          message.getClass().getSimpleName(), message);
-      return false;
-    }
-    return true;
-  }
-}
diff --git a/java/com/google/ipc/invalidation/common/TiclMessageValidator2.java b/java/com/google/ipc/invalidation/common/TiclMessageValidator2.java
deleted file mode 100644
index bcd932d..0000000
--- a/java/com/google/ipc/invalidation/common/TiclMessageValidator2.java
+++ /dev/null
@@ -1,480 +0,0 @@
-/*
- * 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.common;
-
-import com.google.ipc.invalidation.common.ClientProtocolAccessor.ApplicationClientIdPAccessor;
-import com.google.ipc.invalidation.common.ClientProtocolAccessor.ClientConfigPAccessor;
-import com.google.ipc.invalidation.common.ClientProtocolAccessor.ClientHeaderAccessor;
-import com.google.ipc.invalidation.common.ClientProtocolAccessor.ClientToServerMessageAccessor;
-import com.google.ipc.invalidation.common.ClientProtocolAccessor.ClientVersionAccessor;
-import com.google.ipc.invalidation.common.ClientProtocolAccessor.ConfigChangeMessageAccessor;
-import com.google.ipc.invalidation.common.ClientProtocolAccessor.ErrorMessageAccessor;
-import com.google.ipc.invalidation.common.ClientProtocolAccessor.InfoMessageAccessor;
-import com.google.ipc.invalidation.common.ClientProtocolAccessor.InfoRequestMessageAccessor;
-import com.google.ipc.invalidation.common.ClientProtocolAccessor.InitializeMessageAccessor;
-import com.google.ipc.invalidation.common.ClientProtocolAccessor.InvalidationMessageAccessor;
-import com.google.ipc.invalidation.common.ClientProtocolAccessor.InvalidationPAccessor;
-import com.google.ipc.invalidation.common.ClientProtocolAccessor.ObjectIdPAccessor;
-import com.google.ipc.invalidation.common.ClientProtocolAccessor.ProtocolHandlerConfigPAccessor;
-import com.google.ipc.invalidation.common.ClientProtocolAccessor.RateLimitPAccessor;
-import com.google.ipc.invalidation.common.ClientProtocolAccessor.RegistrationMessageAccessor;
-import com.google.ipc.invalidation.common.ClientProtocolAccessor.RegistrationPAccessor;
-import com.google.ipc.invalidation.common.ClientProtocolAccessor.RegistrationStatusAccessor;
-import com.google.ipc.invalidation.common.ClientProtocolAccessor.RegistrationStatusMessageAccessor;
-import com.google.ipc.invalidation.common.ClientProtocolAccessor.RegistrationSubtreeAccessor;
-import com.google.ipc.invalidation.common.ClientProtocolAccessor.RegistrationSummaryAccessor;
-import com.google.ipc.invalidation.common.ClientProtocolAccessor.RegistrationSyncMessageAccessor;
-import com.google.ipc.invalidation.common.ClientProtocolAccessor.ServerHeaderAccessor;
-import com.google.ipc.invalidation.common.ClientProtocolAccessor.ServerToClientMessageAccessor;
-import com.google.ipc.invalidation.common.ClientProtocolAccessor.StatusPAccessor;
-import com.google.ipc.invalidation.common.ClientProtocolAccessor.TokenControlMessageAccessor;
-import com.google.ipc.invalidation.common.ClientProtocolAccessor.VersionAccessor;
-import com.google.ipc.invalidation.util.BaseLogger;
-import com.google.protobuf.MessageLite;
-import com.google.protos.ipc.invalidation.ClientProtocol.ApplicationClientIdP;
-import com.google.protos.ipc.invalidation.ClientProtocol.ClientHeader;
-import com.google.protos.ipc.invalidation.ClientProtocol.ClientToServerMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.ConfigChangeMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.InitializeMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.InvalidationP;
-import com.google.protos.ipc.invalidation.ClientProtocol.ObjectIdP;
-import com.google.protos.ipc.invalidation.ClientProtocol.RateLimitP;
-import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationSummary;
-import com.google.protos.ipc.invalidation.ClientProtocol.ServerHeader;
-import com.google.protos.ipc.invalidation.ClientProtocol.ServerToClientMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.Version;
-
-/**
- * Validator for v2 protocol messages.
- * <p>
- * The basic idea is to declare information about each field in each message, i.e., whether it is
- * optional or it is required. {@code FieldInfo} is a class that keeps track of information
- * about each field and {@code MessageInfo} is a class that keeps track of information about each
- * message. Given a message, we recursively descend a MessageInfo and determine if the fields
- * are as expected. Then once we are done with a message, we perform a post validation step
- * which checks constraints across fields.
- *
- */
-public class TiclMessageValidator2 extends ProtoValidator {
-  public TiclMessageValidator2(BaseLogger logger) {
-    super(logger);
-  }
-
-  /** Describes how to validate common messages. */
-  
-  public class CommonMsgInfos {
-
-    /** Validation for composite (major/minor) versions. */
-    final MessageInfo VERSION = new MessageInfo(ClientProtocolAccessor.VERSION_ACCESSOR,
-      FieldInfo.newRequired(VersionAccessor.MAJOR_VERSION),
-      FieldInfo.newRequired(VersionAccessor.MINOR_VERSION)) {
-      @Override
-      public boolean postValidate(MessageLite message) {
-        // Versions must be non-negative.
-        Version version = (Version) message;
-        if ((version.getMajorVersion() < 0) || (version.getMinorVersion() < 0)) {
-          logger.info("Invalid versions: %s", version);
-          return false;
-        }
-        return true;
-      }
-    };
-
-    /** Validation for the protocol version. */
-    final MessageInfo PROTOCOL_VERSION = new MessageInfo(
-        ClientProtocolAccessor.PROTOCOL_VERSION_ACCESSOR,
-        FieldInfo.newRequired(ClientProtocolAccessor.ProtocolVersionAccessor.VERSION, VERSION));
-
-    /** Validation for object ids. */
-    final MessageInfo OID = new MessageInfo(ClientProtocolAccessor.OBJECT_ID_P_ACCESSOR,
-        FieldInfo.newRequired(ObjectIdPAccessor.NAME),
-        FieldInfo.newRequired(ObjectIdPAccessor.SOURCE)) {
-      @Override
-      public boolean postValidate(MessageLite message) {
-        // Must have non-negative source code.
-        ObjectIdP oid = (ObjectIdP) message;
-        if (oid.getSource() < 0) {
-          logger.info("Source was negative: %s", oid);
-          return false;
-        }
-        return true;
-      }
-    };
-
-    /** Validation for invalidations. */
-    final MessageInfo INVALIDATION = new MessageInfo(
-        ClientProtocolAccessor.INVALIDATION_P_ACCESSOR,
-        FieldInfo.newRequired(InvalidationPAccessor.OBJECT_ID, OID),
-        FieldInfo.newRequired(InvalidationPAccessor.IS_KNOWN_VERSION),
-        FieldInfo.newRequired(InvalidationPAccessor.VERSION),
-        FieldInfo.newOptional(InvalidationPAccessor.PAYLOAD),
-        FieldInfo.newOptional(InvalidationPAccessor.IS_TRICKLE_RESTART),
-        FieldInfo.newOptional(InvalidationPAccessor.BRIDGE_ARRIVAL_TIME_MS_DEPRECATED)) {
-      @Override
-      public boolean postValidate(MessageLite message) {
-        // Must have non-negative version.
-        InvalidationP invalidation = (InvalidationP) message;
-        if (invalidation.getVersion() < 0) {
-          logger.info("Version was negative: %s", invalidation);
-          return false;
-        }
-        boolean isUnknownVersion = !invalidation.getIsKnownVersion();
-        // Note that a missing value for is_trickle_restart is treated like a true value,
-        // becomes it comes from a downlevel client that uses invalidation semantics.
-        boolean isTrickleRestart = !invalidation.hasIsTrickleRestart() ||
-            invalidation.getIsTrickleRestart();
-        if (isUnknownVersion && !isTrickleRestart) {
-          logger.info(
-              "if is_known_version is false, is_trickle_restart must be true or missing: %s",
-              invalidation);
-          return false;
-        }
-        return true;
-      }
-    };
-
-    /** Validation for a message containing many invalidations. */
-    final MessageInfo INVALIDATION_MSG;
-
-    /** Validation for a single registration description. */
-    final MessageInfo REGISTRATIONP = new MessageInfo(
-        ClientProtocolAccessor.REGISTRATION_P_ACCESSOR,
-        FieldInfo.newRequired(RegistrationPAccessor.OBJECT_ID, OID),
-        FieldInfo.newRequired(RegistrationPAccessor.OP_TYPE));
-
-    /** Validation for a summary of registration state. */
-    final MessageInfo REGISTRATION_SUMMARY = new MessageInfo(
-        ClientProtocolAccessor.REGISTRATION_SUMMARY_ACCESSOR,
-        FieldInfo.newRequired(RegistrationSummaryAccessor.NUM_REGISTRATIONS),
-        FieldInfo.newRequired(RegistrationSummaryAccessor.REGISTRATION_DIGEST)) {
-      @Override
-      public boolean postValidate(MessageLite message) {
-        RegistrationSummary summary = (RegistrationSummary) message;
-        return (summary.getNumRegistrations() >= 0)
-            && (!summary.getRegistrationDigest().isEmpty());
-      }
-    };
-
-    final MessageInfo RATE_LIMIT = new MessageInfo(
-        ClientProtocolAccessor.RATE_LIMIT_P_ACCESSOR,
-        FieldInfo.newRequired(RateLimitPAccessor.WINDOW_MS),
-        FieldInfo.newRequired(RateLimitPAccessor.COUNT)) {
-      @Override
-      public boolean postValidate(MessageLite message) {
-        RateLimitP rateLimit = (RateLimitP) message;
-        return (rateLimit.getWindowMs() >= 1000) &&
-            (rateLimit.getWindowMs() > rateLimit.getCount());
-      }
-    };
-
-    final MessageInfo PROTOCOL_HANDLER_CONFIG = new MessageInfo(
-        ClientProtocolAccessor.PROTOCOL_HANDLER_CONFIG_P_ACCESSOR,
-        FieldInfo.newOptional(ProtocolHandlerConfigPAccessor.BATCHING_DELAY_MS),
-        FieldInfo.newOptional(ProtocolHandlerConfigPAccessor.RATE_LIMIT, RATE_LIMIT)
-        );
-
-    // Validation for Client Config. */
-    final MessageInfo CLIENT_CONFIG = new MessageInfo(
-        ClientProtocolAccessor.CLIENT_CONFIG_P_ACCESSOR,
-        FieldInfo.newRequired(ClientConfigPAccessor.VERSION, VERSION),
-        FieldInfo.newOptional(ClientConfigPAccessor.NETWORK_TIMEOUT_DELAY_MS),
-        FieldInfo.newOptional(ClientConfigPAccessor.WRITE_RETRY_DELAY_MS),
-        FieldInfo.newOptional(ClientConfigPAccessor.HEARTBEAT_INTERVAL_MS),
-        FieldInfo.newOptional(ClientConfigPAccessor.PERF_COUNTER_DELAY_MS),
-        FieldInfo.newOptional(ClientConfigPAccessor.MAX_EXPONENTIAL_BACKOFF_FACTOR),
-        FieldInfo.newOptional(ClientConfigPAccessor.SMEAR_PERCENT),
-        FieldInfo.newOptional(ClientConfigPAccessor.IS_TRANSIENT),
-        FieldInfo.newOptional(ClientConfigPAccessor.INITIAL_PERSISTENT_HEARTBEAT_DELAY_MS),
-        FieldInfo.newOptional(ClientConfigPAccessor.CHANNEL_SUPPORTS_OFFLINE_DELIVERY),
-        FieldInfo.newRequired(ClientConfigPAccessor.PROTOCOL_HANDLER_CONFIG,
-            PROTOCOL_HANDLER_CONFIG),
-        FieldInfo.newOptional(ClientConfigPAccessor.OFFLINE_HEARTBEAT_THRESHOLD_MS),
-        FieldInfo.newOptional(ClientConfigPAccessor.ALLOW_SUPPRESSION)
-        );
-
-    private CommonMsgInfos() {
-      // Initialize in constructor since other instance fields are referenced
-      INVALIDATION_MSG = new MessageInfo(
-          ClientProtocolAccessor.INVALIDATION_MESSAGE_ACCESSOR,
-          FieldInfo.newRequired(InvalidationMessageAccessor.INVALIDATION,
-              this.INVALIDATION));
-    }
-  }
-
-  /** Describes how to validate client messages. */
-  private class ClientMsgInfos {
-    /** Validation for client headers. */
-    final MessageInfo HEADER = new MessageInfo(
-        ClientProtocolAccessor.CLIENT_HEADER_ACCESSOR,
-        FieldInfo.newRequired(ClientHeaderAccessor.PROTOCOL_VERSION,
-            commonMsgInfos.PROTOCOL_VERSION),
-        FieldInfo.newOptional(ClientHeaderAccessor.CLIENT_TOKEN),
-        FieldInfo.newOptional(ClientHeaderAccessor.REGISTRATION_SUMMARY,
-            commonMsgInfos.REGISTRATION_SUMMARY),
-        FieldInfo.newRequired(ClientHeaderAccessor.CLIENT_TIME_MS),
-        FieldInfo.newRequired(ClientHeaderAccessor.MAX_KNOWN_SERVER_TIME_MS),
-        FieldInfo.newOptional(ClientHeaderAccessor.MESSAGE_ID),
-        FieldInfo.newOptional(ClientHeaderAccessor.CLIENT_TYPE)) {
-      @Override
-      public boolean postValidate(MessageLite message) {
-        ClientHeader header = (ClientHeader) message;
-
-        // If set, token must not be empty.
-        if (header.hasClientToken() && header.getClientToken().isEmpty()) {
-          logger.info("Client token was set but empty: %s", header);
-          return false;
-        }
-
-        // If set, message id must not be empty.
-        // Do not use String.isEmpty() here for Froyo (JDK5) compatibility.
-        if (header.hasMessageId() && (header.getMessageId().length() == 0)) {
-          logger.info("Message id was set but empty: %s", header);
-          return false;
-        }
-
-        if (header.getClientTimeMs() < 0) {
-          logger.info("Client time was negative: %s", header);
-          return false;
-        }
-
-        if (header.getMaxKnownServerTimeMs() < 0) {
-          logger.info("Max known server time was negative: %s", header);
-          return false;
-        }
-        return true;
-      }
-    };
-
-    /** Validation for application client ids. */
-    final MessageInfo APPLICATION_CLIENT_ID = new MessageInfo(
-        // Client type is optional here since the registrar needs to accept messages from
-        // the ticls that do not set the client type.
-        ClientProtocolAccessor.APPLICATION_CLIENT_ID_P_ACCESSOR,
-        FieldInfo.newOptional(ApplicationClientIdPAccessor.CLIENT_TYPE),
-        FieldInfo.newRequired(ApplicationClientIdPAccessor.CLIENT_NAME)) {
-      @Override
-      public boolean postValidate(MessageLite message) {
-        ApplicationClientIdP applicationClientId = (ApplicationClientIdP) message;
-        return !applicationClientId.getClientName().isEmpty();
-      }
-    };
-
-    /** Validation for client initialization messages. */
-    final MessageInfo INITIALIZE_MESSAGE = new MessageInfo(
-        ClientProtocolAccessor.INITIALIZE_MESSAGE_ACCESSOR,
-        FieldInfo.newRequired(InitializeMessageAccessor.CLIENT_TYPE),
-        FieldInfo.newRequired(InitializeMessageAccessor.NONCE),
-        FieldInfo.newRequired(InitializeMessageAccessor.DIGEST_SERIALIZATION_TYPE),
-        FieldInfo.newRequired(InitializeMessageAccessor.APPLICATION_CLIENT_ID,
-            APPLICATION_CLIENT_ID)) {
-      @Override
-      public boolean postValidate(MessageLite message) {
-        return ((InitializeMessage) message).getClientType() >= 0;
-      }
-    };
-
-    /** Validation for registration requests. */
-    final MessageInfo REGISTRATION = new MessageInfo(
-        ClientProtocolAccessor.REGISTRATION_MESSAGE_ACCESSOR,
-        FieldInfo.newRequired(RegistrationMessageAccessor.REGISTRATION,
-            commonMsgInfos.REGISTRATIONP));
-
-    /** Validation for client versions. */
-    final MessageInfo CLIENT_VERSION = new MessageInfo(
-        ClientProtocolAccessor.CLIENT_VERSION_ACCESSOR,
-        FieldInfo.newRequired(ClientVersionAccessor.VERSION, commonMsgInfos.VERSION),
-        FieldInfo.newRequired(ClientVersionAccessor.PLATFORM),
-        FieldInfo.newRequired(ClientVersionAccessor.LANGUAGE),
-        FieldInfo.newRequired(ClientVersionAccessor.APPLICATION_INFO));
-
-    /** Validation for client information messages. */
-    final MessageInfo INFO = new MessageInfo(
-        ClientProtocolAccessor.INFO_MESSAGE_ACCESSOR,
-        FieldInfo.newRequired(InfoMessageAccessor.CLIENT_VERSION, CLIENT_VERSION),
-        FieldInfo.newOptional(InfoMessageAccessor.CONFIG_PARAMETER),
-        FieldInfo.newOptional(InfoMessageAccessor.PERFORMANCE_COUNTER),
-        FieldInfo.newOptional(InfoMessageAccessor.CLIENT_CONFIG, commonMsgInfos.CLIENT_CONFIG),
-        FieldInfo.newOptional(InfoMessageAccessor.SERVER_REGISTRATION_SUMMARY_REQUESTED));
-
-    /** Validation for registration subtrees. */
-    final MessageInfo SUBTREE = new MessageInfo(
-        ClientProtocolAccessor.REGISTRATION_SUBTREE_ACCESSOR,
-        FieldInfo.newOptional(RegistrationSubtreeAccessor.REGISTERED_OBJECT));
-
-    /** Validation for registration sync messages. */
-    final MessageInfo REGISTRATION_SYNC = new MessageInfo(
-        ClientProtocolAccessor.REGISTRATION_SYNC_MESSAGE_ACCESSOR,
-        FieldInfo.newRequired(RegistrationSyncMessageAccessor.SUBTREE, SUBTREE));
-
-    /** Validation for a ClientToServerMessage. */
-    final MessageInfo CLIENT_MSG = new MessageInfo(
-        ClientProtocolAccessor.CLIENT_TO_SERVER_MESSAGE_ACCESSOR,
-        FieldInfo.newRequired(ClientToServerMessageAccessor.HEADER, HEADER),
-        FieldInfo.newOptional(ClientToServerMessageAccessor.INFO_MESSAGE, INFO),
-        FieldInfo.newOptional(ClientToServerMessageAccessor.INITIALIZE_MESSAGE, INITIALIZE_MESSAGE),
-        FieldInfo.newOptional(ClientToServerMessageAccessor.INVALIDATION_ACK_MESSAGE,
-            commonMsgInfos.INVALIDATION_MSG),
-        FieldInfo.newOptional(ClientToServerMessageAccessor.REGISTRATION_MESSAGE, REGISTRATION),
-        FieldInfo.newOptional(ClientToServerMessageAccessor.REGISTRATION_SYNC_MESSAGE,
-            REGISTRATION_SYNC)) {
-      @Override
-      public boolean postValidate(MessageLite message) {
-        ClientToServerMessage parsedMessage = (ClientToServerMessage) message;
-        // The message either has an initialize request from the client or it has the client token.
-        return (parsedMessage.hasInitializeMessage() ^ parsedMessage.getHeader().hasClientToken());
-      }
-    };
-  }
-
-  /** Describes how to validate server messages. */
-  
-  class ServerMsgInfos {
-    /** Validation for server headers. */
-    final MessageInfo HEADER = new MessageInfo(
-        ClientProtocolAccessor.SERVER_HEADER_ACCESSOR,
-        FieldInfo.newRequired(ServerHeaderAccessor.PROTOCOL_VERSION,
-            commonMsgInfos.PROTOCOL_VERSION),
-        FieldInfo.newRequired(ServerHeaderAccessor.CLIENT_TOKEN),
-        FieldInfo.newOptional(ServerHeaderAccessor.REGISTRATION_SUMMARY,
-            commonMsgInfos.REGISTRATION_SUMMARY),
-        FieldInfo.newRequired(ServerHeaderAccessor.SERVER_TIME_MS),
-        FieldInfo.newOptional(ServerHeaderAccessor.MESSAGE_ID)) {
-      @Override
-      public boolean postValidate(MessageLite message) {
-        ServerHeader header = (ServerHeader) message;
-        if (header.getClientToken().isEmpty()) {
-          logger.info("Client token was empty: %s", header);
-          return false;
-        }
-        if (header.getServerTimeMs() < 0) {
-          logger.info("Server time was negative: %s", header);
-          return false;
-        }
-        // If set, message id must not be empty.
-        // Do not use String.isEmpty() here for Froyo (JDK5) compatibility.
-        if (header.hasMessageId() && (header.getMessageId().length() == 0)) {
-          logger.info("Message id was set but empty: %s", header);
-          return false;
-        }
-        return true;
-      }
-    };
-
-    /** Validation for server response codes. */
-    final MessageInfo STATUSP = new MessageInfo(
-        ClientProtocolAccessor.STATUS_P_ACCESSOR,
-        FieldInfo.newRequired(StatusPAccessor.CODE),
-        FieldInfo.newOptional(StatusPAccessor.DESCRIPTION));
-
-    /** Validation for token control messages. */
-    final MessageInfo TOKEN_CONTROL = new MessageInfo(
-        ClientProtocolAccessor.TOKEN_CONTROL_MESSAGE_ACCESSOR,
-        FieldInfo.newOptional(TokenControlMessageAccessor.NEW_TOKEN));
-
-    /** Validation for error messages. */
-    final MessageInfo ERROR = new MessageInfo(
-        ClientProtocolAccessor.ERROR_MESSAGE_ACCESSOR,
-        FieldInfo.newRequired(ErrorMessageAccessor.CODE),
-        FieldInfo.newRequired(ErrorMessageAccessor.DESCRIPTION));
-
-    /** Validation for registration results. */
-    final MessageInfo REGISTRATION_RESULT = new MessageInfo(
-        ClientProtocolAccessor.REGISTRATION_STATUS_ACCESSOR,
-        FieldInfo.newRequired(RegistrationStatusAccessor.REGISTRATION,
-            commonMsgInfos.REGISTRATIONP),
-        FieldInfo.newRequired(RegistrationStatusAccessor.STATUS, STATUSP));
-
-    /** Validation for registration status messages. */
-    final MessageInfo REGISTRATION_STATUS_MSG = new MessageInfo(
-        ClientProtocolAccessor.REGISTRATION_STATUS_MESSAGE_ACCESSOR,
-        FieldInfo.newRequired(RegistrationStatusMessageAccessor.REGISTRATION_STATUS,
-            REGISTRATION_RESULT));
-
-    /** Validation for registration sync requests. */
-    final MessageInfo REGISTRATION_SYNC_REQUEST = new MessageInfo(
-        ClientProtocolAccessor.REGISTRATION_SYNC_REQUEST_MESSAGE_ACCESSOR);
-
-    /** Validation for info requests. */
-    final MessageInfo INFO_REQUEST = new MessageInfo(
-        ClientProtocolAccessor.INFO_REQUEST_MESSAGE_ACCESSOR,
-        FieldInfo.newRequired(InfoRequestMessageAccessor.INFO_TYPE));
-
-    /** Validation for config change message. */
-    final MessageInfo CONFIG_CHANGE = new MessageInfo(
-        ClientProtocolAccessor.CONFIG_CHANGE_MESSAGE_ACCESSOR,
-        FieldInfo.newOptional(ConfigChangeMessageAccessor.NEXT_MESSAGE_DELAY_MS)) {
-          @Override
-          public boolean postValidate(MessageLite message) {
-            ConfigChangeMessage parsedMessage = (ConfigChangeMessage) message;
-            // If the message has a next_message_delay_ms value, it must be positive.
-            return !parsedMessage.hasNextMessageDelayMs() ||
-                (parsedMessage.getNextMessageDelayMs() > 0);
-          }
-        };
-
-    /** Validation for the top-level server messages. */
-    final MessageInfo SERVER_MSG = new MessageInfo(
-        ClientProtocolAccessor.SERVER_TO_CLIENT_MESSAGE_ACCESSOR,
-        FieldInfo.newRequired(ServerToClientMessageAccessor.HEADER, HEADER),
-        FieldInfo.newOptional(ServerToClientMessageAccessor.TOKEN_CONTROL_MESSAGE, TOKEN_CONTROL),
-        FieldInfo.newOptional(ServerToClientMessageAccessor.INVALIDATION_MESSAGE,
-            commonMsgInfos.INVALIDATION_MSG),
-        FieldInfo.newOptional(ServerToClientMessageAccessor.REGISTRATION_STATUS_MESSAGE,
-            REGISTRATION_STATUS_MSG),
-        FieldInfo.newOptional(ServerToClientMessageAccessor.REGISTRATION_SYNC_REQUEST_MESSAGE,
-            REGISTRATION_SYNC_REQUEST),
-        FieldInfo.newOptional(ServerToClientMessageAccessor.CONFIG_CHANGE_MESSAGE, CONFIG_CHANGE),
-        FieldInfo.newOptional(ServerToClientMessageAccessor.INFO_REQUEST_MESSAGE, INFO_REQUEST),
-        FieldInfo.newOptional(ServerToClientMessageAccessor.ERROR_MESSAGE, ERROR));
-  }
-
-  /** Common validation information */
-  
-  final CommonMsgInfos commonMsgInfos = new CommonMsgInfos();
-
-  /** Client validation information */
-  private final ClientMsgInfos clientMsgInfos = new ClientMsgInfos();
-
-  /** Server validation information */
-  
-  final ServerMsgInfos serverMsgInfos = new ServerMsgInfos();
-
-  /** Returns whether {@code clientMessage} is valid. */
-  public boolean isValid(ClientToServerMessage clientMessage) {
-    return checkMessage(clientMessage, clientMsgInfos.CLIENT_MSG);
-  }
-
-  /** Returns whether {@code serverMessage} is valid. */
-  public boolean isValid(ServerToClientMessage serverMessage) {
-    return checkMessage(serverMessage, serverMsgInfos.SERVER_MSG);
-  }
-
-  /** Returns whether {@code invalidation} is valid. */
-  public boolean isValid(InvalidationP invalidation) {
-    return checkMessage(invalidation, commonMsgInfos.INVALIDATION);
-  }
-
-  /** Returns whether {@code version} is valid. */
-  public boolean isValid(Version version) {
-    return checkMessage(version, commonMsgInfos.VERSION);
-  }
-
-  /** Returns the {@code MessageInfo} for a {@link ServerToClientMessage}. */
-  public MessageInfo getServerToClientMessageInfo() {
-    return serverMsgInfos.SERVER_MSG;
-  }
-}
diff --git a/java/com/google/ipc/invalidation/common/TrickleState.java b/java/com/google/ipc/invalidation/common/TrickleState.java
deleted file mode 100644
index 97cb55f..0000000
--- a/java/com/google/ipc/invalidation/common/TrickleState.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.common;
-
-import com.google.protos.ipc.invalidation.ClientProtocol.InvalidationP;
-
-/**
- * Enumeration describing whether an invalidation restarts its trickle.
- *
- */
-public enum TrickleState {
-  /** The trickle is restarting; that is, past versions may have been dropped. */
-  RESTART,   
-  /** The trickle is not restarting. */
-  CONTINUE;  
-
-  /** Returns RESTART if {@code isTrickleRestart} is true, CONTINUE otherwise. */
-  public static TrickleState fromBoolean(boolean isTrickleRestart) {
-    return isTrickleRestart ? RESTART : CONTINUE;
-  }
-
-  /** Returns a TrickleState based on the value of {@code invalidation.is_trickle_restart}. */
-  public static TrickleState fromInvalidation(InvalidationP invalidation) {
-    return TrickleState.fromBoolean(invalidation.getIsTrickleRestart());
-  }
-}
diff --git a/java/com/google/ipc/invalidation/examples/android2/ExampleListenerState.java b/java/com/google/ipc/invalidation/examples/android2/ExampleListenerState.java
index 0693ea7..04cbf3f 100644
--- a/java/com/google/ipc/invalidation/examples/android2/ExampleListenerState.java
+++ b/java/com/google/ipc/invalidation/examples/android2/ExampleListenerState.java
@@ -110,7 +110,7 @@
     }
 
     void toString(StringBuilder builder) {
-      builder.append(isRegistered ? "REG " : "UNREG ").append(objectId.toString());
+      builder.append(isRegistered ? "REG " : "UNREG ").append(objectId);
       if (payload != null) {
         builder.append(", payload=").append(payload.toStringUtf8());
       }
@@ -121,8 +121,7 @@
         builder.append(", isBackground");
       }
       if (invalidationTimeMillis != null) {
-        builder.append(", invalidationTime=").append(
-            new Date(invalidationTimeMillis.longValue()).toString());
+        builder.append(", invalidationTime=").append(new Date(invalidationTimeMillis.longValue()));
       }
     }
   }
diff --git a/java/com/google/ipc/invalidation/examples/android2/MainActivity.java b/java/com/google/ipc/invalidation/examples/android2/MainActivity.java
index c8c04e9..e748ff6 100644
--- a/java/com/google/ipc/invalidation/examples/android2/MainActivity.java
+++ b/java/com/google/ipc/invalidation/examples/android2/MainActivity.java
@@ -18,7 +18,6 @@
 
 import com.google.ipc.invalidation.external.client.contrib.MultiplexingGcmListener;
 import com.google.ipc.invalidation.external.client.types.ObjectId;
-import com.google.protobuf.ByteString;
 
 import android.app.Activity;
 import android.content.Context;
@@ -32,6 +31,8 @@
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
+import java.nio.charset.Charset;
+
 /**
  * A simple  sample application that displays information about object registrations and
  * versions.
@@ -173,7 +174,7 @@
 
         String name = nameField.getText().toString();
         ObjectId objectId =
-            ObjectId.newInstance(source, ByteString.copyFromUtf8(name).toByteArray());
+            ObjectId.newInstance(source, name.getBytes(Charset.forName("UTF-8")));
         performRegistration(v.getContext(), objectId);
       }
 
diff --git a/java/com/google/ipc/invalidation/examples/android2/example_listener.proto b/java/com/google/ipc/invalidation/examples/android2/example_listener.proto
index e9a01ba..bb6d91e 100644
--- a/java/com/google/ipc/invalidation/examples/android2/example_listener.proto
+++ b/java/com/google/ipc/invalidation/examples/android2/example_listener.proto
@@ -2,7 +2,6 @@
 package ipc.invalidation.examples.android2;
 option java_package = "com.google.ipc.invalidation.examples.android2";
 option java_outer_classname = "ExampleListenerProto";
-option optimize_for = LITE_RUNTIME;
 
 // Persistent state for the example listener.
 message ExampleListenerStateProto {
diff --git a/java/com/google/ipc/invalidation/external/client/InvalidationClientFactory.java b/java/com/google/ipc/invalidation/external/client/InvalidationClientFactory.java
index 20c6615..a40854a 100644
--- a/java/com/google/ipc/invalidation/external/client/InvalidationClientFactory.java
+++ b/java/com/google/ipc/invalidation/external/client/InvalidationClientFactory.java
@@ -18,7 +18,7 @@
 
 import com.google.ipc.invalidation.ticl.InvalidationClientCore;
 import com.google.ipc.invalidation.ticl.InvalidationClientImpl;
-import com.google.protos.ipc.invalidation.ClientProtocol.ClientConfigP;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.ClientConfigP;
 
 import java.util.Random;
 
@@ -37,9 +37,9 @@
    */
   public static InvalidationClient createClient(SystemResources resources,
       InvalidationClientConfig clientConfig, InvalidationListener listener) {
-    ClientConfigP internalConfig = InvalidationClientCore.createConfig()
-        .setAllowSuppression(clientConfig.allowSuppression)
-        .build();
+    ClientConfigP.Builder internalConfigBuilder = InvalidationClientCore.createConfig().toBuilder();
+    internalConfigBuilder.allowSuppression = clientConfig.allowSuppression;
+    ClientConfigP internalConfig = internalConfigBuilder.build();
     Random random = new Random(resources.getInternalScheduler().getCurrentTimeMs());
     return new InvalidationClientImpl(resources, random, clientConfig.clientType,
         clientConfig.clientName, internalConfig, clientConfig.applicationName, listener);
diff --git a/java/com/google/ipc/invalidation/external/client/android/AndroidClientFactory.java b/java/com/google/ipc/invalidation/external/client/android/AndroidClientFactory.java
deleted file mode 100644
index a0c3c2a..0000000
--- a/java/com/google/ipc/invalidation/external/client/android/AndroidClientFactory.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * 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.external.client.android;
-
-import com.google.common.base.Preconditions;
-
-import android.accounts.Account;
-import android.content.Context;
-
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * Factory for obtaining an {@code InvalidationClient} for the Android platform. The {@link #create}
- * method will create a invalidation client associated with a particular application and user
- * account.
- * <p>
- * Applications should persist the unique client key for the new client so invalidation activity can
- * restart later if the application is removed from memory. An application can obtain an
- * invalidation client instance to resume activity by calling the {@link #resume} method with the
- * same application id that was originally passed to {@link #create}.
- *
- */
-public class AndroidClientFactory {
-  /**
-   * A mapping of application id to invalidation client instances that can be used to
-   * resume/reassociate an existing invalidation client. Client instances are not guaranteed (nor
-   * required) to be reused.
-   */
-  private static final Map<String, AndroidInvalidationClientImpl> clientMap =
-      new ConcurrentHashMap<String, AndroidInvalidationClientImpl>();
-
-  /**
-   * Starts a new invalidation client for the provided application and account token that will
-   * deliver invalidation events to an instance of the provided listener component.
-   * <p>
-   * The implementation of this method is idempotent. If you call {@link #create} more than once
-   * with the same application id, account, and listenerName values, all calls after the first one
-   * are equivalent to just calling {@link #resume} with the same application id.
-   *
-   * @param context the context for the client.
-   * @param clientKey a unique id that identifies the created client within the scope of the
-   *        application.
-   * @param account user account that is registering the invalidations.
-   * @param authType the authentication token type that should be used to authenticate the client.
-   * @param listenerClass the {@link AndroidInvalidationListener} subclass that is registered to
-   *        receive the broadcast intents for invalidation events.
-   */
-  public static AndroidInvalidationClient create(Context context, String clientKey, int clientType,
-      Account account, String authType,
-      Class<? extends AndroidInvalidationListener> listenerClass) {
-    Preconditions.checkNotNull(context, "context");
-    Preconditions.checkNotNull(account, "account");
-    Preconditions.checkArgument((authType != null) && (authType.length() != 0),
-        "authType must be a non-empty string value");
-    Preconditions.checkNotNull(listenerClass, "listenerClass");
-
-    AndroidInvalidationClientImpl client = null;
-    if (clientMap.containsKey(clientKey)) {
-      return resume(context, clientKey);
-    }
-    if (client == null) {
-      client = new AndroidInvalidationClientImpl(context, clientKey, clientType, account, authType,
-          listenerClass);
-      client.initialize();
-      clientMap.put(clientKey, client);
-    }
-    return client;
-  }
-
-  /**
-   * Creates a new AndroidInvalidationClient instance that is resuming processing for an existing
-   * application id.
-   * <p>
-   * Use of this method is not recommended: use {@link #create} instead.
-   *
-   * @param context the context for the client.
-   * @param clientKey a unique key that identifies the created client within the scope of the
-   *        device.
-   */
-  public static AndroidInvalidationClient resume(Context context, String clientKey) {
-    return resume(context, clientKey, true);
-  }
-
-  /**
-   * Creates a new AndroidInvalidationClient instance that is resuming processing for an existing
-   * application id.
-   * <p>
-   * Use of this method is not recommended: use {@link #create} instead.
-   *
-   * @param context the context for the client.
-   * @param clientKey a unique key that identifies the created client within the scope of the
-   *        device.
-   * @param sendTiclResumeRequest whether to send a request to the service to resume the Ticl. If
-   *        {@code false}, assumes the Ticl is already loaded at the service. This is used in the
-   *         listener implementation and should not be set by clients.
-   */
-  public static AndroidInvalidationClient resume(Context context, String clientKey,
-      boolean sendTiclResumeRequest) {
-    Preconditions.checkNotNull(context, "context");
-
-    // See if a cached entry is available with a matching application id
-    AndroidInvalidationClientImpl client = clientMap.get(clientKey);
-    if (client != null) {
-      // Notify the client instance that it has multiple references.
-      client.addReference();
-    } else {
-      // Attempt to resume the client using the invalidation service
-      client = new AndroidInvalidationClientImpl(context, clientKey);
-      client.initResumed(sendTiclResumeRequest);
-    }
-    return client;
-  }
-
-  /**
-   * Release the client instance associated with the provided key.   Any transient resources
-   * associated with the client in the factory will be released.
-   *
-   * @param clientKey the client to remove
-   * @return {@code true} if a client with the provided key was found and releasedUUUU  .
-   */
-  static boolean release(String clientKey) {
-    return clientMap.remove(clientKey) != null;
-  }
-
-  /**
-   * Resets the state of the factory by dropping all cached client references.
-   */
-  
-  static void resetForTest() {
-    clientMap.clear();
-  }
-}
diff --git a/java/com/google/ipc/invalidation/external/client/android/AndroidInvalidationClient.java b/java/com/google/ipc/invalidation/external/client/android/AndroidInvalidationClient.java
deleted file mode 100644
index 04aa2b0..0000000
--- a/java/com/google/ipc/invalidation/external/client/android/AndroidInvalidationClient.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.external.client.android;
-
-import com.google.ipc.invalidation.external.client.InvalidationClient;
-
-/**
- * Extends the {@link InvalidationClient} interface to add Android-specific
- * client functionality.
- *
- */
-public interface AndroidInvalidationClient extends InvalidationClient {
-  /**
-   * Returns the client key that uniquely identifies this client.   The client key can be passed
-   * to {@link AndroidClientFactory#resume} to resume processing with the client instance that
-   * is identified by this.
-   */
-  public String getClientKey();
-
-  /**
-   * Releases any transient resources associated with the client such as connections to bound
-   * services.
-   */
-  public void release();
-
-  /**
-   * Permanently destroys the client and all associated state.
-   */
-  public void destroy();
-}
diff --git a/java/com/google/ipc/invalidation/external/client/android/AndroidInvalidationClientImpl.java b/java/com/google/ipc/invalidation/external/client/android/AndroidInvalidationClientImpl.java
deleted file mode 100644
index 4331e64..0000000
--- a/java/com/google/ipc/invalidation/external/client/android/AndroidInvalidationClientImpl.java
+++ /dev/null
@@ -1,341 +0,0 @@
-/*
- * 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.external.client.android;
-
-import com.google.ipc.invalidation.external.client.SystemResources.Logger;
-import com.google.ipc.invalidation.external.client.android.service.AndroidLogger;
-import com.google.ipc.invalidation.external.client.android.service.Event;
-import com.google.ipc.invalidation.external.client.android.service.InvalidationBinder;
-import com.google.ipc.invalidation.external.client.android.service.InvalidationService;
-import com.google.ipc.invalidation.external.client.android.service.Request;
-import com.google.ipc.invalidation.external.client.android.service.Request.Action;
-import com.google.ipc.invalidation.external.client.android.service.Response;
-import com.google.ipc.invalidation.external.client.android.service.ServiceBinder.BoundWork;
-import com.google.ipc.invalidation.external.client.types.AckHandle;
-import com.google.ipc.invalidation.external.client.types.ObjectId;
-
-import android.accounts.Account;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.RemoteException;
-
-import java.util.Collection;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * Implementation of the {@code InvalidationClient} interface for Android. Instances of the class
- * are obtained using {@link AndroidClientFactory#create} or {@link AndroidClientFactory#resume}.
- * <p>
- * The class provides implementations of the {@code InvalidationClient} methods that delegate to the
- *  invalidation service running on the device using the bound service model defined in
- * {@link InvalidationService}.
- *
- */
-final class AndroidInvalidationClientImpl implements AndroidInvalidationClient {
-  /** Logger */
-  private static final Logger logger = AndroidLogger.forTag("InvClient");
-
-  /**
-   * The application context associated with the client.
-   */
-  public final Context context;
-
-  /**
-   * Contains the device-unique client key associated with this client.
-   */
-  private final String clientKey;
-
-  /**
-   * Contains the client type for this client.
-   */
-  private final int clientType;
-
-  /**
-   * The Account associated with this client. May be {@code null} for resumed clients.
-   */
-  private Account account;
-
-  /**
-   * The authentication type that is used to authenticate the client.
-   */
-  private String authType;
-
-  /**
-   * A service binder used to bind to the invalidation service.
-   */
-  private final InvalidationBinder serviceBinder;
-
-  /**
-   * The {@code InvalidationListener} service class that handles events for this client. May be
-   * {@code null} for resumed clients.
-   */
-  private final Class<? extends AndroidInvalidationListener> listenerClass;
-
-  /**
-   * The number of callers that are sharing a reference to this client instance. Used to decide when
-   * the service binding can be safely released.
-   */
-  private AtomicInteger refcnt = new AtomicInteger(0);
-
-  /** Whether {@link #release} was ever called with a non-positive {@code refcnt}. */
-  
-  AtomicBoolean wasOverReleasedForTest = new AtomicBoolean(false);
-
-  /**
-   * Creates a new invalidation client with the provided client key and account that sends
-   * invalidation events to the specified component.
-   *
-   * @param context the execution context for the client.
-   * @param clientKey a unique id that identifies the created client within the scope of the
-   *        application.
-   * @param account the user account associated with the client.
-   * @param listenerClass the {@link AndroidInvalidationListener} subclass that will handle
-   *        invalidation events.
-   */
-  AndroidInvalidationClientImpl(Context context,
-      String clientKey,
-      int clientType,
-      Account account,
-      String authType,
-      Class<? extends AndroidInvalidationListener> listenerClass) {
-    this.context = context;
-    this.clientKey = clientKey;
-    this.clientType = clientType;
-    this.account = account;
-    this.authType = authType;
-    this.listenerClass = listenerClass;
-    this.serviceBinder = new InvalidationBinder(context);
-  }
-
-  /**
-   * Constructs a resumed invalidation client with the provided client key and context.
-   *
-   * @param context the application context for the client.
-   * @param clientKey a unique id that identifies the resumed client within the scope of the device.
-   */
-  AndroidInvalidationClientImpl(Context context, String clientKey) {
-    this.clientKey = clientKey;
-    this.context = context;
-    this.account = null;
-    this.authType = null;
-    this.listenerClass = null;
-    this.clientType = -1;
-    this.serviceBinder = new InvalidationBinder(context);
-  }
-
-  /**
-   * Returns the {@link Context} within which the client was created or resumed.
-   */
-  Context getContext() {
-    return context;
-  }
-
-  @Override
-  public String getClientKey() {
-    return clientKey;
-  }
-
-  /**
-   * Returns the event listener class associated with the client or {@code null} if unknown (when
-   * resumed).
-   */
-  Class<? extends AndroidInvalidationListener> getListenerClass() {
-    return listenerClass;
-  }
-
-  @Override
-  public void start() {
-    Request request = Request.newBuilder(Action.START).setClientKey(clientKey).build();
-    executeServiceRequest(request);
-  }
-
-  @Override
-  public void stop() {
-    Request request = Request.newBuilder(Action.STOP).setClientKey(clientKey).build();
-    executeServiceRequest(request);
-  }
-
-  /**
-   * Registers to receive invalidation notifications for an object.
-   *
-   * @param objectId object id.
-   */
-  @Override
-  public void register(ObjectId objectId) {
-    Request request =
-        Request.newBuilder(Action.REGISTER).setClientKey(clientKey).setObjectId(objectId).build();
-    executeServiceRequest(request);
-  }
-
-  /**
-   * Registers to receive invalidation notifications for a collection of objects.
-   *
-   * @param objectIds object id collection.
-   */
-  @Override
-  public void register(Collection<ObjectId> objectIds) {
-    Request request =
-        Request.newBuilder(Action.REGISTER).setClientKey(clientKey).setObjectIds(objectIds).build();
-    executeServiceRequest(request);
-  }
-
-  /**
-   * Unregisters to disable receipt of invalidations on an object.
-   *
-   * @param objectId object id.
-   */
-  @Override
-  public void unregister(ObjectId objectId) {
-    Request request =
-        Request.newBuilder(Action.UNREGISTER).setClientKey(clientKey).setObjectId(objectId).build();
-    executeServiceRequest(request);
-  }
-
-  /**
-   * Unregisters to disable receipt of invalidations for a collection of objects.
-   *
-   * @param objectIds object id collection.
-   */
-  @Override
-  public void unregister(Collection<ObjectId> objectIds) {
-    Request request = Request
-        .newBuilder(Action.UNREGISTER)
-        .setClientKey(clientKey)
-        .setObjectIds(objectIds)
-        .build();
-    executeServiceRequest(request);
-  }
-
-  @Override
-  public void acknowledge(AckHandle ackHandle) {
-    Request request = Request
-        .newBuilder(Action.ACKNOWLEDGE)
-        .setClientKey(clientKey)
-        .setAckHandle(ackHandle)
-        .build();
-    executeServiceRequest(request);
-  }
-
-  @Override
-  public void release() {
-    // Release the binding and remove from the client factory when the last reference is
-    // released.
-    final int refsRemaining = refcnt.decrementAndGet();
-    if (refsRemaining < 0) {
-      wasOverReleasedForTest.set(true);
-      logger.warning("Over-release of client %s", clientKey);
-    } else if (refsRemaining == 0) {
-      AndroidClientFactory.release(clientKey);
-      serviceBinder.release();
-    }
-  }
-
-  @Override
-  public void destroy() {
-    Request request = Request
-        .newBuilder(Action.DESTROY)
-        .setClientKey(clientKey)
-        .build();
-    executeServiceRequest(request);
-  }
-
-  /**
-   * Called to initialize a newly created client instance with the invalidation service.
-   */
-  void initialize() {
-    // Create an intent that can be used to fire listener events back to the
-    // provided listener service. Use setComponent and not setPackage/setClass so the
-    // intent is guaranteed to be valid even if the service is not in the same application
-    Intent eventIntent = new Intent(Event.LISTENER_INTENT);
-    ComponentName component = new ComponentName(context.getPackageName(), listenerClass.getName());
-    eventIntent.setComponent(component);
-
-    Request request = Request
-        .newBuilder(Action.CREATE)
-        .setClientKey(clientKey)
-        .setClientType(clientType)
-        .setAccount(account)
-        .setAuthType(authType)
-        .setIntent(eventIntent)
-        .build();
-    executeServiceRequest(request);
-    addReference();
-  }
-
-  /**
-   * Called to resume an existing client instance with the invalidation service. Iff
-   * {@code sendTiclResumeRequest}, a request is sent to the invalidatation service to ensure
-   * that the Ticl is loaded.
-   */
-  void initResumed(boolean sendTiclResumeRequest) {
-    if (sendTiclResumeRequest) {
-      Request request = Request.newBuilder(Action.RESUME).setClientKey(clientKey).build();
-      executeServiceRequest(request);
-    }
-    addReference();
-  }
-
-  /**
-   * Called to indicate that a client instance is being returned as a reference.
-   */
-  void addReference() {
-    refcnt.incrementAndGet();
-  }
-
-  /**
-   * Returns the number of references to this client instance.
-   */
-  
-  int getReferenceCountForTest() {
-    return refcnt.get();
-  }
-
-  /**
-   * Returns {@code true} if the client has a binding to the invalidation service.
-   */
-  
-  boolean hasServiceBindingForTest() {
-    return serviceBinder.isBoundForTest();
-  }
-
-  /**
-   * Executes a request against the invalidation service and does common error processing against
-   * the resulting response. If unable to connect to the service or an error status is received from
-   * it, a warning will be logged and the request will be dropped.
-   *
-   * @param request the request to execute.
-   */
-  private void executeServiceRequest(final Request request) {
-    serviceBinder.runWhenBound(new BoundWork<InvalidationService>() {
-      @Override
-      public void run(InvalidationService service) {
-        Bundle outBundle = new Bundle();
-        try {
-          service.handleRequest(request.getBundle(), outBundle);
-        } catch (RemoteException exception) {
-          logger.warning("Remote exeption executing request %s: %s", request,
-              exception.getMessage());
-        }
-        Response response = new Response(outBundle);
-        response.warnOnFailure();
-      }
-    });
-  }
-}
diff --git a/java/com/google/ipc/invalidation/external/client/android/AndroidInvalidationListener.java b/java/com/google/ipc/invalidation/external/client/android/AndroidInvalidationListener.java
deleted file mode 100644
index 5687d2d..0000000
--- a/java/com/google/ipc/invalidation/external/client/android/AndroidInvalidationListener.java
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * 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.external.client.android;
-
-import com.google.ipc.invalidation.external.client.InvalidationListener;
-import com.google.ipc.invalidation.external.client.SystemResources.Logger;
-import com.google.ipc.invalidation.external.client.android.service.AndroidLogger;
-import com.google.ipc.invalidation.external.client.android.service.Event;
-import com.google.ipc.invalidation.external.client.android.service.Event.Action;
-import com.google.ipc.invalidation.external.client.android.service.ListenerService;
-import com.google.ipc.invalidation.external.client.android.service.Response;
-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 android.app.Service;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.IBinder;
-
-/**
- * An abstract base class for implementing a {@link Service} component
- * that handles events from the invalidation service. This class should be
- * subclassed and concrete implementations of the {@link InvalidationListener}
- * methods added to provide application-specific handling of invalidation
- * events.
- * <p>
- * This implementing subclass should be registered in {@code
- * AndroidManifest.xml} as a service of the invalidation
- * listener binding intent, as in the following sample fragment:
- *
- * <pre>
- * {@code
- * <manifest ...>
- *   <application ...>
- *     ...
- *     service android:name="com.myco.example.AppListenerService" ...>
- *       <intent-filter>
- *         <action android:name="com.google.ipc.invalidation.LISTENER"/>
- *       </intent-filter>
- *     </receiver>
- *     ...
- *   <application>
- *   ...
- * </manifest>
- * }
- * </pre>
- *
- */
-public abstract class AndroidInvalidationListener extends Service
-    implements InvalidationListener {
-
-  /** Logger */
-  private static final Logger logger = AndroidLogger.forTag("InvListener");
-
-  /**
-   * Simple service stub that delegates back to methods on the service.
-   */
-  private final ListenerService.Stub listenerBinder = new ListenerService.Stub() {
-
-    @Override
-    public void handleEvent(Bundle input, Bundle output) {
-      AndroidInvalidationListener.this.handleEvent(input, output);
-    }
-  };
-
-  /** Lock over all state in this class. */
-  private final Object lock = new Object();
-
-  /** Whether the service is in the created state. */
-  private boolean isCreated = false;
-
-  @Override
-  public void onCreate() {
-    synchronized (lock) {
-      super.onCreate();
-      logger.fine("onCreate: %s", this.getClass());
-      this.isCreated = true;
-    }
-  }
-
-  @Override
-  public void onDestroy() {
-    synchronized (lock) {
-      logger.fine("onDestroy: %s", this.getClass());
-      this.isCreated = false;
-      super.onDestroy();
-    }
-  }
-
-  @Override
-  public IBinder onBind(Intent arg0) {
-    synchronized (lock) {
-      logger.fine("Binding: %s", arg0);
-      return listenerBinder;
-    }
-  }
-
-  /**
-   * Handles a {@link ListenerService#handleEvent} call received by the
-   * listener service.
-   *
-   * @param input bundle containing event parameters.
-   * @param output bundled used to return response to the invalidation service.
-   */
-  protected void handleEvent(Bundle input, Bundle output) {
-    synchronized (lock) {
-      if (!isCreated) {
-        logger.warning("Dropping bundle since not created: %s", input);
-        return;
-      }
-      Event event = new Event(input);
-      Response.Builder response = Response.newBuilder(event.getActionOrdinal(), output);
-      // All events should contain an action and client id
-      Action action = event.getAction();
-      String clientKey = event.getClientKey();
-      logger.fine("Received %s event for %s", action, clientKey);
-
-      AndroidInvalidationClient client = null;
-      try {
-        if (clientKey == null) {
-          throw new IllegalStateException("Missing client id:" + event);
-        }
-
-        // Obtain the client instance for the client receiving the event. Do not attempt to load it
-        // at the service: if a Ticl has been unloaded, the listener shouldn't resurrect it, because
-        // that can lead to a zombie client.
-        client = AndroidClientFactory.resume(this, clientKey, false);
-
-        // Determine the event type based upon the request action, extract parameters
-        // from extras, and invoke the listener event handler method.
-        logger.fine("%s event for %s", action, clientKey);
-        switch(action) {
-          case READY:
-          {
-            ready(client);
-            break;
-          }
-          case INVALIDATE:
-          {
-            Invalidation invalidation = event.getInvalidation();
-            AckHandle ackHandle = event.getAckHandle();
-            invalidate(client, invalidation, ackHandle);
-            break;
-          }
-          case INVALIDATE_UNKNOWN:
-          {
-            ObjectId objectId = event.getObjectId();
-            AckHandle ackHandle = event.getAckHandle();
-            invalidateUnknownVersion(client, objectId, ackHandle);
-            break;
-          }
-          case INVALIDATE_ALL:
-          {
-            AckHandle ackHandle = event.getAckHandle();
-            invalidateAll(client, ackHandle);
-            break;
-          }
-          case INFORM_REGISTRATION_STATUS:
-          {
-            ObjectId objectId = event.getObjectId();
-            RegistrationState state = event.getRegistrationState();
-            informRegistrationStatus(client, objectId, state);
-            break;
-          }
-          case INFORM_REGISTRATION_FAILURE:
-          {
-            ObjectId objectId = event.getObjectId();
-            String errorMsg = event.getError();
-            boolean isTransient = event.getIsTransient();
-            informRegistrationFailure(client, objectId, isTransient, errorMsg);
-            break;
-          }
-          case REISSUE_REGISTRATIONS:
-          {
-            byte[] prefix = event.getPrefix();
-            int prefixLength = event.getPrefixLength();
-            reissueRegistrations(client, prefix, prefixLength);
-            break;
-          }
-          case INFORM_ERROR:
-          {
-            ErrorInfo errorInfo = event.getErrorInfo();
-            informError(client, errorInfo);
-            break;
-          }
-          default:
-            logger.warning("Urecognized event: %s", event);
-        }
-        response.setStatus(Response.Status.SUCCESS);
-      } catch (RuntimeException re) {
-        // If an exception occurs during processing, log it, and store the
-        // result in the response sent back to the service.
-        logger.severe("Failure in handleEvent", re);
-        response.setError(re.getMessage());
-      } finally {
-        // Listeners will only use a client reference for the life of the event and release
-        // it immediately since there is no way to know if additional events are coming.
-        if (client != null) {
-          client.release();
-        }
-      }
-    }
-  }
-}
diff --git a/java/com/google/ipc/invalidation/external/client/android/service/AndroidClientException.java b/java/com/google/ipc/invalidation/external/client/android/service/AndroidClientException.java
deleted file mode 100644
index fffe397..0000000
--- a/java/com/google/ipc/invalidation/external/client/android/service/AndroidClientException.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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.external.client.android.service;
-
-/**
- * Represents an invalidation runtime exception that will be raised to the client.
- *
- */
-public class AndroidClientException extends RuntimeException {
-
-  final int status;
-  final String message;
-
-  /**
-   * Creates a new client exception with the provided status value and message
-   * @param status the integer status value that describes the error.
-   * @param message an error message string.
-   *
-   * @see Response.Status
-   */
-  public AndroidClientException(int status, String message) {
-    super(message);
-    this.status = status;
-    this.message = message;
-  }
-}
diff --git a/java/com/google/ipc/invalidation/external/client/android/service/AndroidLogger.java b/java/com/google/ipc/invalidation/external/client/android/service/AndroidLogger.java
index e423db6..301cabd 100644
--- a/java/com/google/ipc/invalidation/external/client/android/service/AndroidLogger.java
+++ b/java/com/google/ipc/invalidation/external/client/android/service/AndroidLogger.java
@@ -82,7 +82,7 @@
    * This should be a value from the {@link Log} constants.
    */
   private static int minimumLogLevel = 0;
-  
+
   /**
    * The maximum length of an Android logging tag. There's no formal constants but the constraint is
    * mentioned in the Log javadoc
@@ -213,7 +213,7 @@
 
   /**
    * Add additional constraint on logging. In addition to the normal check of
-   * {@link Log.isLoggable(String, int)} for logging, this also requires a minimum
+   * {@link Log#isLoggable(String, int)} for logging, this also requires a minimum
    * log level of the given value. This should be a value from the {@link Log} constants.
    */
   public static void setMinimumAndroidLogLevel(int logLevel) {
diff --git a/java/com/google/ipc/invalidation/external/client/android/service/Event.java b/java/com/google/ipc/invalidation/external/client/android/service/Event.java
deleted file mode 100644
index e9fa90f..0000000
--- a/java/com/google/ipc/invalidation/external/client/android/service/Event.java
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * 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.external.client.android.service;
-
-import com.google.ipc.invalidation.external.client.InvalidationListener.RegistrationState;
-import com.google.ipc.invalidation.external.client.types.ErrorInfo;
-import com.google.ipc.invalidation.external.client.types.Invalidation;
-
-import android.content.Intent;
-import android.os.Bundle;
-
-/**
- * Creates and interprets event message bundles sent from the invalidation
- * service to its application clients.
- *
- */
-public class Event extends Message {
-
-  /** An intent that can be used to bind to the event listener service */
-  public static final Intent LISTENER_INTENT = new Intent("com.google.ipc.invalidation.EVENT");
-
-  /** The set of event action types */
-  public static enum Action {
-
-    /** Indicates client is ready for use */
-    READY,
-
-    /** Invalidate an object */
-    INVALIDATE,
-
-    /** Invalidation an object with an unknown version */
-    INVALIDATE_UNKNOWN,
-
-    /** Invalidate all objects */
-    INVALIDATE_ALL,
-
-    /** Registration status change notification */
-    INFORM_REGISTRATION_STATUS,
-
-    /** Registration failure */
-    INFORM_REGISTRATION_FAILURE,
-
-    /** Request to reissue registrations */
-    REISSUE_REGISTRATIONS,
-
-    /** Processing error */
-    INFORM_ERROR,
-  }
-
-  /** The set of parameters that can be found in event message bundles */
-  public class Parameter extends Message.Parameter {
-
-    /**  Contains a {@link ParcelableErrorInfo} that represents an error */
-    public static final String ERROR_INFO = "errorInfo";
-
-    /** Contains an {@link ParcelableInvalidation} */
-    public static final String INVALIDATION = "invalidation";
-
-    /** Contains a boolean value indicating whether an event error is transient */
-    public static final String IS_TRANSIENT = "isTransient";
-
-    /** Contains an integer ordinal value representing a registration state */
-    public static final String REGISTRATION_STATE = "registrationState";
-
-    /** Byte array prefix of registrations requested or -1 if no prefix is present */
-    public static final String PREFIX = "prefix";
-
-    /** The integer number of bits in {@link #PREFIX} */
-    public static final String PREFIX_LENGTH = "prefixLength";
-  }
-
-  /**
-   * A builder class for constructing new event messages.
-   *
-   * @see #newBuilder
-   */
-  public static class Builder extends Message.Builder<Event, Builder> {
-
-    // Use newBuilder()
-    private Builder(Action action) {
-      super(action.ordinal(), new Bundle());
-    }
-
-    /**
-     * Stores error information within an event message.
-     */
-    public Builder setErrorInfo(ErrorInfo errorInfo) {
-      bundle.putParcelable(Parameter.ERROR, new ParcelableErrorInfo(errorInfo));
-      return this;
-    }
-
-    /**
-     * Stores in invalidation within an event message.
-     */
-    public Builder setInvalidation(Invalidation invalidation) {
-      bundle.putParcelable(Parameter.INVALIDATION, new ParcelableInvalidation(invalidation, true));
-      return this;
-    }
-
-   /*
-    * Stores in registrations requested prefix within an event message.
-    *
-    * @param prefix the registration digest prefix
-    * @param prefixLength the number of significant bits in the prefix
-    */
-   public Builder setPrefix(byte [] prefix, int prefixLength) {
-     bundle.putByteArray(Parameter.PREFIX, prefix);
-     bundle.putInt(Parameter.PREFIX_LENGTH, prefixLength);
-     return this;
-   }
-
-    /**
-     * Stores the isTransient flag within an event message.
-     */
-    public Builder setIsTransient(boolean isTransient) {
-      bundle.putBooleanArray(Parameter.IS_TRANSIENT, new boolean [] { isTransient });
-      return this;
-    }
-
-    /**
-     * Stores registration state information within an event message.
-     */
-    public Builder setRegistrationState(RegistrationState state) {
-      bundle.putInt(Parameter.REGISTRATION_STATE, state.ordinal());
-      return this;
-    }
-
-    /**
-     * Returns an event containing the set parameters.
-     */
-    @Override
-    public Event build() {
-      return new Event(bundle);
-    }
-  }
-
-  /**
-   * Constructs a new builder for an event associated with the provided action.
-   */
-  public static Builder newBuilder(Action action) {
-    return new Builder(action);
-  }
-
-  /**
-   * Constructs a new event using the contents of the provided parameter bundle.
-   */
-  public Event(Bundle bundle) {
-    super(bundle);
-  }
-
-  /**
-   * Returns the action from an event message.
-   */
-  public Action getAction() {
-    return Action.values()[getActionOrdinal()];
-  }
-
-  /**
-   * Returns the error information from an event message, or {@code null} if not present.
-   */
-  public ErrorInfo getErrorInfo() {
-    ParcelableErrorInfo parcelableErrorInfo = parameters.getParcelable(Parameter.ERROR);
-    return parcelableErrorInfo != null ? parcelableErrorInfo.errorInfo : null;
-  }
-
-  /**
-   * Returns an invalidation from an event message, or {@code null} if not present.
-   */
-  public Invalidation getInvalidation() {
-    ParcelableInvalidation parcelableInvalidation =
-        parameters.getParcelable(Parameter.INVALIDATION);
-    return parcelableInvalidation != null ? parcelableInvalidation.invalidation : null;
-  }
-
-  /**
-   * Returns the isTransient flag from within an event, or {@code null} if not present.
-   */
-  public boolean getIsTransient() {
-    boolean [] isTransient = parameters.getBooleanArray(Parameter.IS_TRANSIENT);
-    return isTransient != null ? isTransient[0] : null;
-  }
-
-  /**
-   * Returns the registration prefix from the event, or {@code null} if not present.
-   */
-  public byte [] getPrefix() {
-    return parameters.getByteArray(Parameter.PREFIX);
-  }
-
-  /**
-   * Returns the length of the registration prefix in bits or {@code -1} if not present.
-   */
-  public int getPrefixLength() {
-    return parameters.getInt(Parameter.PREFIX_LENGTH, -1);
-  }
-
-  /**
-   * Returns the registration state from an event message, or {@code null} if not present.
-   */
-  public RegistrationState getRegistrationState() {
-    int ordinal = parameters.getInt(Parameter.REGISTRATION_STATE, -1);
-    return ordinal < 0 ? null : RegistrationState.values()[ordinal];
-  }
-}
diff --git a/java/com/google/ipc/invalidation/external/client/android/service/InvalidationBinder.java b/java/com/google/ipc/invalidation/external/client/android/service/InvalidationBinder.java
deleted file mode 100644
index de6c02f..0000000
--- a/java/com/google/ipc/invalidation/external/client/android/service/InvalidationBinder.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * 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.external.client.android.service;
-
-import android.content.Context;
-import android.os.IBinder;
-
-/**
- * A service binder implementation for connecting to the {@link InvalidationService}.
- *
- */
-public class InvalidationBinder extends ServiceBinder<InvalidationService> {
-
-  /**
-   * Contains the name of the service implementation class that will be explicit bound to or
-   * {@code null} if implicitly binding
-   */
-  private static String serviceClassName;
-
-  static {
-    try {
-      // If the expected service class if found in the current application, use an explicit binding
-      // otherwise an implicit, intent-based binding will be used.  The latter capability is
-      // generally only to support mock and test service bindings.
-      Class<?> serviceClass =
-          Class.forName("com.google.ipc.invalidation.ticl.android.AndroidInvalidationService");
-      serviceClassName = serviceClass.getName();
-    } catch (ClassNotFoundException e) {
-      serviceClassName = null;
-    }
-  }
-
-  /**
-   * Constructs a new InvalidationBinder that connects to the invalidation service.
-   */
-  public InvalidationBinder(Context context) {
-    super(context, Request.SERVICE_INTENT, InvalidationService.class, serviceClassName);
-  }
-
-  @Override
-  protected InvalidationService asInterface(IBinder binder) {
-    return InvalidationService.Stub.asInterface(binder);
-  }
-}
diff --git a/java/com/google/ipc/invalidation/external/client/android/service/InvalidationService.aidl b/java/com/google/ipc/invalidation/external/client/android/service/InvalidationService.aidl
deleted file mode 100644
index 6cc3732..0000000
--- a/java/com/google/ipc/invalidation/external/client/android/service/InvalidationService.aidl
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * 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.external.client.android.service;
-
-import android.os.Bundle;
-
-/**
- * Defines the bound service interface for the Invalidation service.   The service exposes
- * an intent-like model with a single {@link #handleRrequest} entry point that packages the
- * action and its parameters into a {@link Bundle} but uses a synchronous calling model where
- * a response bundle is also returned to the client containing status and any result or
- * failure information.
- * <p>
- * Having a single entry point (as compared to a interface method per action with explicit
- * parameters) will make it easier to evolve the interface over time.   New action types or
- * additional optional parameters can be added in subsequent versions without changing the
- * service interface in ways that would be incompatible with existing clients.  This is
- * important because the service will be packaged (and updated) independently from clients
- * of the invalidation service.
- * <p>
- * The synchronous nature of the interface (having a response object that can indicate success
- * or failure of an action) is important to support reliable registrations.  If a client
- * sends a registration request, it's important to know that it has been successfully received
- * by the local invalidation service.
- *
- * Before binding, the invalidation service should first ensure that the service is started by
- * calling the {@code Context#startService} with the {@link ServiceParameter#SERVICE_INTENT}.
- * The client can then bind to the service using {@code Context#bindService} with the same
- * intent.   Clients should never explicitly stop the service;  the service itself will decide
- * when it has successfully processed all requests from active clients and will stop itself.
- */
-interface InvalidationService {
-
-  /**
-   * Sends a request to the invalidation service and retrieves the response containing any
-   * return data or status/error information.   The {@code action} parameter in the request
-   * bundle will indicate the type of request to be executed and the request parameters will
-   * also be stored in the bundle.   The service will acknowledge successful processing of
-   * the request by returning a response bundle that contains a {@code status} parameter
-   * indicating the success or failure of the request.  If successful, any other output
-   * parameters will be included as values in the response bundle.  On failure, additional
-   * error or debug information will be included in the response bundle.
-   *
-   * @see Request
-   * @see Response
-   */
-  void handleRequest(in Bundle request, out Bundle response);
-}
diff --git a/java/com/google/ipc/invalidation/external/client/android/service/ListenerBinder.java b/java/com/google/ipc/invalidation/external/client/android/service/ListenerBinder.java
deleted file mode 100644
index ae371e5..0000000
--- a/java/com/google/ipc/invalidation/external/client/android/service/ListenerBinder.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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.external.client.android.service;
-
-import android.content.Context;
-import android.content.Intent;
-import android.os.IBinder;
-
-/**
- * A service binder for connecting to a client {@link ListenerService}.
- *
- */
-public class ListenerBinder extends ServiceBinder<ListenerService> {
-
-  /**
-   * Constructs a new ListenerBinder that connects to the ListenerService bound by the provided
-   * intent. The intent should contain the component or class name of the target listener.
-   */
-  public ListenerBinder(Context context, Intent listenerIntent, String listenerClassName) {
-    super(context, listenerIntent, ListenerService.class, listenerClassName);
-  }
-
-  @Override
-  protected ListenerService asInterface(IBinder binder) {
-    return ListenerService.Stub.asInterface(binder);
-  }
-}
diff --git a/java/com/google/ipc/invalidation/external/client/android/service/ListenerService.aidl b/java/com/google/ipc/invalidation/external/client/android/service/ListenerService.aidl
deleted file mode 100644
index fdbbb89..0000000
--- a/java/com/google/ipc/invalidation/external/client/android/service/ListenerService.aidl
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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.external.client.android.service;
-
-import android.os.Bundle;
-
-/**
- * Defines the bound service interface for an Invalidation listener service.  The service 
- * exposes an intent-like model with a single {@link #handleEvent} entry point that packages
- * the event action and its parameters into a {@link Bundle} but uses a synchronous calling
- * model where a response bundle is also returned to the service containing status and/or
- * <p>
- * Having a single entry point (as compared to a interface method per action with explicit
- * parameters) will make it easier to evolve the interface over time.   New event types or
- * additional optional parameters can be added in subsequent versions without changing the
- * service interface in ways that would be incompatible with existing clients.  This is
- * important because the listener services will be packaged (and updated) independently from
- * the invalidation service.
- * <p>
- * The synchronous nature of the interface (having a response object that can indicate success
- * or failure of event handling) is important to support reliable events.  If the service
- * sends a registration request, it's important to know that it has been successfully received
- * by the local invalidation service.
- *
- * The invalidation service will bind to the invalidation listener using an intent that
- * contains the {@link Event.LISTENER} action along with the explicit listener class name
- * that was provided to {@code AndroidClientFactory.create()}.
- */
-interface ListenerService {
-
-  /**
-   * Sends a request to the invalidation service and retrieves the response containing any
-   * return data or status/error information.   The {@code action} parameter in the request
-   * bundle will indicate the type of request to be executed and the request parameters will
-   * also be stored in the bundle.   The service will acknowledge successful processing of
-   * the request by returning a response bundle that contains a {@code status} parameter
-   * indicating the success or failure of the request.  If successful, any other output
-   * parameters will be included as values in the response bundle.  On failure, additional
-   * error or debug information will be included in the response bundle.
-   *
-   * @see Event
-   * @see Response
-   */
-  void handleEvent(in Bundle event, out Bundle response);
-}
diff --git a/java/com/google/ipc/invalidation/external/client/android/service/Message.java b/java/com/google/ipc/invalidation/external/client/android/service/Message.java
deleted file mode 100644
index 6749a30..0000000
--- a/java/com/google/ipc/invalidation/external/client/android/service/Message.java
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * 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.external.client.android.service;
-
-import com.google.ipc.invalidation.external.client.android.service.Request.Action;
-import com.google.ipc.invalidation.external.client.types.AckHandle;
-import com.google.ipc.invalidation.external.client.types.ObjectId;
-
-import android.accounts.Account;
-import android.os.Bundle;
-
-/**
- * A base class for message bundles sent to/from the invalidation service. This
- * class provides the declaration of the base parameter names, a basic builder
- * class for storing them in messages, and the accessor methods to read them.
- *
- */
-public abstract class Message {
-  protected final Bundle parameters;
-
-  /** The list of parameter names that are common across message types */
-  public static class Parameter {
-    protected Parameter() {} // can subclass but not instantiate
-
-    public static final String ACTION = "action";
-
-    public static final String ACCOUNT = "account";
-
-    public static final String AUTH_TYPE = "authType";
-
-    public static final String ACK_TOKEN = "ackToken";
-
-    public static final String CLIENT = "client";
-
-    public static final String OBJECT_ID = "objectId";
-
-    /** A string value describing any error in processing */
-    public static final String ERROR = "error";
-  }
-
-  /**
-   * A base builder class for constructing new messages and populating
-   * them with parameter values.
-   *
-   * @param <MessageType> the message type constructed by the builder
-   * @param <BuilderType> the concrete builder subtype
-   */
-  protected abstract static class Builder<MessageType extends Message,
-                                          BuilderType extends Builder<?, ?>> {
-    protected final Bundle bundle;
-
-    // Typed pointer to 'this' that's set once in constructor for return by setters,
-    // to avoid unchecked warning suppression throughout the code
-    private BuilderType thisInstance;
-
-    @SuppressWarnings("unchecked")
-    protected Builder(int actionOrdinal, Bundle b) {
-      this.bundle = b;
-      this.thisInstance = (BuilderType) this; // requires unchecked but is safe
-      b.putInt(Parameter.ACTION, actionOrdinal);
-    }
-
-    /** Stores an account in the built parameters. */
-    public BuilderType setAccount(Account account) {
-      bundle.putParcelable(Parameter.ACCOUNT, account);
-      return thisInstance;
-    }
-
-    /** Stores an acknowledgement handle in the built parameters. */
-    public BuilderType setAckHandle(AckHandle ackHandle) {
-      bundle.putByteArray(Parameter.ACK_TOKEN, ackHandle.getHandleData());
-      return thisInstance;
-    }
-
-    /** Stores the authentication type in the built parameters */
-    public BuilderType setAuthType(String authType) {
-      bundle.putString(Parameter.AUTH_TYPE, authType);
-      return thisInstance;
-    }
-
-    /** Stores a client key in the built parameters. */
-    public BuilderType setClientKey(String clientKey) {
-      bundle.putString(Parameter.CLIENT, clientKey);
-      return thisInstance;
-    }
-
-
-    /** Stores an error message value within a response message.*/
-    public BuilderType setError(String message) {
-      bundle.putString(Parameter.ERROR, message);
-      return thisInstance;
-    }
-
-    /** Stores an object ID in the built parameters. */
-    public BuilderType setObjectId(ObjectId objectId) {
-      bundle.putParcelable(Parameter.OBJECT_ID, new ParcelableObjectId(objectId));
-      return thisInstance;
-    }
-
-    /**
-     * Returns the message associated with the builder.  Concrete subclasses
-     * will override to return a concrete message instance.
-     */
-    public abstract MessageType build();
-  }
-
-  /**
-   * Constructs a new message containing the the parameters in the provide bundle.
-   */
-  protected Message(Bundle bundle) {
-    this.parameters = bundle;
-  }
-
-  /**
-   * Returns the parameter bundle associated with the message.
-   */
-  public Bundle getBundle() {
-    return parameters;
-  }
-
-  /**
-   * Returns the action set on the message or {@code null} if not set. For
-   * request or event messages, this will be the action associated with the
-   * message. For response messages, it will be the action associated with the
-   * original request or event that is being responded to.
-   */
-  public int getActionOrdinal() {
-    return parameters.getInt(Parameter.ACTION);
-  }
-
-  /** Returns the account set on the message or {@code null} if not set. */
-  public Account getAccount() {
-    return parameters.getParcelable(Parameter.ACCOUNT);
-  }
-
-  /** Returns the acknowledgement handle set on the message or {@code null} if not set */
-  public AckHandle getAckHandle() {
-    byte [] tokenData = parameters.getByteArray(Parameter.ACK_TOKEN);
-    return tokenData != null ? AckHandle.newInstance(tokenData) : null;
-  }
-
-  /** Returns the authentication type set on the message or {@code null} if not set */
-  public String getAuthType() {
-    return parameters.getString(Parameter.AUTH_TYPE);
-  }
-
-  /** Returns the client key set on the message or {@code null} if not set */
-  public String getClientKey() {
-    return parameters.getString(Parameter.CLIENT);
-  }
-
-  /**
-   * Returns the error message string or {@code null} if not present.
-   */
-  public String getError() {
-    return parameters.getString(Parameter.ERROR);
-  }
-
-  /** Returns the object id set on the message or {@code null} if not set */
-  public ObjectId getObjectId() {
-    ParcelableObjectId parcelableObjectId = parameters.getParcelable(Parameter.OBJECT_ID);
-    return parcelableObjectId != null ? parcelableObjectId.objectId : null;
-  }
-
-  @Override
-  public String toString() {
-    String actionStr = (getActionOrdinal() < Action.values().length) ?
-        Action.values()[getActionOrdinal()].toString() : "invalid";
-    return "Message ACTION = " + actionStr + " CLIENT = " + getClientKey();
-  }
-}
diff --git a/java/com/google/ipc/invalidation/external/client/android/service/ParcelableErrorInfo.java b/java/com/google/ipc/invalidation/external/client/android/service/ParcelableErrorInfo.java
deleted file mode 100644
index 4d06e55..0000000
--- a/java/com/google/ipc/invalidation/external/client/android/service/ParcelableErrorInfo.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * 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.external.client.android.service;
-
-import com.google.ipc.invalidation.external.client.types.ErrorInfo;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Wraps an {link ErrorInfo} to enable writing to and reading from a
- * {@link Parcel}.
- */
-class ParcelableErrorInfo implements Parcelable {
-  final ErrorInfo errorInfo;
-
-  /**
-   * Creator required by the Parcelable implementation conventions.
-   */
-  public static final Parcelable.Creator<ParcelableErrorInfo> CREATOR =
-      new Parcelable.Creator<ParcelableErrorInfo>() {
-        @Override
-        public ParcelableErrorInfo createFromParcel(Parcel in) {
-          return new ParcelableErrorInfo(in);
-        }
-
-        @Override
-        public ParcelableErrorInfo[] newArray(int size) {
-          return new ParcelableErrorInfo[size];
-        }
-      };
-
-  /**
-   * Creates a new wrapper around the provided error info.
-   */
-  ParcelableErrorInfo(ErrorInfo errorInfo) {
-    this.errorInfo = errorInfo;
-  }
-
-  /**
-   * Creates a new ErrorInfo wrapper by reading data from a parcel.
-   */
-  public ParcelableErrorInfo(Parcel in) {
-    int reason = in.readInt();
-    boolean isTransient = in.createBooleanArray()[0];
-    String message = in.readString();
-    this.errorInfo = ErrorInfo.newInstance(reason, isTransient, message, null);
-  }
-
-  @Override
-  public int describeContents() {
-    return 0;  // no special contents
-  }
-
-  @Override
-  public void writeToParcel(Parcel parcel, int flags) {
-
-    // Data written to parcel is:
-    // 1. int errorReason
-    // 2. boolean [] { isTransient }
-    // 3. String error message
-    // TODO: Add support for object marshaling when needed
-    parcel.writeInt(errorInfo.getErrorReason());
-    parcel.writeBooleanArray(new boolean[]{errorInfo.isTransient()});
-    parcel.writeString(errorInfo.getErrorMessage());
-  }
-
-  @Override
-  public boolean equals(Object object) {
-    return object instanceof ParcelableErrorInfo
-        && errorInfo.equals(((ParcelableErrorInfo) object).errorInfo);
-  }
-
-  @Override
-  public int hashCode() {
-    return errorInfo.hashCode();
-  }
-}
diff --git a/java/com/google/ipc/invalidation/external/client/android/service/ParcelableInvalidation.java b/java/com/google/ipc/invalidation/external/client/android/service/ParcelableInvalidation.java
deleted file mode 100644
index da47e2c..0000000
--- a/java/com/google/ipc/invalidation/external/client/android/service/ParcelableInvalidation.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * 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.external.client.android.service;
-
-import com.google.ipc.invalidation.external.client.types.Invalidation;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Wraps an {link Invalidation} to enable writing to and reading from a
- * {@link Parcel}.
- */
-class ParcelableInvalidation implements Parcelable {
-  final Invalidation invalidation;
-  final boolean includePayload;
-
-  /**
-   * Creator required by the Parcelable implementation conventions.
-   */
-  public static final Parcelable.Creator<ParcelableInvalidation> CREATOR =
-      new Parcelable.Creator<ParcelableInvalidation>() {
-        @Override
-        public ParcelableInvalidation createFromParcel(Parcel in) {
-          return new ParcelableInvalidation(in);
-        }
-
-        @Override
-        public ParcelableInvalidation[] newArray(int size) {
-          return new ParcelableInvalidation[size];
-        }
-      };
-
-  /**
-   * Creates a new wrapper around the provided invalidation
-   */
-  ParcelableInvalidation(Invalidation invalidation, boolean includePayload) {
-    this.invalidation = invalidation;
-    this.includePayload = includePayload;
-  }
-
-  /**
-   * Creates a new invalidation wrapper by reading data from a parcel.
-   */
-  public ParcelableInvalidation(Parcel in) {
-    // Read parcelable object id from parcel using the application class loader
-    ParcelableObjectId objectId = in.readParcelable(getClass().getClassLoader());
-    long version = in.readLong();
-    boolean isTrickleRestart = in.createBooleanArray()[0];
-    boolean[] values = in.createBooleanArray();
-    byte[] payload = null;
-    if (values[0]) { // hasPayload
-      payload = in.createByteArray();
-    }
-    this.invalidation = Invalidation.newInstance(objectId.objectId, version, payload,
-        isTrickleRestart);
-    this.includePayload = payload != null;
-  }
-
-  @Override
-  public int describeContents() {
-    return 0;  // no special contents
-  }
-
-  @Override
-  public void writeToParcel(Parcel parcel, int flags) {
-
-    // Data written to parcel is:
-    // 1. object id (as ParcelableObjectId)
-    // 2. long version
-    // 3. boolean [] { isTrickleRestart }
-    // 4. boolean [] { hasPayload }
-    // 5. byte array for payload (if hasPayload)
-    parcel.writeParcelable(new ParcelableObjectId(invalidation.getObjectId()), 0);
-    parcel.writeLong(invalidation.getVersion());
-    parcel.writeBooleanArray(new boolean[] {invalidation.getIsTrickleRestartForInternalUse()});
-    byte[] payload = invalidation.getPayload();
-    if (includePayload && payload != null) {
-      parcel.writeBooleanArray(new boolean[] {true});
-      parcel.writeByteArray(payload);
-    } else {
-      parcel.writeBooleanArray(new boolean[] {false});
-    }
-  }
-
-  @Override
-  public boolean equals(Object object) {
-    return object instanceof ParcelableInvalidation
-        && invalidation.equals(((ParcelableInvalidation) object).invalidation);
-  }
-
-  @Override
-  public int hashCode() {
-    return invalidation.hashCode();
-  }
-}
diff --git a/java/com/google/ipc/invalidation/external/client/android/service/ParcelableObjectId.java b/java/com/google/ipc/invalidation/external/client/android/service/ParcelableObjectId.java
deleted file mode 100644
index e7da821..0000000
--- a/java/com/google/ipc/invalidation/external/client/android/service/ParcelableObjectId.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * 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.external.client.android.service;
-
-import com.google.ipc.invalidation.external.client.types.ObjectId;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Wraps an {link ObjectId} to enable writing to and reading from a
- * {@link Parcel}.
- */
-class ParcelableObjectId implements Parcelable {
-  final ObjectId objectId;
-
-  /**
-   * Creator required by the Parcelable implementation conventions.
-   */
-  public static final Parcelable.Creator<ParcelableObjectId> CREATOR =
-      new Parcelable.Creator<ParcelableObjectId>() {
-        @Override
-        public ParcelableObjectId createFromParcel(Parcel in) {
-          return new ParcelableObjectId(in);
-        }
-
-        @Override
-        public ParcelableObjectId[] newArray(int size) {
-          return new ParcelableObjectId[size];
-        }
-      };
-
-  /**
-   * Creates a new wrapper around the provided object id.
-   */
-  ParcelableObjectId(ObjectId objectId) {
-    this.objectId = objectId;
-  }
-
-  /**
-   * Creates a new wrapper and object id by reading data from a parcel.
-   */
-  private ParcelableObjectId(Parcel in) {
-    int source = in.readInt();
-    byte[] value = in.createByteArray();
-    objectId = ObjectId.newInstance(source, value);
-  }
-
-  @Override
-  public int describeContents() {
-    return 0;  // no special contents
-  }
-
-  @Override
-  public void writeToParcel(Parcel parcel, int flags) {
-
-    // Data written to parcel is:
-    // 1. numeric value of source type
-    // 2. byte array for name
-    parcel.writeInt(objectId.getSource());
-    parcel.writeByteArray(objectId.getName());
-  }
-
-  @Override
-  public boolean equals(Object object) {
-    return object instanceof ParcelableObjectId
-        && objectId.equals(((ParcelableObjectId) object).objectId);
-  }
-
-  @Override
-  public int hashCode() {
-    return objectId.hashCode();
-  }
-}
diff --git a/java/com/google/ipc/invalidation/external/client/android/service/Request.java b/java/com/google/ipc/invalidation/external/client/android/service/Request.java
deleted file mode 100644
index e684843..0000000
--- a/java/com/google/ipc/invalidation/external/client/android/service/Request.java
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * 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.external.client.android.service;
-
-import com.google.ipc.invalidation.external.client.types.ObjectId;
-
-import android.content.Intent;
-import android.os.Bundle;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-/**
- * Creates and interprets request message bundles sent to the invalidation
- * service from its application clients.
- *
- */
-public final class Request extends Message {
-
-  /**
-   * An intent that can be used to bind to the invalidation service.
-   */
-  public static final Intent SERVICE_INTENT = new Intent("com.google.ipc.invalidation.SERVICE");
-
-  /**
-   * Contains the list of request action names.
-   */
-  public static enum Action {
-
-    /** Creates a new invalidation client instance */
-    CREATE,
-
-    /** Resumes an invalidation client instances */
-    RESUME,
-
-    /** Starts the invalidation client */
-    START,
-
-    /** Stops an invalidation client */
-    STOP,
-
-    /** Registers for invalidation notifications on an object */
-    REGISTER,
-
-    /** Unregisters for invalidation notifications on an object */
-    UNREGISTER,
-
-    /** Acknowledges an event recieved from the invalidations service */
-    ACKNOWLEDGE,
-
-    /** Destroys the client permanently */
-    DESTROY;
-  }
-
-  /**
-   * Contains the list of parameter names that are valid for request bundles
-   */
-  public static class Parameter extends Message.Parameter {
-    private Parameter() {} // not instantiable
-
-    /** Contains the integer client type */
-    public static final String CLIENT_TYPE = "clientType";
-
-    /** Contains an {@link Intent} value that can be used to bind for event delivery */
-    public static final String INTENT = "intent";
-
-    /** Contains an {@link ArrayList} of {@link ObjectId} instances */
-    public static final String OBJECT_ID_LIST = "objectIdList";
-  }
-
-  /**
-   * A builder class for constructing new request messages.
-   *
-   * @see #newBuilder
-   */
-  public static class Builder extends Message.Builder<Request, Builder> {
-
-    // Constructed using newBuilder()
-    private Builder(Action action) {
-      super(action.ordinal(), new Bundle());
-    }
-
-    /**
-     * Stores the client type within a request message.
-     */
-    public Builder setClientType(int clientType) {
-      bundle.putInt(Parameter.CLIENT_TYPE, clientType);
-      return this;
-    }
-
-    /**
-     * Stores an intent within a request message.
-     */
-    public Builder setIntent(Intent eventIntent) {
-      bundle.putParcelable(Parameter.INTENT, eventIntent);
-      return this;
-    }
-
-
-    /** Stores a collection object IDs in the built parameters */
-    public Builder setObjectIds(Collection<ObjectId> objectIds) {
-      ArrayList<ParcelableObjectId> objectList =
-          new ArrayList<ParcelableObjectId>(objectIds.size());
-      for (ObjectId objectId : objectIds) {
-        objectList.add(new ParcelableObjectId(objectId));
-      }
-      bundle.putParcelableArrayList(Parameter.OBJECT_ID_LIST, objectList);
-      return this;
-    }
-
-    /**
-     * Returns an event containing the set parameters.
-     */
-    @Override
-    public Request build() {
-      return new Request(bundle);
-    }
-  }
-
-  /**
-   * Constructs a new builder for a request associated with the provided action.
-   */
-  public static Builder newBuilder(Action action) {
-    return new Builder(action);
-  }
-
-  /**
-   * Constructs a new request using the contents of the provided parameter bundle.
-   */
-  public Request(Bundle bundle) {
-    super(bundle);
-  }
-
-  /**
-   * Returns the action from a request message.
-   */
-  public Action getAction() {
-    return Action.values()[getActionOrdinal()];
-  }
-
-  /**
-   * Returns the client type from a request message, or {@code -1} if not present.
-   */
-  public int getClientType() {
-    return parameters.getInt(Parameter.CLIENT_TYPE, -1);
-  }
-
-  /**
-   * Returns the intent from a request message, or {@code null} if not present.
-   */
-  public Intent getIntent() {
-    return parameters.getParcelable(Parameter.INTENT);
-  }
-
-
-  /** Returns the object ID set on the message or {@code null} if not set */
-  public Collection<ObjectId> getObjectIds() {
-    List<ParcelableObjectId> parcelableObjectIds =
-        parameters.getParcelableArrayList(Parameter.OBJECT_ID_LIST);
-    if (parcelableObjectIds == null) {
-      return null;
-    }
-    List<ObjectId> objectIds = new ArrayList<ObjectId>(parcelableObjectIds.size());
-    for (ParcelableObjectId parcelableObjectId : parcelableObjectIds) {
-      objectIds.add(parcelableObjectId.objectId);
-    }
-    return objectIds;
-  }
-}
diff --git a/java/com/google/ipc/invalidation/external/client/android/service/Response.java b/java/com/google/ipc/invalidation/external/client/android/service/Response.java
deleted file mode 100644
index f189d03..0000000
--- a/java/com/google/ipc/invalidation/external/client/android/service/Response.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * 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.external.client.android.service;
-
-import android.os.Bundle;
-
-/**
- * Creates and interprets response message bundles returned by the invalidation
- * service or application clients in response to request or event messages.
- *
- */
-public final class Response extends Message {
-  private static final AndroidLogger logger = AndroidLogger.forTag("Response");
-
-  /** Contains the list of parameter names that are valid for response bundles. */
-  public static class Parameter extends Message.Parameter {
-    private Parameter() {} // not instantiable
-
-    /**
-     * An integer status code indicating success or failure.
-     *
-     * @see Status
-     */
-    public static final String STATUS = "status";
-  }
-
-  /** Defined values for the {@link Parameter#STATUS} parameter. */
-  public static class Status {
-    public static final int SUCCESS = 0;
-    public static final int INVALID_CLIENT = 1;
-    public static final int RUNTIME_ERROR = -1;
-    public static final int UNKNOWN = -2;
-  }
-
-  /**
-   * A builder class for constructing new response messages.
-   *
-   * @see #newBuilder
-   */
-  public static class Builder extends Message.Builder<Response, Builder> {
-
-    // Instantiate using newBuilder()
-    private Builder(int actionOrdinal, Bundle b) {
-      super(actionOrdinal, b);
-    }
-
-    /**
-     * Stores a status value within a response message.
-     */
-    public Builder setStatus(int status) {
-      bundle.putInt(Parameter.STATUS, status);
-      return this;
-    }
-
-    /**
-     * Sets the status to {@link Status#RUNTIME_ERROR} and the error message to
-     * the exception message within a response message.
-     */
-    public void setException(Exception exception) {
-      if (exception instanceof AndroidClientException) {
-        AndroidClientException ace = (AndroidClientException) exception;
-        setStatus(ace.status);
-        setError(ace.message);
-      } else {
-        setStatus(Status.RUNTIME_ERROR);
-        setError(exception.getMessage());
-      }
-    }
-
-    /**
-     * Returns an response containing the set parameters.
-     */
-    @Override
-    public Response build() {
-      return new Response(bundle);
-    }
-  }
-
-  /**
-   * Constructs a new builder for a response associated with the provided action
-   * that will store parameters into the provided bundle.
-   */
-  public static Builder newBuilder(int actionOrdinal, Bundle b) {
-    return new Builder(actionOrdinal, b);
-  }
-
-  /**
-   * Constructs a new response using the contents of the provided parameter bundle.
-   */
-  public Response(Bundle bundle) {
-    super(bundle);
-  }
-
-  /**
-   * Returns the status from a response message or {@link Status#UNKNOWN} if not
-   * set by the callee (presumed failure).
-   */
-  public int getStatus() {
-    return parameters.getInt(Parameter.STATUS, Status.UNKNOWN);
-  }
-
-  /**
-   * Logs an error if the response message contains a status value other than
-   * {@link Status#SUCCESS}.
-   */
-  public void warnOnFailure() {
-    int status = getStatus();
-    if (status != Status.SUCCESS) {
-      String error = parameters.getString(Parameter.ERROR);
-      if (error == null) {
-        error = "Unexpected status value:" + status;
-      }
-      logger.warning("Error from AndroidInvalidationService: %s", error);
-    }
-  }
-}
diff --git a/java/com/google/ipc/invalidation/external/client/android/service/ServiceBinder.java b/java/com/google/ipc/invalidation/external/client/android/service/ServiceBinder.java
deleted file mode 100644
index 4856cdc..0000000
--- a/java/com/google/ipc/invalidation/external/client/android/service/ServiceBinder.java
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * 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.external.client.android.service;
-
-import com.google.common.base.Preconditions;
-import com.google.ipc.invalidation.external.client.SystemResources.Logger;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.IBinder;
-
-import java.util.LinkedList;
-import java.util.Queue;
-
-
-/**
- * Abstract base class that assists in making connections to a bound service. Subclasses can define
- * a concrete binding to a particular bound service interface by binding to an explicit type on
- * declaration, providing a public constructor, and providing an implementation of the
- * {@link #asInterface} method.
- * <p>
- * This class has two main methods: {@link #runWhenBound} and {@link #release()}.
- * {@code runWhenBound} submits a {@code receiver} to be invoked once the service is bound,
- * initiating a bind if necessary. {@code release} releases the binding if one exists.
- * <p>
- * Interestingly, invocations of receivers passed to {@code runWhenBound} and calls to
- * {@code release} will be executed in program order. I.e., a call to runWhenBound followed by
- * a call to release will result in the receiver passed to runWhenBound being invoked before the
- * release, even if the binder had to wait for the service to be bound.
- * <p>
- * It is legal to call runWhenBound after a call to release.
- *
- * @param <BoundService> the bound service interface associated with the binder.
- *
- */
-public abstract class ServiceBinder<BoundService> {
-  /**
-   * Interface for a work unit to be executed when the service is bound.
-   * @param <ServiceType> the bound service interface type
-   */
-  public interface BoundWork<ServiceType> {
-    /** Function called with the bound service once the service is bound. */
-    void run(ServiceType service);
-  }
-  /** Logger */
-  private static final Logger logger = AndroidLogger.forTag("InvServiceBinder");
-
-  /** Intent that can be used to bind to the service */
-  private final Intent serviceIntent;
-
-  /** Class that represents the bound service interface */
-  private final Class<BoundService> serviceClass;
-
-  /** Name of the component that implements the service interface. */
-  private final String componentClassName;
-
-  /** Work waiting to be run when the service becomes bound. */
-  private final Queue<BoundWork<BoundService>> pendingWork =
-      new LinkedList<BoundWork<BoundService>>();
-
-  /** Used to synchronize. */
-  private final Object lock = new Object();
-
-  /** Bound service instance held by the binder or {@code null} if not bound. */
-  private BoundService serviceInstance = null;
-
-  /** Context to use when binding and unbinding. */
-  private final Context context;
-
-  /** Whether bindService has been called. */
-  private boolean hasCalledBind = false;
-
-  /** Whether we are currently executing an event from the queue. */
-  private boolean queueHandlingInProgress = false;
-
-  /** Number of times {@link #startBind()} has been called, for tests. */
-  private int numStartBindForTest = 0;
-
-  /**
-   * Service connection implementation that handles connection/disconnection
-   * events for the binder.
-   */
-  private final ServiceConnection serviceConnection = new ServiceConnection() {
-
-    @Override
-    public void onServiceConnected(ComponentName serviceName, IBinder binder) {
-      logger.fine("onServiceConnected: %s", serviceName);
-      synchronized (lock) {
-        // Once the service is bound, save it and run any work that was waiting for it.
-        serviceInstance = asInterface(binder);
-        handleQueue();
-      }
-    }
-
-    @Override
-    public void onServiceDisconnected(ComponentName serviceName) {
-      logger.fine("onServiceDisconnected: %s", serviceClass);
-      synchronized (lock) {
-        serviceInstance = null;
-      }
-    }
-  };
-
-  /**
-   * Constructs a new ServiceBinder that uses the provided intent to bind to the service of the
-   * specific type. Subclasses should expose a public constructor that passes the appropriate intent
-   * and type into this constructor.
-   *
-   * @param context context to use for (un)binding.
-   * @param serviceIntent intent that can be used to connect to the bound service.
-   * @param serviceClass interface exposed by the bound service.
-   * @param componentClassName name of component implementing the bound service. If non-null, then
-   *        an explicit binding to the named component within the same class is guaranteed.
-   */
-  protected ServiceBinder(Context context, Intent serviceIntent, Class<BoundService> serviceClass,
-      String componentClassName) {
-    this.context = Preconditions.checkNotNull(context);
-    this.serviceIntent = Preconditions.checkNotNull(serviceIntent);
-    this.serviceClass = Preconditions.checkNotNull(serviceClass);
-    this.componentClassName = componentClassName;
-  }
-
-  /** Returns the intent used to bind to the service */
-  public Intent getIntent() {
-    Intent bindIntent;
-    if (componentClassName == null) {
-      return serviceIntent;
-    }
-    bindIntent = new Intent(serviceIntent);
-    bindIntent.setClassName(context, componentClassName);
-    return bindIntent;
-  }
-
-  /** Runs {@code receiver} when the service becomes bound. */
-  public void runWhenBound(BoundWork<BoundService> receiver) {
-    synchronized (lock) {
-      pendingWork.add(receiver);
-      handleQueue();
-    }
-  }
-
-  /** Unbinds the service associated with the binder. No-op if not bound. */
-  public void release() {
-    synchronized (lock) {
-      if (!hasCalledBind) {
-        logger.fine("Release is a no-op since not bound: %s", serviceClass);
-        return;
-      }
-      // We need to release using a runWhenBound to avoid having a release jump ahead of
-      // pending work waiting for a bind (i.e., to preserve program order).
-      runWhenBound(new BoundWork<BoundService>() {
-        @Override
-        public void run(BoundService ignored) {
-          synchronized (lock) {
-            // Do the unbind.
-            logger.fine("Unbinding %s from %s", serviceClass, serviceInstance);
-            try {
-              context.unbindService(serviceConnection);
-            } catch (IllegalArgumentException exception) {
-              logger.fine("Exception unbinding from %s: %s", serviceClass,
-                  exception.getMessage());
-            }
-            // Clear the now-stale reference and reset hasCalledBind so that we will initiate a
-            // bind on a subsequent call to runWhenBound.
-            serviceInstance = null;
-            hasCalledBind = false;
-
-            // This isn't necessarily wrong, but it's slightly odd.
-            if (!pendingWork.isEmpty()) {
-              logger.info("Still have %s work items in release of %s", pendingWork.size(),
-                  serviceClass);
-            }
-          }
-        }
-      });
-    }
-  }
-
-  /**
-   * Returns {@code true} if the service binder is currently connected to the
-   * bound service.
-   */
-  public boolean isBoundForTest() {
-    synchronized (lock) {
-      return hasCalledBind;
-    }
-  }
-
-  @Override
-  public String toString() {
-    synchronized (lock) {
-      return this.getClass().getSimpleName() + "[" + serviceIntent + "]";
-    }
-  }
-
-  /** Returns the number of times {@code startBind} has been called, for tests. */
-  public int getNumStartBindForTest() {
-    return numStartBindForTest;
-  }
-
-  /**
-   * Recursively process the queue of {@link #pendingWork}. Initiates a bind to the service if
-   * required. Else, if the service instance is available, removes the head of the queue and invokes
-   * it with the service instance.
-   * <p>
-   * Note: this function differs from {@link #runWhenBound} only in that {@code runWhenBound}
-   * enqueues into {@link #pendingWork}.
-   */
-  private void handleQueue() {
-    if (queueHandlingInProgress) {
-      // Someone called back into runWhenBound from receiver.accept. We don't want to start another
-      // recursive call, since we're already handling the queue.
-      return;
-    }
-    if (pendingWork.isEmpty()) {
-      // Recursive base case.
-      return;
-    }
-    if (!hasCalledBind) {
-      // Initiate a bind if not bound.
-      Preconditions.checkState(serviceInstance == null,
-          "Bind not called but service instance is set: %s", serviceClass);
-
-      // May fail, but does its own logging. If it fails, we will never dispatch the work in the
-      // queue, but it's unclear what we can do in this case other than log.
-      startBind();
-      return;
-    }
-    if (serviceInstance == null) {
-      // Wait for the service to become bound if it is not yet available and a bind is in progress.
-      Preconditions.checkState(hasCalledBind, "No service instance and not waiting for bind: %s",
-          serviceClass);
-      return;
-    }
-
-    // Service is bound and available. Remove and invoke the head of the queue, then recurse to
-    // process the rest. We recurse because the head of the queue may have been a release(), which
-    // would have unbound the service, and we would need to reinvoke the binding code.
-    BoundWork<BoundService> work = pendingWork.remove();
-    queueHandlingInProgress = true;
-    work.run(serviceInstance);
-    queueHandlingInProgress = false;
-    handleQueue();
-  }
-
-  /**
-   * Binds to the service associated with the binder within the provided context. Returns whether
-   * binding was successfully initiated.
-   */
-  private boolean startBind() {
-    Preconditions.checkState(!hasCalledBind, "Bind already called for %s", serviceClass);
-    ++numStartBindForTest;
-    Intent bindIntent = getIntent();
-    if (!context.bindService(bindIntent, serviceConnection, Context.BIND_AUTO_CREATE)) {
-      logger.severe("Unable to bind to service: %s", bindIntent);
-      return false;
-    }
-    hasCalledBind = true;
-    return true;
-  }
-
-  /** Returns a bound service stub of the expected type. */
-  protected abstract BoundService asInterface(IBinder binder);
-}
diff --git a/java/com/google/ipc/invalidation/external/client/android2/AndroidClientFactory.java b/java/com/google/ipc/invalidation/external/client/android2/AndroidClientFactory.java
index d4cd3d8..82c53d9 100644
--- a/java/com/google/ipc/invalidation/external/client/android2/AndroidClientFactory.java
+++ b/java/com/google/ipc/invalidation/external/client/android2/AndroidClientFactory.java
@@ -18,8 +18,8 @@
 import com.google.ipc.invalidation.ticl.InvalidationClientCore;
 import com.google.ipc.invalidation.ticl.android2.AndroidTiclManifest;
 import com.google.ipc.invalidation.ticl.android2.ProtocolIntents;
-import com.google.protos.ipc.invalidation.ClientProtocol.ClientConfigP;
-import com.google.protos.ipc.invalidation.Types.ClientType;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.ClientConfigP;
+import com.google.ipc.invalidation.util.Bytes;
 
 import android.content.Context;
 import android.content.Intent;
@@ -39,10 +39,10 @@
    * @param clientType type of the client to create
    * @param clientName name of the client to create
    */
-  public static void createClient(Context context, ClientType.Type clientType, byte[] clientName) {
-    ClientConfigP config = InvalidationClientCore.createConfig().build();
+  public static void createClient(Context context, int clientType, byte[] clientName) {
+    ClientConfigP config = InvalidationClientCore.createConfig();
     Intent intent = ProtocolIntents.InternalDowncalls.newCreateClientIntent(
-        clientType.getNumber(), clientName, config, false);
+        clientType, Bytes.fromByteArray(clientName), config, false);
     intent.setClassName(context, new AndroidTiclManifest(context).getTiclServiceClass());
     context.startService(intent);
   }
diff --git a/java/com/google/ipc/invalidation/external/client/contrib/AndroidListener.java b/java/com/google/ipc/invalidation/external/client/contrib/AndroidListener.java
index 127d6ec..aad35b9 100644
--- a/java/com/google/ipc/invalidation/external/client/contrib/AndroidListener.java
+++ b/java/com/google/ipc/invalidation/external/client/contrib/AndroidListener.java
@@ -26,19 +26,21 @@
 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.ProtoConverter;
+import com.google.ipc.invalidation.ticl.InvalidationClientCore;
+import com.google.ipc.invalidation.ticl.ProtoWrapperConverter;
 import com.google.ipc.invalidation.ticl.android2.AndroidClock;
 import com.google.ipc.invalidation.ticl.android2.AndroidInvalidationListenerIntentMapper;
 import com.google.ipc.invalidation.ticl.android2.ProtocolIntents;
 import com.google.ipc.invalidation.ticl.android2.channel.AndroidChannelConstants.AuthTokenConstants;
-import com.google.protobuf.InvalidProtocolBufferException;
-import com.google.protos.ipc.invalidation.AndroidListenerProtocol;
-import com.google.protos.ipc.invalidation.AndroidListenerProtocol.RegistrationCommand;
-import com.google.protos.ipc.invalidation.AndroidListenerProtocol.StartCommand;
-import com.google.protos.ipc.invalidation.ClientProtocol.ClientConfigP;
-import com.google.protos.ipc.invalidation.ClientProtocol.InvalidationMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.InvalidationP;
-import com.google.protos.ipc.invalidation.ClientProtocol.ObjectIdP;
+import com.google.ipc.invalidation.ticl.proto.AndroidListenerProtocol;
+import com.google.ipc.invalidation.ticl.proto.AndroidListenerProtocol.RegistrationCommand;
+import com.google.ipc.invalidation.ticl.proto.AndroidListenerProtocol.StartCommand;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.ClientConfigP;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationMessage;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationP;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP;
+import com.google.ipc.invalidation.util.Bytes;
+import com.google.ipc.invalidation.util.ProtoWrapper.ValidationException;
 
 import android.app.IntentService;
 import android.app.PendingIntent;
@@ -126,7 +128,7 @@
 
   /** The last client ID passed to the ready up-call. */
   
-  static byte[] lastClientIdForTest;
+  static Bytes lastClientIdForTest;
 
   /**
    * Invalidation listener implementation. We implement the interface on a private field rather
@@ -136,30 +138,30 @@
   private final InvalidationListener invalidationListener = new InvalidationListener() {
     @Override
     public final void ready(final InvalidationClient client) {
-      byte[] clientId = state.getClientId().toByteArray();
+      Bytes clientId = state.getClientId();
       AndroidListener.lastClientIdForTest = clientId;
-      AndroidListener.this.ready(clientId);
+      AndroidListener.this.ready(clientId.getByteArray());
     }
 
     @Override
     public final void reissueRegistrations(final InvalidationClient client, byte[] prefix,
         int prefixLength) {
-      AndroidListener.this.reissueRegistrations(state.getClientId().toByteArray());
+      AndroidListener.this.reissueRegistrations(state.getClientId().getByteArray());
     }
 
     @Override
     public final void informRegistrationStatus(final InvalidationClient client,
         final ObjectId objectId, final RegistrationState regState) {
       state.informRegistrationSuccess(objectId);
-      AndroidListener.this.informRegistrationStatus(state.getClientId().toByteArray(),
-          objectId, regState);
+      AndroidListener.this.informRegistrationStatus(state.getClientId().getByteArray(), objectId,
+          regState);
     }
 
     @Override
     public final void informRegistrationFailure(final InvalidationClient client,
         final ObjectId objectId, final boolean isTransient, final String errorMessage) {
       state.informRegistrationFailure(objectId, isTransient);
-      AndroidListener.this.informRegistrationFailure(state.getClientId().toByteArray(), objectId,
+      AndroidListener.this.informRegistrationFailure(state.getClientId().getByteArray(), objectId,
           isTransient, errorMessage);
     }
 
@@ -217,7 +219,7 @@
     Preconditions.checkNotNull(config.clientName);
 
     return AndroidListenerIntents.createStartIntent(context, config.clientType,
-        config.clientName, config.allowSuppression);
+        Bytes.fromByteArray(config.clientName), config.allowSuppression);
   }
 
   /** See specs for {@link InvalidationClient#start}. */
@@ -226,8 +228,8 @@
     Preconditions.checkNotNull(clientName);
 
     final boolean allowSuppression = true;
-    return AndroidListenerIntents.createStartIntent(context, clientType, clientName,
-        allowSuppression);
+    return AndroidListenerIntents.createStartIntent(context, clientType,
+        Bytes.fromByteArray(clientName), allowSuppression);
   }
 
   /** See specs for {@link InvalidationClient#stop}. */
@@ -251,8 +253,8 @@
     Preconditions.checkNotNull(objectIds);
 
     final boolean isRegister = true;
-    return AndroidListenerIntents.createRegistrationIntent(context, clientId, objectIds,
-        isRegister);
+    return AndroidListenerIntents.createRegistrationIntent(context, Bytes.fromByteArray(clientId),
+        objectIds, isRegister);
   }
 
   /**
@@ -283,8 +285,8 @@
     Preconditions.checkNotNull(objectIds);
 
     final boolean isRegister = false;
-    return AndroidListenerIntents.createRegistrationIntent(context, clientId, objectIds,
-        isRegister);
+    return AndroidListenerIntents.createRegistrationIntent(context, Bytes.fromByteArray(clientId),
+        objectIds, isRegister);
   }
 
   /**
@@ -499,7 +501,7 @@
         }
         return state;
       }
-    } catch (InvalidProtocolBufferException exception) {
+    } catch (ValidationException exception) {
       logger.warning("Failed to parse listener state: %s", exception);
     }
     return null;
@@ -552,13 +554,13 @@
     // Make sure the registration is intended for this client. If not, we ignore it (suggests
     // there is a new client now).
     if (!command.getClientId().equals(state.getClientId())) {
-      logger.warning("Ignoring registration request for old client. Old ID = {0}, New ID = {1}",
+      logger.warning("Ignoring registration request for old client. Old ID = %s, New ID = %s",
           command.getClientId(), state.getClientId());
       return true;
     }
     boolean isRegister = command.getIsRegister();
-    for (ObjectIdP objectIdP : command.getObjectIdList()) {
-      ObjectId objectId = ProtoConverter.convertFromObjectIdProto(objectIdP);
+    for (ObjectIdP objectIdP : command.getObjectId()) {
+      ObjectId objectId = ProtoWrapperConverter.convertFromObjectIdProto(objectIdP);
       // We may need to delay the registration command (if it is not already delayed).
       int delayMs = 0;
       if (!command.getIsDelayed()) {
@@ -607,12 +609,14 @@
     // messages directed at the wrong instance.
     state = new AndroidListenerState(initialMaxDelayMs, maxDelayFactor);
     boolean skipStartForTest = false;
-    ClientConfigP clientConfig = command.getAllowSuppression() ?
-        ClientConfigP.getDefaultInstance() :
-            ClientConfigP.newBuilder().setAllowSuppression(false).build();
+    ClientConfigP clientConfig = InvalidationClientCore.createConfig();
+    if (command.getAllowSuppression() != clientConfig.getAllowSuppression()) {
+      ClientConfigP.Builder clientConfigBuilder = clientConfig.toBuilder();
+      clientConfigBuilder.allowSuppression = command.getAllowSuppression();
+      clientConfig = clientConfigBuilder.build();
+    }
     Intent startIntent = ProtocolIntents.InternalDowncalls.newCreateClientIntent(
-        command.getClientType(), command.getClientName().toByteArray(),
-        clientConfig, skipStartForTest);
+        command.getClientType(), command.getClientName(), clientConfig, skipStartForTest);
     AndroidListenerIntents.issueTiclIntent(getApplicationContext(), startIntent);
     return true;
   }
@@ -639,11 +643,11 @@
     try {
       InvalidationMessage invalidationMessage = InvalidationMessage.parseFrom(data);
       List<Invalidation> invalidations = new ArrayList<Invalidation>();
-      for (InvalidationP invalidation : invalidationMessage.getInvalidationList()) {
-        invalidations.add(ProtoConverter.convertFromInvalidationProto(invalidation));
+      for (InvalidationP invalidation : invalidationMessage.getInvalidation()) {
+        invalidations.add(ProtoWrapperConverter.convertFromInvalidationProto(invalidation));
       }
       backgroundInvalidateForInternalUse(invalidations);
-    } catch (InvalidProtocolBufferException exception) {
+    } catch (ValidationException exception) {
       logger.info("Failed to parse background invalidation intent payload: %s",
           exception.getMessage());
     }
diff --git a/java/com/google/ipc/invalidation/external/client/contrib/AndroidListenerIntents.java b/java/com/google/ipc/invalidation/external/client/contrib/AndroidListenerIntents.java
index 37d0d6d..d799ef6 100644
--- a/java/com/google/ipc/invalidation/external/client/contrib/AndroidListenerIntents.java
+++ b/java/com/google/ipc/invalidation/external/client/contrib/AndroidListenerIntents.java
@@ -22,10 +22,10 @@
 import com.google.ipc.invalidation.ticl.android2.AndroidClock;
 import com.google.ipc.invalidation.ticl.android2.AndroidTiclManifest;
 import com.google.ipc.invalidation.ticl.android2.channel.AndroidChannelConstants.AuthTokenConstants;
-import com.google.protobuf.ByteString;
-import com.google.protobuf.InvalidProtocolBufferException;
-import com.google.protos.ipc.invalidation.AndroidListenerProtocol.RegistrationCommand;
-import com.google.protos.ipc.invalidation.AndroidListenerProtocol.StartCommand;
+import com.google.ipc.invalidation.ticl.proto.AndroidListenerProtocol.RegistrationCommand;
+import com.google.ipc.invalidation.ticl.proto.AndroidListenerProtocol.StartCommand;
+import com.google.ipc.invalidation.util.Bytes;
+import com.google.ipc.invalidation.util.ProtoWrapper.ValidationException;
 
 import android.app.AlarmManager;
 import android.app.PendingIntent;
@@ -98,7 +98,7 @@
     // Attempt to parse the extra.
     try {
       return RegistrationCommand.parseFrom(data);
-    } catch (InvalidProtocolBufferException exception) {
+    } catch (ValidationException exception) {
       logger.warning("Received invalid proto: %s", exception);
       return null;
     }
@@ -118,7 +118,7 @@
     // Attempt to parse the extra.
     try {
       return StartCommand.parseFrom(data);
-    } catch (InvalidProtocolBufferException exception) {
+    } catch (ValidationException exception) {
       logger.warning("Received invalid proto: %s", exception);
       return null;
     }
@@ -131,7 +131,7 @@
 
   /** Issues a registration retry with delay. */
   static void issueDelayedRegistrationIntent(Context context, AndroidClock clock,
-      ByteString clientId, ObjectId objectId, boolean isRegister, int delayMs, int requestCode) {
+      Bytes clientId, ObjectId objectId, boolean isRegister, int delayMs, int requestCode) {
     RegistrationCommand command = isRegister ?
         AndroidListenerProtos.newDelayedRegisterCommand(clientId, objectId) :
             AndroidListenerProtos.newDelayedUnregisterCommand(clientId, objectId);
@@ -150,12 +150,12 @@
   }
 
   /** Creates a 'start-client' intent. */
-  static Intent createStartIntent(Context context, int clientType, byte[] clientName,
+  static Intent createStartIntent(Context context, int clientType, Bytes clientName,
       boolean allowSuppression) {
     Intent intent = new Intent();
     // Create proto for the start command.
-    StartCommand command = AndroidListenerProtos.newStartCommand(clientType,
-        ByteString.copyFrom(clientName), allowSuppression);
+    StartCommand command =
+        AndroidListenerProtos.newStartCommand(clientType, clientName, allowSuppression);
     intent.putExtra(EXTRA_START, command.toByteArray());
     return setAndroidListenerClass(context, intent);
   }
@@ -177,13 +177,12 @@
   }
 
   /** Constructs an intent with {@link RegistrationCommand} proto. */
-  static Intent createRegistrationIntent(Context context, byte[] clientId,
+  static Intent createRegistrationIntent(Context context, Bytes clientId,
       Iterable<ObjectId> objectIds, boolean isRegister) {
     // Registration intent has an extra containing the RegistrationCommand proto.
     Intent intent = new Intent();
-    RegistrationCommand command = isRegister
-        ? AndroidListenerProtos.newRegisterCommand(ByteString.copyFrom(clientId), objectIds)
-            : AndroidListenerProtos.newUnregisterCommand(ByteString.copyFrom(clientId), objectIds);
+    RegistrationCommand command =
+        AndroidListenerProtos.newRegistrationCommand(clientId, objectIds, isRegister);
     intent.putExtra(EXTRA_REGISTRATION, command.toByteArray());
     return setAndroidListenerClass(context, intent);
   }
diff --git a/java/com/google/ipc/invalidation/external/client/contrib/AndroidListenerProtos.java b/java/com/google/ipc/invalidation/external/client/contrib/AndroidListenerProtos.java
index fb0fe05..c5b077e 100644
--- a/java/com/google/ipc/invalidation/external/client/contrib/AndroidListenerProtos.java
+++ b/java/com/google/ipc/invalidation/external/client/contrib/AndroidListenerProtos.java
@@ -15,16 +15,19 @@
  */
 package com.google.ipc.invalidation.external.client.contrib;
 
-import com.google.common.base.Preconditions;
 import com.google.ipc.invalidation.external.client.types.ObjectId;
-import com.google.ipc.invalidation.ticl.ProtoConverter;
+import com.google.ipc.invalidation.ticl.ProtoWrapperConverter;
 import com.google.ipc.invalidation.ticl.TiclExponentialBackoffDelayGenerator;
-import com.google.protobuf.ByteString;
-import com.google.protos.ipc.invalidation.AndroidListenerProtocol.AndroidListenerState;
-import com.google.protos.ipc.invalidation.AndroidListenerProtocol.AndroidListenerState.RetryRegistrationState;
-import com.google.protos.ipc.invalidation.AndroidListenerProtocol.RegistrationCommand;
-import com.google.protos.ipc.invalidation.AndroidListenerProtocol.StartCommand;
+import com.google.ipc.invalidation.ticl.proto.AndroidListenerProtocol.AndroidListenerState;
+import com.google.ipc.invalidation.ticl.proto.AndroidListenerProtocol.AndroidListenerState.RetryRegistrationState;
+import com.google.ipc.invalidation.ticl.proto.AndroidListenerProtocol.RegistrationCommand;
+import com.google.ipc.invalidation.ticl.proto.AndroidListenerProtocol.StartCommand;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP;
+import com.google.ipc.invalidation.util.Bytes;
 
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 
@@ -34,55 +37,38 @@
  */
 class AndroidListenerProtos {
 
-  /** Creates a register command for the given objects and client. */
-  static RegistrationCommand newRegisterCommand(ByteString clientId, Iterable<ObjectId> objectIds) {
-    final boolean isRegister = true;
-    return newRegistrationCommand(clientId, objectIds, isRegister);
-  }
-
-  /** Creates an unregister command for the given objects and client. */
-  static RegistrationCommand newUnregisterCommand(ByteString clientId,
-      Iterable<ObjectId> objectIds) {
-    final boolean isRegister = false;
-    return newRegistrationCommand(clientId, objectIds, isRegister);
-  }
-
   /** Creates a retry register command for the given object and client. */
-  static RegistrationCommand newDelayedRegisterCommand(ByteString clientId, ObjectId objectId) {
+  static RegistrationCommand newDelayedRegisterCommand(Bytes clientId, ObjectId objectId) {
     final boolean isRegister = true;
     return newDelayedRegistrationCommand(clientId, objectId, isRegister);
   }
 
   /** Creates a retry unregister command for the given object and client. */
-  static RegistrationCommand newDelayedUnregisterCommand(ByteString clientId, ObjectId objectId) {
+  static RegistrationCommand newDelayedUnregisterCommand(Bytes clientId, ObjectId objectId) {
     final boolean isRegister = false;
     return newDelayedRegistrationCommand(clientId, objectId, isRegister);
   }
 
   /** Creates proto for {@link AndroidListener} state. */
-  static AndroidListenerState newAndroidListenerState(ByteString clientId, int requestCodeSeqNum,
+  static AndroidListenerState newAndroidListenerState(Bytes clientId, int requestCodeSeqNum,
       Map<ObjectId, TiclExponentialBackoffDelayGenerator> delayGenerators,
-      Iterable<ObjectId> desiredRegistrations) {
-    AndroidListenerState.Builder builder = AndroidListenerState.newBuilder()
-        .setClientId(clientId)
-        .setRequestCodeSeqNum(requestCodeSeqNum);
-    for (ObjectId objectId : desiredRegistrations) {
-      builder.addRegistration(ProtoConverter.convertToObjectIdProto(objectId));
-    }
+      Collection<ObjectId> desiredRegistrations) {
+    ArrayList<RetryRegistrationState> retryRegistrationState =
+        new ArrayList<RetryRegistrationState>(delayGenerators.size());
     for (Entry<ObjectId, TiclExponentialBackoffDelayGenerator> entry : delayGenerators.entrySet()) {
-      builder.addRetryRegistrationState(
+      retryRegistrationState.add(
           newRetryRegistrationState(entry.getKey(), entry.getValue()));
     }
-    return builder.build();
+    return AndroidListenerState.create(
+        ProtoWrapperConverter.convertToObjectIdProtoCollection(desiredRegistrations),
+        retryRegistrationState, clientId, requestCodeSeqNum);
   }
 
   /** Creates proto for retry registration state. */
   static RetryRegistrationState newRetryRegistrationState(ObjectId objectId,
       TiclExponentialBackoffDelayGenerator delayGenerator) {
-    return RetryRegistrationState.newBuilder()
-        .setObjectId(ProtoConverter.convertToObjectIdProto(objectId))
-        .setExponentialBackoffState(delayGenerator.marshal())
-        .build();
+    return RetryRegistrationState.create(ProtoWrapperConverter.convertToObjectIdProto(objectId),
+        delayGenerator.marshal());
   }
 
   /** Returns {@code true} iff the given proto is valid. */
@@ -101,36 +87,23 @@
   }
 
   /** Creates start command proto. */
-  static StartCommand newStartCommand(int clientType, ByteString clientName,
+  static StartCommand newStartCommand(int clientType, Bytes clientName,
       boolean allowSuppression) {
-    return StartCommand.newBuilder()
-        .setClientType(clientType)
-        .setClientName(clientName)
-        .setAllowSuppression(allowSuppression)
-        .build();
+    return StartCommand.create(clientType, clientName, allowSuppression);
   }
 
-  private static RegistrationCommand newRegistrationCommand(ByteString clientId,
+  static RegistrationCommand newRegistrationCommand(Bytes clientId,
       Iterable<ObjectId> objectIds, boolean isRegister) {
-    RegistrationCommand.Builder builder = RegistrationCommand.newBuilder()
-        .setIsRegister(isRegister)
-        .setClientId(clientId)
-        .setIsDelayed(false);
-    for (ObjectId objectId : objectIds) {
-      Preconditions.checkNotNull(objectId);
-      builder.addObjectId(ProtoConverter.convertToObjectIdProto(objectId));
-    }
-    return builder.build();
+    return RegistrationCommand.create(isRegister,
+        ProtoWrapperConverter.convertToObjectIdProtoCollection(objectIds), clientId,
+        /* isDelayed */ false);
   }
 
-  private static RegistrationCommand newDelayedRegistrationCommand(ByteString clientId,
+  private static RegistrationCommand newDelayedRegistrationCommand(Bytes clientId,
       ObjectId objectId, boolean isRegister) {
-    return RegistrationCommand.newBuilder()
-        .setIsRegister(isRegister)
-        .addObjectId(ProtoConverter.convertToObjectIdProto(objectId))
-        .setClientId(clientId)
-        .setIsDelayed(true)
-        .build();
+    List<ObjectIdP> objectIds = new ArrayList<ObjectIdP>(1);
+    objectIds.add(ProtoWrapperConverter.convertToObjectIdProto(objectId));
+    return RegistrationCommand.create(isRegister, objectIds, clientId, /* isDelayed */ true);
   }
 
   // Prevent instantiation.
diff --git a/java/com/google/ipc/invalidation/external/client/contrib/AndroidListenerState.java b/java/com/google/ipc/invalidation/external/client/contrib/AndroidListenerState.java
index 026b5ef..35f59d9 100644
--- a/java/com/google/ipc/invalidation/external/client/contrib/AndroidListenerState.java
+++ b/java/com/google/ipc/invalidation/external/client/contrib/AndroidListenerState.java
@@ -16,15 +16,15 @@
 package com.google.ipc.invalidation.external.client.contrib;
 
 import com.google.ipc.invalidation.external.client.types.ObjectId;
-import com.google.ipc.invalidation.ticl.ProtoConverter;
+import com.google.ipc.invalidation.ticl.ProtoWrapperConverter;
 import com.google.ipc.invalidation.ticl.TiclExponentialBackoffDelayGenerator;
+import com.google.ipc.invalidation.ticl.proto.AndroidListenerProtocol;
+import com.google.ipc.invalidation.ticl.proto.AndroidListenerProtocol.AndroidListenerState.RetryRegistrationState;
+import com.google.ipc.invalidation.ticl.proto.Client.ExponentialBackoffState;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP;
 import com.google.ipc.invalidation.util.Bytes;
 import com.google.ipc.invalidation.util.Marshallable;
 import com.google.ipc.invalidation.util.TypedUtil;
-import com.google.protobuf.ByteString;
-import com.google.protos.ipc.invalidation.AndroidListenerProtocol;
-import com.google.protos.ipc.invalidation.AndroidListenerProtocol.AndroidListenerState.RetryRegistrationState;
-import com.google.protos.ipc.invalidation.ClientProtocol.ObjectIdP;
 
 import java.nio.ByteBuffer;
 import java.util.HashMap;
@@ -90,7 +90,7 @@
    * The identifier for the current client. The ID is randomly generated and is used to ensure that
    * messages are not handled by the wrong client instance.
    */
-  private final ByteString clientId;
+  private final Bytes clientId;
 
   /** Initializes state for a new client. */
   AndroidListenerState(int initialMaxDelayMs, int maxDelayFactor) {
@@ -108,11 +108,15 @@
   AndroidListenerState(int initialMaxDelayMs, int maxDelayFactor,
       AndroidListenerProtocol.AndroidListenerState state) {
     desiredRegistrations = new HashSet<ObjectId>();
-    for (ObjectIdP objectIdProto : state.getRegistrationList()) {
-      desiredRegistrations.add(ProtoConverter.convertFromObjectIdProto(objectIdProto));
+    for (ObjectIdP objectIdProto : state.getRegistration()) {
+      desiredRegistrations.add(ProtoWrapperConverter.convertFromObjectIdProto(objectIdProto));
     }
-    for (RetryRegistrationState retryState : state.getRetryRegistrationStateList()) {
-      ObjectId objectId = ProtoConverter.convertFromObjectIdProto(retryState.getObjectId());
+    for (RetryRegistrationState retryState : state.getRetryRegistrationState()) {
+      ObjectIdP objectIdP = retryState.getNullableObjectId();
+      if (objectIdP == null) {
+        continue;
+      }
+      ObjectId objectId = ProtoWrapperConverter.convertFromObjectIdProto(objectIdP);
       delayGenerators.put(objectId, new TiclExponentialBackoffDelayGenerator(random,
           initialMaxDelayMs, maxDelayFactor, retryState.getExponentialBackoffState()));
     }
@@ -214,7 +218,7 @@
    * Gets the identifier for the current client. Used to determine if registrations commands are
    * relevant to this instance.
    */
-  ByteString getClientId() {
+  Bytes getClientId() {
     return clientId;
   }
 
@@ -253,12 +257,12 @@
 
     AndroidListenerState that = (AndroidListenerState) object;
 
-    return (this.isDirty == that.isDirty) &&
-        (this.requestCodeSeqNum == that.requestCodeSeqNum) &&
-        (this.desiredRegistrations.size() == that.desiredRegistrations.size()) &&
-        (this.desiredRegistrations.containsAll(that.desiredRegistrations)) &&
-        (this.clientId.equals(that.clientId)) &&
-        equals(this.delayGenerators, that.delayGenerators);
+    return (this.isDirty == that.isDirty)
+        && (this.requestCodeSeqNum == that.requestCodeSeqNum)
+        && (this.desiredRegistrations.size() == that.desiredRegistrations.size())
+        && (this.desiredRegistrations.containsAll(that.desiredRegistrations))
+        && TypedUtil.<Bytes>equals(this.clientId, that.clientId)
+        && equals(this.delayGenerators, that.delayGenerators);
   }
 
   /** Compares the contents of two {@link #delayGenerators} maps. */
@@ -269,8 +273,8 @@
     }
     for (Entry<ObjectId, TiclExponentialBackoffDelayGenerator> xEntry : x.entrySet()) {
       TiclExponentialBackoffDelayGenerator yGenerator = y.get(xEntry.getKey());
-      if ((yGenerator == null) || !xEntry.getValue().marshal().toByteString().equals(
-          yGenerator.marshal().toByteString())) {
+      if ((yGenerator == null) || !TypedUtil.<ExponentialBackoffState>equals(
+          xEntry.getValue().marshal(), yGenerator.marshal())) {
         return false;
       }
     }
@@ -281,20 +285,19 @@
   public String toString() {
     return String.format("AndroidListenerState[%s]: isDirty = %b, " +
         "desiredRegistrations.size() = %d, delayGenerators.size() = %d, requestCodeSeqNum = %d",
-        Bytes.toString(clientId), isDirty, desiredRegistrations.size(), delayGenerators.size(),
-        requestCodeSeqNum);
+        clientId, isDirty, desiredRegistrations.size(), delayGenerators.size(), requestCodeSeqNum);
   }
 
   /**
    * Constructs a new globally unique ID for the client. Can be used to determine if commands
    * originated from this instance of the listener.
    */
-  private static ByteString createGloballyUniqueClientId() {
+  private static Bytes createGloballyUniqueClientId() {
     UUID guid = UUID.randomUUID();
     byte[] bytes = new byte[16];
     ByteBuffer buffer = ByteBuffer.wrap(bytes);
     buffer.putLong(guid.getLeastSignificantBits());
     buffer.putLong(guid.getMostSignificantBits());
-    return ByteString.copyFrom(bytes);
+    return new Bytes(bytes);
   }
 }
diff --git a/java/com/google/ipc/invalidation/external/client/contrib/MultiplexingGcmListener.java b/java/com/google/ipc/invalidation/external/client/contrib/MultiplexingGcmListener.java
index 927ea59..6a0645f 100644
--- a/java/com/google/ipc/invalidation/external/client/contrib/MultiplexingGcmListener.java
+++ b/java/com/google/ipc/invalidation/external/client/contrib/MultiplexingGcmListener.java
@@ -21,7 +21,7 @@
 import com.google.android.gcm.GCMRegistrar;
 import com.google.ipc.invalidation.external.client.SystemResources.Logger;
 import com.google.ipc.invalidation.external.client.android.service.AndroidLogger;
-import com.google.ipc.invalidation.ticl.android.c2dm.WakeLockManager;
+import com.google.ipc.invalidation.ticl.android2.WakeLockManager;
 
 import android.app.IntentService;
 import android.content.BroadcastReceiver;
@@ -332,7 +332,7 @@
     GCMRegistrar.checkDevice(context);
     GCMRegistrar.checkManifest(context);
     final String regId = GCMRegistrar.getRegistrationId(context);
-    if (regId.equals("")) {
+    if (regId.isEmpty()) {
       GCMRegistrar.register(context, readSenderIdsFromManifestOrDie(context));
     }
     return regId;
diff --git a/java/com/google/ipc/invalidation/testing/android/InvalidationTest.aidl b/java/com/google/ipc/invalidation/testing/android/InvalidationTest.aidl
deleted file mode 100644
index fb5ab29..0000000
--- a/java/com/google/ipc/invalidation/testing/android/InvalidationTest.aidl
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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.testing.android;
-
-import android.os.Bundle;
-
-interface InvalidationTest {
-
-  /**
-   * Used to set whether the invalidation test service should store incoming
-   * actions and outgoing events respectively by {@link getActionEvents()}
-   * and {@link getEventIntents()}.  If {@code false}, they will be processed
-   * and forgotten.
-   */
-  void setCapture(boolean captureActions, boolean captureEvents);
-
-  /**
-   * Returns an array of bundle containing the set of invalidation requests
-   * received by the test service since the last call to this method.
-   */
-  Bundle [] getRequests();
-
-  /**
-   * Returns an array of intents containing the set of invalidation event
-   * bundles sent by the test service since the last call to this method.
-   */
-  Bundle [] getEvents();
-
-  /**
-   * Instructs the test service to send an event back to the client to support
-   * testing of listener functionality.
-   */
-  void sendEvent(in Bundle eventBundle);
-  
-  /**
-   * Reset all state for the invalidation test service.  This will clear all
-   * current clients and drop and disable any captured action or event bundles.
-   */
-  void reset();
-}
diff --git a/java/com/google/ipc/invalidation/testing/android/InvalidationTestListener.java b/java/com/google/ipc/invalidation/testing/android/InvalidationTestListener.java
deleted file mode 100644
index 8a684d7..0000000
--- a/java/com/google/ipc/invalidation/testing/android/InvalidationTestListener.java
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * 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.testing.android;
-
-import com.google.ipc.invalidation.external.client.InvalidationClient;
-import com.google.ipc.invalidation.external.client.InvalidationListener;
-import com.google.ipc.invalidation.external.client.SystemResources.Logger;
-import com.google.ipc.invalidation.external.client.android.AndroidInvalidationClient;
-import com.google.ipc.invalidation.external.client.android.AndroidInvalidationListener;
-import com.google.ipc.invalidation.external.client.android.service.AndroidLogger;
-import com.google.ipc.invalidation.external.client.android.service.Event;
-import com.google.ipc.invalidation.external.client.android.service.Response;
-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 android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * TestListener service maintains a mapping of listeners by client key and forwards received events
- * to an InvalidationListener instance.   The listener should be registered in
- * {@code Android-Manifest.xml} as follows:
- *
- * {@code
- * <service
- *   android:name="com.google.ipc.invalidation.testing.android.InvalidationTestListener">
- *  <intent-filter>
- *     <action android:name="com.google.ipc.invalidation.EVENTS"/>
- *  </intent-filter>
- * </service>
- * }
- *
- */
-public class InvalidationTestListener extends AndroidInvalidationListener {
-
-  /** Logger */
-  private static final Logger logger = AndroidLogger.forTag("InvTestListener");
-
-  private static final Map<String, InvalidationListener> listenerMap =
-      new ConcurrentHashMap<String, InvalidationListener>();
-
-  /**
-   * Creates and returns an intent that is valid for use in creating a new invalidation client
-   * that will deliver events to the test listener.
-   */
-  public static Intent getEventIntent(Context context) {
-    Intent eventIntent = new Intent(Event.LISTENER_INTENT);
-    ComponentName component = new ComponentName(context.getPackageName(),
-        InvalidationTestListener.class.getName());
-    eventIntent.setComponent(component);
-    return eventIntent;
-  }
-
-  /**
-   * Sets the invalidation listener delegate to receive events for a given clientKey.
-   */
-  public static void setInvalidationListener(String clientKey, InvalidationListener listener) {
-    logger.fine("setListener %s for %s", listener, clientKey);
-    listenerMap.put(clientKey, listener);
-  }
-
-  /**
-   * Removes the invalidation listener delegate to receive events for a given clientKey.
-   */
-  public static void removeInvalidationListener(String clientKey) {
-    listenerMap.remove(clientKey);
-  }
-
-
-  @Override
-  protected void handleEvent(Bundle input, Bundle output) {
-
-    // Ignore events that target a client key where there is no listener registered
-    // It's likely that these are late-delivered events for an earlier test case.
-    Event event = new Event(input);
-    String clientKey = event.getClientKey();
-    if (!listenerMap.containsKey(clientKey)) {
-      logger.fine("Ignoring %s event to %s", event.getAction(), clientKey);
-      Response.Builder response = Response.newBuilder(event.getActionOrdinal(), output);
-      response.setStatus(Response.Status.SUCCESS);
-      return;
-    }
-
-    super.handleEvent(input, output);
-  }
-
-  @Override
-  public void ready(InvalidationClient client) {
-    InvalidationListener listener = getListener(client);
-    logger.fine("Received READY for %s: %s", getClientKey(client), listener);
-    if (listener != null) {
-      listener.ready(client);
-    }
-  }
-
-  @Override
-  public void invalidate(
-      InvalidationClient client, Invalidation invalidation, AckHandle ackHandle) {
-    InvalidationListener listener = getListener(client);
-    logger.fine("Received INVALIDATE for %s: %s", getClientKey(client), listener);
-    if (listener != null) {
-      listener.invalidate(client, invalidation, ackHandle);
-    }
-  }
-
-  @Override
-  public void invalidateUnknownVersion(
-      InvalidationClient client, ObjectId objectId, AckHandle ackHandle) {
-    InvalidationListener listener = getListener(client);
-    logger.fine("Received INVALIDATE_UNKNOWN_VERSION for %s: %s", getClientKey(client), listener);
-    if (listener != null) {
-      listener.invalidateUnknownVersion(client, objectId, ackHandle);
-    }
-  }
-
-  @Override
-  public void invalidateAll(InvalidationClient client, AckHandle ackHandle) {
-    InvalidationListener listener = getListener(client);
-    logger.fine("Received INVALIDATE_ALL for %s: %s", getClientKey(client), listener);
-    if (listener != null) {
-      listener.invalidateAll(client, ackHandle);
-    }
-  }
-
-  @Override
-  public void informRegistrationStatus(
-      InvalidationClient client, ObjectId objectId, RegistrationState regState) {
-    InvalidationListener listener = getListener(client);
-    logger.fine("Received INFORM_REGISTRATION_STATUS for %s: %s", getClientKey(client), listener);
-    if (listener != null) {
-      listener.informRegistrationStatus(client, objectId, regState);
-    }
-  }
-
-  @Override
-  public void informRegistrationFailure(
-      InvalidationClient client, ObjectId objectId, boolean isTransient, String errorMessage) {
-    InvalidationListener listener = getListener(client);
-    logger.fine("Received INFORM_REGISTRATION_FAILURE for %s: %s", getClientKey(client), listener);
-    if (listener != null) {
-      listener.informRegistrationFailure(client, objectId, isTransient, errorMessage);
-    }
-  }
-
-  @Override
-  public void reissueRegistrations(InvalidationClient client, byte[] prefix, int prefixLength) {
-    InvalidationListener listener = getListener(client);
-    logger.fine("Received REISSUE_REGISTRATIONS for %s: %s", getClientKey(client), listener);
-    if (listener != null) {
-      listener.reissueRegistrations(client, prefix, prefixLength);
-    }
-  }
-
-  @Override
-  public void informError(InvalidationClient client, ErrorInfo errorInfo) {
-    InvalidationListener listener = getListener(client);
-    logger.fine("Received INFORM_ERROR for %s: %s", getClientKey(client), listener);
-    if (listener != null) {
-      listener.informError(client, errorInfo);
-    }
-  }
-
-  private String getClientKey(InvalidationClient client) {
-    return ((AndroidInvalidationClient) client).getClientKey();
-  }
-
-  private InvalidationListener getListener(InvalidationClient client) {
-    String clientKey = getClientKey(client);
-    return listenerMap.get(clientKey);
-  }
-}
diff --git a/java/com/google/ipc/invalidation/testing/android/InvalidationTestService.java b/java/com/google/ipc/invalidation/testing/android/InvalidationTestService.java
deleted file mode 100644
index 9335b38..0000000
--- a/java/com/google/ipc/invalidation/testing/android/InvalidationTestService.java
+++ /dev/null
@@ -1,414 +0,0 @@
-/*
- * 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.testing.android;
-
-import com.google.common.base.Preconditions;
-import com.google.ipc.invalidation.external.client.SystemResources.Logger;
-import com.google.ipc.invalidation.external.client.android.service.AndroidLogger;
-import com.google.ipc.invalidation.external.client.android.service.Event;
-import com.google.ipc.invalidation.external.client.android.service.ListenerBinder;
-import com.google.ipc.invalidation.external.client.android.service.ListenerService;
-import com.google.ipc.invalidation.external.client.android.service.Request;
-import com.google.ipc.invalidation.external.client.android.service.Request.Action;
-import com.google.ipc.invalidation.external.client.android.service.Request.Parameter;
-import com.google.ipc.invalidation.external.client.android.service.Response;
-import com.google.ipc.invalidation.external.client.android.service.ServiceBinder.BoundWork;
-import com.google.ipc.invalidation.ticl.android.AbstractInvalidationService;
-import com.google.ipc.invalidation.util.TypedUtil;
-
-import android.accounts.Account;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.IBinder;
-
-import junit.framework.Assert;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * A stub invalidation service implementation that can be used to test the
- * client library or invalidation applications. The test service will validate
- * all incoming events sent by the client. It also supports the ability to store
- * all incoming action intents and outgoing event intents and make them
- * available for retrieval via the {@link InvalidationTest} interface.
- * <p>
- * The implementation of service intent handling will simply log the invocation
- * and do nothing else.
- *
- */
-public class InvalidationTestService extends AbstractInvalidationService {
-
-  private static class ClientState {
-    final Account account;
-    final String authType;
-    final Intent eventIntent;
-
-    private ClientState(Account account, String authType, Intent eventIntent) {
-      this.account = account;
-      this.authType = authType;
-      this.eventIntent = eventIntent;
-    }
-  }
-
-  /**
-   * Intent that can be used to bind to the InvalidationTest service.
-   */
-  public static final Intent TEST_INTENT = new Intent("com.google.ipc.invalidation.TEST");
-
-  /** Logger */
-  private static final Logger logger = AndroidLogger.forTag("InvTestService");
-
-  /** Map of currently active clients from key to {@link ClientState} */
-  private static Map<String, ClientState> clientMap = new HashMap<String, ClientState>();
-
-  /** {@code true} the test service should capture actions */
-  private static boolean captureActions;
-
-  /** The stored actions that are available for retrieval */
-  private static List<Bundle> actions = new ArrayList<Bundle>();
-
-  /** {@code true} if the client should capture events */
-  private static boolean captureEvents;
-
-  /** The stored events that are available for retrieval */
-  private static List<Bundle> events = new ArrayList<Bundle>();
-
-  /** Lock over all state in all instances. */
-  private static final Object LOCK = new Object();
-
-  /**
-   * InvalidationTest stub to handle calls from clients.
-   */
-  private final InvalidationTest.Stub testBinder = new InvalidationTest.Stub() {
-
-    @Override
-    public void setCapture(boolean captureActions, boolean captureEvents) {
-      synchronized (LOCK) {
-        InvalidationTestService.captureActions = captureActions;
-        InvalidationTestService.captureEvents = captureEvents;
-      }
-    }
-
-    @Override
-    public Bundle[] getRequests() {
-      synchronized (LOCK) {
-        logger.fine("Reading actions from %s:%d", actions, actions.size());
-        Bundle[] value = new Bundle[actions.size()];
-        actions.toArray(value);
-        actions.clear();
-        return value;
-      }
-    }
-
-    @Override
-    public Bundle[] getEvents() {
-      synchronized (LOCK) {
-        Bundle[] value = new Bundle[events.size()];
-        events.toArray(value);
-        events.clear();
-        return value;
-      }
-    }
-
-    @Override
-    public void sendEvent(final Bundle eventBundle) {
-      synchronized (LOCK) {
-        // Retrive info for that target client
-        String clientKey = eventBundle.getString(Parameter.CLIENT);
-        ClientState state = clientMap.get(clientKey);
-        Preconditions.checkNotNull(state, "No state for %s in %s", clientKey, clientMap.keySet());
-
-        // Bind to the listener associated with the client and send the event
-        ListenerBinder binder = new ListenerBinder(getBaseContext(), state.eventIntent,
-            InvalidationTestListener.class.getName());
-        binder.runWhenBound(new BoundWork<ListenerService>() {
-          @Override
-          public void run(ListenerService service) {
-            InvalidationTestService.this.sendEvent(service, new Event(eventBundle));
-          }
-        });
-
-        // Will happen after the runWhenBound invokes the receiver. Could also be done inside
-        // the receiver.
-        binder.release();
-      }
-    }
-
-    @Override
-    public void reset() {
-      synchronized (LOCK) {
-        logger.info("Resetting test service");
-        captureActions = false;
-        captureEvents = false;
-        clientMap.clear();
-        actions.clear();
-        events.clear();
-      }
-    }
-  };
-
-  @Override
-  public void onCreate() {
-    synchronized (LOCK) {
-      logger.info("onCreate");
-      super.onCreate();
-    }
-  }
-
-  @Override
-  public void onDestroy() {
-    synchronized (LOCK) {
-      logger.info("onDestroy");
-      super.onDestroy();
-    }
-  }
-
-  @Override
-  public int onStartCommand(Intent intent, int flags, int startId) {
-    synchronized (LOCK) {
-      logger.info("onStart");
-      return super.onStartCommand(intent, flags, startId);
-    }
-  }
-
-  @Override
-  public IBinder onBind(Intent intent) {
-    synchronized (LOCK) {
-      logger.info("onBind");
-
-      // For InvalidationService binding, delegate to the superclass
-      if (Request.SERVICE_INTENT.getAction().equals(intent.getAction())) {
-        return super.onBind(intent);
-      }
-
-      // Otherwise, return the test interface binder
-      return testBinder;
-    }
-  }
-
-  @Override
-  public boolean onUnbind(Intent intent) {
-    synchronized (LOCK) {
-      logger.info("onUnbind");
-      return super.onUnbind(intent);
-    }
-  }
-
-  @Override
-  protected void handleRequest(Bundle input, Bundle output) {
-    synchronized (LOCK) {
-      super.handleRequest(input, output);
-      if (captureActions) {
-        actions.add(input);
-      }
-      validateResponse(input, output);
-    }
-  }
-
-  @Override
-  protected void sendEvent(ListenerService listenerService, Event event) {
-    synchronized (LOCK) {
-      if (captureEvents) {
-        events.add(event.getBundle());
-      }
-      super.sendEvent(listenerService, event);
-    }
-  }
-
-
-  @Override
-  protected void create(Request request, Response.Builder response) {
-    synchronized (LOCK) {
-      validateRequest(request, Action.CREATE, Parameter.ACTION, Parameter.CLIENT,
-          Parameter.CLIENT_TYPE, Parameter.ACCOUNT, Parameter.AUTH_TYPE, Parameter.INTENT);
-      logger.info("Creating client %s:%s", request.getClientKey(), clientMap.keySet());
-      if (!TypedUtil.containsKey(clientMap, request.getClientKey())) {
-        // If no client exists with this key, create one.
-        clientMap.put(
-            request.getClientKey(), new ClientState(request.getAccount(), request.getAuthType(),
-                request.getIntent()));
-      } else {
-        // Otherwise, verify that the existing client has the same account / auth type / intent.
-        ClientState existingState = TypedUtil.mapGet(clientMap, request.getClientKey());
-        Preconditions.checkState(request.getAccount().equals(existingState.account));
-        Preconditions.checkState(request.getAuthType().equals(existingState.authType));
-      }
-      response.setStatus(Response.Status.SUCCESS);
-    }
-  }
-
-  @Override
-  protected void resume(Request request, Response.Builder response) {
-    synchronized (LOCK) {
-      validateRequest(
-          request, Action.RESUME, Parameter.ACTION, Parameter.CLIENT);
-      ClientState state = clientMap.get(request.getClientKey());
-      if (state != null) {
-        logger.info("Resuming client %s:%s", request.getClientKey(), clientMap.keySet());
-        response.setStatus(Response.Status.SUCCESS);
-        response.setAccount(state.account);
-        response.setAuthType(state.authType);
-      } else {
-        logger.warning("Cannot resume client %s:%s", request.getClientKey(), clientMap.keySet());
-        response.setStatus(Response.Status.INVALID_CLIENT);
-      }
-    }
-  }
-
-  @Override
-  protected void register(Request request, Response.Builder response) {
-    synchronized (LOCK) {
-      // Ensure that one (and only one) of the variant object id forms is used
-      String objectParam =
-        request.getBundle().containsKey(Parameter.OBJECT_ID) ?
-            Parameter.OBJECT_ID : Parameter.OBJECT_ID_LIST;
-      validateRequest(request, Action.REGISTER, Parameter.ACTION, Parameter.CLIENT, objectParam);
-      if (!validateClient(request)) {
-        response.setStatus(Response.Status.INVALID_CLIENT);
-        return;
-      }
-      response.setStatus(Response.Status.SUCCESS);
-    }
-  }
-
-  @Override
-  protected void unregister(Request request, Response.Builder response) {
-    synchronized (LOCK) {
-      // Ensure that one (and only one) of the variant object id forms is used
-      String objectParam =
-        request.getBundle().containsKey(Parameter.OBJECT_ID) ?
-            Parameter.OBJECT_ID :
-            Parameter.OBJECT_ID_LIST;
-      validateRequest(request, Action.UNREGISTER, Parameter.ACTION,
-          Parameter.CLIENT, objectParam);
-      if (!validateClient(request)) {
-        response.setStatus(Response.Status.INVALID_CLIENT);
-        return;
-      }
-      response.setStatus(Response.Status.SUCCESS);
-    }
-  }
-
-  @Override
-  protected void start(Request request, Response.Builder response) {
-    synchronized (LOCK) {
-      validateRequest(
-          request, Action.START, Parameter.ACTION, Parameter.CLIENT);
-      if (!validateClient(request)) {
-        response.setStatus(Response.Status.INVALID_CLIENT);
-        return;
-      }
-      response.setStatus(Response.Status.SUCCESS);
-    }
-  }
-
-  @Override
-  protected void stop(Request request, Response.Builder response) {
-    synchronized (LOCK) {
-      validateRequest(request, Action.STOP, Parameter.ACTION, Parameter.CLIENT);
-      if (!validateClient(request)) {
-        response.setStatus(Response.Status.INVALID_CLIENT);
-        return;
-      }
-      response.setStatus(Response.Status.SUCCESS);
-    }
-  }
-
-  @Override
-  protected void acknowledge(Request request, Response.Builder response) {
-    synchronized (LOCK) {
-      validateRequest(request, Action.ACKNOWLEDGE, Parameter.ACTION, Parameter.CLIENT,
-          Parameter.ACK_TOKEN);
-      if (!validateClient(request)) {
-        response.setStatus(Response.Status.INVALID_CLIENT);
-        return;
-      }
-      response.setStatus(Response.Status.SUCCESS);
-    }
-  }
-
-  @Override
-  protected void destroy(Request request, Response.Builder response) {
-    synchronized (LOCK) {
-      validateRequest(request, Action.DESTROY, Parameter.ACTION, Parameter.CLIENT);
-      if (!validateClient(request)) {
-        response.setStatus(Response.Status.INVALID_CLIENT);
-        return;
-      }
-      response.setStatus(Response.Status.SUCCESS);
-    }
-  }
-
-  /**
-   * Validates that the client associated with the request is one that has
-   * previously been created or resumed on the test service.
-   */
-  private boolean validateClient(Request request) {
-    if (!clientMap.containsKey(request.getClientKey())) {
-      logger.warning("Client %s is not an active client: %s",
-                     request.getClientKey(), clientMap.keySet());
-      return false;
-    }
-    return true;
-  }
-
-  /**
-   * Validates that the request contains exactly the set of parameters expected.
-   *
-   * @param request request to validate
-   * @param action expected action
-   * @param parameters expected parameters
-   */
-  private void validateRequest(Request request, Action action, String... parameters) {
-    Assert.assertEquals(action, request.getAction());
-    List<String> expectedParameters = new ArrayList<String>(Arrays.asList(parameters));
-    Bundle requestBundle = request.getBundle();
-    for (String parameter : requestBundle.keySet()) {
-      Assert.assertTrue("Unexpected parameter: " + parameter, expectedParameters.remove(parameter));
-
-      // Validate the value
-      Object value = requestBundle.get(parameter);
-      Assert.assertNotNull(value);
-    }
-    Assert.assertTrue("Missing parameter:" + expectedParameters, expectedParameters.isEmpty());
-  }
-
-  /**
-   * Validates a response bundle being returned to a client contains valid
-   * success response.
-   */
-  protected void validateResponse(Bundle input, Bundle output) {
-    synchronized (LOCK) {
-      int status = output.getInt(Response.Parameter.STATUS, Response.Status.UNKNOWN);
-      Assert.assertEquals("Unexpected failure for input = " + input + "; output = " + output,
-          Response.Status.SUCCESS, status);
-      String error = output.getString(Response.Parameter.ERROR);
-      Assert.assertNull(error);
-    }
-  }
-
-  /** Returns whether a client with key {@code clientKey} is known to the service. */
-  public static boolean clientExists(String clientKey) {
-    synchronized (LOCK) {
-      return TypedUtil.containsKey(clientMap, clientKey);
-    }
-  }
-}
diff --git a/java/com/google/ipc/invalidation/ticl/AckCache.java b/java/com/google/ipc/invalidation/ticl/AckCache.java
new file mode 100644
index 0000000..4812050
--- /dev/null
+++ b/java/com/google/ipc/invalidation/ticl/AckCache.java
@@ -0,0 +1,103 @@
+/*
+ * 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;
+
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationP;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP;
+import com.google.ipc.invalidation.util.TypedUtil;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * An ack "cache" that allows the TICL to avoid unnecessary delivery of a
+ * known-version invalidation when the client has aleady acked a known-version,
+ * restarted invalidation with the same or a greater version number.
+ * <p>
+ * This helps invalidation clients avoid unnecessary syncs against their backend
+ * when invalidations for an object are redelivered or reordered, as can occur
+ * frequently during a PCR or (to a lesser degree) as a result of internal
+ * failures and channel flakiness.
+ * <p>
+ * This optimization is especially useful for applications that want to use
+ * the TI Pubsub API to deliver invalidations, because version numbers are not
+ * a concept in the API itself. While the client could include version numbers
+ * in the payload, truncation messages do not include a payload.
+ * <p>
+ * The  cache invalidation API does expose version numbers, so client
+ * applications could implement the same logic themselves, but many
+ * do not, so it is a useful convenience to implement this for them in the TICL.
+ * <p>
+ * Note this class currently only records acks for restarted, known-version
+ * invalidations. While we might add ack tracking for continous invalidations at
+ * some time in the future, tracking continuous invalidations has less of a
+ * payoff than tracking restarted invalidations, because such an ack does not
+ * implicitly ack earlier invalidations for that object, and greater complexity,
+ * because of the potentially unbounded number of acks that need to be tracked
+ * for each object.
+ */
+class AckCache {
+
+  /**
+   * A map from object id to the (long) version number of the highest
+   * <em>restarted, known version</em> invalidation for that object that has
+   * been acked by the client.
+   */
+  private Map<ObjectIdP, Long> highestAckedVersionMap = new HashMap<ObjectIdP, Long>();
+
+  /** Records the fact that the client has acknowledged the given invalidation. */
+  void recordAck(InvalidationP inv) {
+    if (!inv.getIsTrickleRestart() || !inv.getIsKnownVersion()) {
+      return;
+    }
+
+    // If the invalidation version is newer than the highest acked version in the
+    // map, then update the map.
+    ObjectIdP objectId = inv.getObjectId();
+    long version = inv.getVersion();
+    if (version > getHighestAckedVersion(objectId)) {
+      highestAckedVersionMap.put(objectId, version);
+    }
+  };
+
+  /**
+   * Returns true if the client has already acked a restarted invalidation with
+   * a version number greater than or equal to that in {@code inv} and the same
+   * object id, and {@code inv} is a known version invalidation. Unknown version
+   * invalidations are never considered already acked.
+   *
+   * @param {!invalidation.proto.InvalidationP} inv
+   * @return {boolean}
+   */
+  boolean isAcked(InvalidationP inv) {
+    return inv.getIsKnownVersion()
+        && this.getHighestAckedVersion(inv.getObjectId()) >= inv.getVersion();
+  };
+
+
+  /**
+   * Returns the highest acked version for the object id with the given key, or
+   * -1 if no versions have been acked.
+   *
+   * @param {string} objectIdKey The string key for an object id.
+   * @return {!goog.math.Long}
+   * @private
+   */
+  private long getHighestAckedVersion(ObjectIdP objectId) {
+    Long version = TypedUtil.mapGet(highestAckedVersionMap, objectId);
+    return (version != null) ? version : -1L;
+  };
+}
diff --git a/java/com/google/ipc/invalidation/ticl/InvalidationClientCore.java b/java/com/google/ipc/invalidation/ticl/InvalidationClientCore.java
index 3281dc4..79fa23a 100644
--- a/java/com/google/ipc/invalidation/ticl/InvalidationClientCore.java
+++ b/java/com/google/ipc/invalidation/ticl/InvalidationClientCore.java
@@ -19,12 +19,8 @@
 import static com.google.ipc.invalidation.external.client.SystemResources.Scheduler.NO_DELAY;
 
 import com.google.common.base.Preconditions;
-import com.google.ipc.invalidation.common.CommonInvalidationConstants2;
-import com.google.ipc.invalidation.common.CommonProtoStrings2;
-import com.google.ipc.invalidation.common.CommonProtos2;
 import com.google.ipc.invalidation.common.DigestFunction;
 import com.google.ipc.invalidation.common.ObjectIdDigestUtils;
-import com.google.ipc.invalidation.common.TiclMessageValidator2;
 import com.google.ipc.invalidation.external.client.InvalidationListener;
 import com.google.ipc.invalidation.external.client.InvalidationListener.RegistrationState;
 import com.google.ipc.invalidation.external.client.SystemResources;
@@ -45,36 +41,38 @@
 import com.google.ipc.invalidation.ticl.Statistics.ClientErrorType;
 import com.google.ipc.invalidation.ticl.Statistics.IncomingOperationType;
 import com.google.ipc.invalidation.ticl.Statistics.ReceivedMessageType;
+import com.google.ipc.invalidation.ticl.proto.ChannelCommon.NetworkEndpointId;
+import com.google.ipc.invalidation.ticl.proto.Client.AckHandleP;
+import com.google.ipc.invalidation.ticl.proto.Client.ExponentialBackoffState;
+import com.google.ipc.invalidation.ticl.proto.Client.PersistentTiclState;
+import com.google.ipc.invalidation.ticl.proto.Client.RunStateP;
+import com.google.ipc.invalidation.ticl.proto.ClientConstants;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.ApplicationClientIdP;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.ClientConfigP;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.ErrorMessage;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.InfoRequestMessage.InfoType;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationP;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.ProtocolHandlerConfigP;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationP;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationStatus;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSubtree;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSummary;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version;
+import com.google.ipc.invalidation.ticl.proto.CommonProtos;
+import com.google.ipc.invalidation.ticl.proto.JavaClient.InvalidationClientState;
+import com.google.ipc.invalidation.ticl.proto.JavaClient.ProtocolHandlerState;
+import com.google.ipc.invalidation.ticl.proto.JavaClient.RecurringTaskState;
+import com.google.ipc.invalidation.ticl.proto.JavaClient.RegistrationManagerStateP;
+import com.google.ipc.invalidation.ticl.proto.JavaClient.StatisticsState;
 import com.google.ipc.invalidation.util.Box;
 import com.google.ipc.invalidation.util.Bytes;
 import com.google.ipc.invalidation.util.InternalBase;
 import com.google.ipc.invalidation.util.Marshallable;
+import com.google.ipc.invalidation.util.ProtoWrapper.ValidationException;
 import com.google.ipc.invalidation.util.Smearer;
 import com.google.ipc.invalidation.util.TextBuilder;
 import com.google.ipc.invalidation.util.TypedUtil;
-import com.google.protobuf.ByteString;
-import com.google.protobuf.InvalidProtocolBufferException;
-import com.google.protos.ipc.invalidation.ChannelCommon.NetworkEndpointId;
-import com.google.protos.ipc.invalidation.Client.AckHandleP;
-import com.google.protos.ipc.invalidation.Client.ExponentialBackoffState;
-import com.google.protos.ipc.invalidation.Client.PersistentTiclState;
-import com.google.protos.ipc.invalidation.Client.RunStateP;
-import com.google.protos.ipc.invalidation.ClientProtocol.ApplicationClientIdP;
-import com.google.protos.ipc.invalidation.ClientProtocol.ClientConfigP;
-import com.google.protos.ipc.invalidation.ClientProtocol.ErrorMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.InfoRequestMessage.InfoType;
-import com.google.protos.ipc.invalidation.ClientProtocol.InvalidationP;
-import com.google.protos.ipc.invalidation.ClientProtocol.ObjectIdP;
-import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationP;
-import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationP.OpType;
-import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationStatus;
-import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationSubtree;
-import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationSummary;
-import com.google.protos.ipc.invalidation.JavaClient.InvalidationClientState;
-import com.google.protos.ipc.invalidation.JavaClient.ProtocolHandlerState;
-import com.google.protos.ipc.invalidation.JavaClient.RecurringTaskState;
-import com.google.protos.ipc.invalidation.JavaClient.RegistrationManagerStateP;
-import com.google.protos.ipc.invalidation.JavaClient.StatisticsState;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -198,8 +196,8 @@
     private static final String TASK_NAME = "PersistentWrite";
 
     /** The last client token that was written to to persistent state successfully. */
-    private final Box<ProtoWrapper<PersistentTiclState>> lastWrittenState =
-        Box.of(ProtoWrapper.of(PersistentTiclState.getDefaultInstance()));
+    private final Box<PersistentTiclState> lastWrittenState =
+        Box.of(PersistentTiclState.DEFAULT_INSTANCE);
 
     PersistentWriteTask() {
       super(TASK_NAME, NO_DELAY, config.getWriteRetryDelayMs(), true);
@@ -218,9 +216,9 @@
       }
 
       // Compute the state that we will write if we decide to go ahead with the write.
-      final ProtoWrapper<PersistentTiclState> state =
-          ProtoWrapper.of(CommonProtos2.newPersistentTiclState(clientToken, lastMessageSendTimeMs));
-      byte[] serializedState = PersistenceUtils.serializeState(state.getProto(), digestFn);
+      final PersistentTiclState state =
+          PersistentTiclState.create(clientToken, lastMessageSendTimeMs);
+      byte[] serializedState = PersistenceUtils.serializeState(state, digestFn);
 
       // Decide whether or not to do the write. The decision varies depending on whether or
       // not the channel supports offline delivery. If we decide not to do the write, then
@@ -234,8 +232,8 @@
       } else {
         // If we do not support offline delivery, we avoid writing the state on each message, and
         // we avoid checking the last-sent time (we check only the client token).
-        if (state.getProto().getClientToken().equals(
-                lastWrittenState.get().getProto().getClientToken())) {
+        if (TypedUtil.<Bytes>equals(
+            state.getClientToken(), lastWrittenState.get().getClientToken())) {
           return false;
         }
       }
@@ -244,7 +242,7 @@
       storage.writeKey(CLIENT_TOKEN_KEY, serializedState, new Callback<Status>() {
         @Override
         public void accept(Status status) {
-          logger.info("Write state completed: %s for %s", status, state.getProto());
+          logger.info("Write state completed: %s for %s", status, state);
           Preconditions.checkState(resources.getInternalScheduler().isRunningOnThread());
           if (status.isSuccess()) {
             // Set lastWrittenToken to be the token that was written (NOT clientToken - which
@@ -383,9 +381,6 @@
   /** Object handling low-level wire format interactions. */
   private final ProtocolHandler protocolHandler;
 
-  /** Used to validate messages */
-  private final TiclMessageValidator2 msgValidator;
-
   /** The function for computing the registration and persistence state digests. */
   private final DigestFunction digestFn = new ObjectIdDigestUtils.Sha1DigestFunction();
 
@@ -399,12 +394,12 @@
   private final Smearer smearer;
 
   /** Current client token known from the server. */
-  private ByteString clientToken = null;
+  private Bytes clientToken = null;
 
   // After the client starts, exactly one of nonce and clientToken is non-null.
 
   /** If not {@code null}, nonce for pending identifier request. */
-  private ByteString nonce = null;
+  private Bytes nonce = null;
 
   /** Whether we should send registrations to the server or not. */
   private boolean shouldSendRegistrations;
@@ -464,17 +459,15 @@
     this.config = config;
     this.ticlState = (ticlRunState == null) ? new RunState() : new RunState(ticlRunState);
     this.smearer = new Smearer(random, this.config.getSmearPercent());
-    this.applicationClientId =
-        CommonProtos2.newApplicationClientIdP(clientType, ByteString.copyFrom(clientName));
+    this.applicationClientId = ApplicationClientIdP.create(clientType, new Bytes(clientName));
     this.listener = listener;
-    this.msgValidator = new TiclMessageValidator2(resources.getLogger());
-    this.statistics = (statisticsState != null) ?
-        Statistics.deserializeStatistics(resources.getLogger(), statisticsState.getCounterList()) :
-        new Statistics();
+    this.statistics = (statisticsState != null)
+        ? Statistics.deserializeStatistics(resources.getLogger(), statisticsState.getCounter())
+        : new Statistics();
     this.registrationManager = new RegistrationManager(logger, statistics, digestFn,
         regManagerState);
     this.protocolHandler = new ProtocolHandler(config.getProtocolHandlerConfig(), resources,
-        smearer, statistics, clientType, applicationName, this, msgValidator, protocolHandlerState);
+        smearer, statistics, clientType, applicationName, this, protocolHandlerState);
   }
 
   /**
@@ -559,22 +552,24 @@
   }
 
   /** Returns a default config builder for the client. */
-  public static ClientConfigP.Builder createConfig() {
-    return ClientConfigP.newBuilder()
-        .setVersion(CommonProtos2.newVersion(CommonInvalidationConstants2.CONFIG_MAJOR_VERSION,
-            CommonInvalidationConstants2.CONFIG_MINOR_VERSION))
-        .setProtocolHandlerConfig(ProtocolHandler.createConfig());
+  public static ClientConfigP createConfig() {
+    Version version =
+        Version.create(ClientConstants.CONFIG_MAJOR_VERSION, ClientConstants.CONFIG_MINOR_VERSION);
+    ProtocolHandlerConfigP protocolHandlerConfig = ProtocolHandler.createConfig();
+    ClientConfigP.Builder builder = new ClientConfigP.Builder(version, protocolHandlerConfig);
+    return builder.build();
   }
 
   /** Returns a configuration builder with parameters set for unit tests. */
-  public static ClientConfigP.Builder createConfigForTest() {
-    return ClientConfigP.newBuilder()
-        .setVersion(CommonProtos2.newVersion(CommonInvalidationConstants2.CONFIG_MAJOR_VERSION,
-            CommonInvalidationConstants2.CONFIG_MINOR_VERSION))
-        .setProtocolHandlerConfig(ProtocolHandler.createConfigForTest())
-        .setNetworkTimeoutDelayMs(2 * 1000)
-        .setHeartbeatIntervalMs(5 * 1000)
-        .setWriteRetryDelayMs(500);
+  public static ClientConfigP createConfigForTest() {
+    Version version =
+        Version.create(ClientConstants.CONFIG_MAJOR_VERSION, ClientConstants.CONFIG_MINOR_VERSION);
+    ProtocolHandlerConfigP protocolHandlerConfig = ProtocolHandler.createConfigForTest();
+    ClientConfigP.Builder builder = new ClientConfigP.Builder(version, protocolHandlerConfig);
+    builder.networkTimeoutDelayMs = 2 * 1000;
+    builder.heartbeatIntervalMs = 5 * 1000;
+    builder.writeRetryDelayMs = 500;
+    return builder.build();
   }
 
   /**
@@ -601,8 +596,7 @@
       this.batchingTask = new BatchingTask(protocolHandler, resources, smearer,
           marshalledState.getBatchingTaskState());
       if (marshalledState.hasLastWrittenState()) {
-        persistentWriteTask.lastWrittenState.set(
-            ProtoWrapper.of(marshalledState.getLastWrittenState()));
+        persistentWriteTask.lastWrittenState.set(marshalledState.getLastWrittenState());
       }
     }
     // The handling of new InitialPersistentHeartbeatTask is a little strange. We create one when
@@ -680,22 +674,24 @@
   
   public RegistrationManagerState getRegistrationManagerStateCopyForTest() {
     Preconditions.checkState(resources.getInternalScheduler().isRunningOnThread());
-    return registrationManager.getRegistrationManagerStateCopyForTest(
-        new ObjectIdDigestUtils.Sha1DigestFunction());
+    return registrationManager.getRegistrationManagerStateCopyForTest();
   }
 
   @Override
   
   public void changeNetworkTimeoutDelayForTest(int networkTimeoutDelayMs) {
-    config = ClientConfigP.newBuilder(config).setNetworkTimeoutDelayMs(networkTimeoutDelayMs)
-        .build();
+    ClientConfigP.Builder builder = config.toBuilder();
+    builder.networkTimeoutDelayMs = networkTimeoutDelayMs;
+    config = builder.build();
     createSchedulingTasks(null);
   }
 
   @Override
   
   public void changeHeartbeatDelayForTest(int heartbeatDelayMs) {
-    config = ClientConfigP.newBuilder(config).setHeartbeatIntervalMs(heartbeatDelayMs).build();
+    ClientConfigP.Builder builder = config.toBuilder();
+    builder.heartbeatIntervalMs = heartbeatDelayMs;
+    config = builder.build();
     createSchedulingTasks(null);
   }
 
@@ -708,7 +704,7 @@
 
   @Override
   
-  public ByteString getClientTokenForTest() {
+  public Bytes getClientTokenForTest() {
     return getClientToken();
   }
 
@@ -799,7 +795,7 @@
       // id from the server.
       statistics.recordError(ClientErrorType.PERSISTENT_DESERIALIZATION_FAILURE);
       logger.severe("Failed deserializing persistent state: %s",
-          CommonProtoStrings2.toLazyCompactString(serializedState));
+          Bytes.toLazyCompactString(serializedState));
     }
     if (persistentState != null) {
       // If we have persistent state, use the previously-stored token and send a heartbeat to
@@ -810,8 +806,7 @@
       // We'll ask the application for all of its registrations, but to avoid
       // making the registrar redo the work of performing registrations that
       // probably already exist, we'll suppress sending them to the registrar.
-      logger.info("Restarting from persistent state: %s",
-          CommonProtoStrings2.toLazyCompactString(persistentState.getClientToken()));
+      logger.info("Restarting from persistent state: %s", persistentState.getClientToken());
       setNonce(null);
       setClientToken(persistentState.getClientToken());
       shouldSendRegistrations = false;
@@ -936,9 +931,8 @@
    * @param regOpType whether to register or unregister
    */
   private void performRegisterOperations(final Collection<ObjectId> objectIds,
-      final RegistrationP.OpType regOpType) {
+      final int regOpType) {
     Preconditions.checkState(!objectIds.isEmpty(), "Must specify some object id");
-    Preconditions.checkNotNull(regOpType, "Must specify (un)registration");
     Preconditions.checkState(internalScheduler.isRunningOnThread(),
         "Not running on internal thread");
 
@@ -963,12 +957,11 @@
     List<ObjectIdP> objectIdProtos = new ArrayList<ObjectIdP>(objectIds.size());
     for (ObjectId objectId : objectIds) {
       Preconditions.checkNotNull(objectId, "Must specify object id");
-      ObjectIdP objectIdProto = ProtoConverter.convertToObjectIdProto(objectId);
+      ObjectIdP objectIdProto = ProtoWrapperConverter.convertToObjectIdProto(objectId);
       IncomingOperationType opType = (regOpType == RegistrationP.OpType.REGISTER) ?
           IncomingOperationType.REGISTRATION : IncomingOperationType.UNREGISTRATION;
       statistics.recordIncomingOperation(opType);
-      logger.info("Register %s, %s", CommonProtoStrings2.toLazyCompactString(objectIdProto),
-          regOpType);
+      logger.info("Register %s, %s", objectIdProto, regOpType);
       objectIdProtos.add(objectIdProto);
     }
 
@@ -993,30 +986,31 @@
     Preconditions.checkState(internalScheduler.isRunningOnThread(),
         "Not running on internal thread");
 
-    // 1. Parse the ack handle first.
+    // Parse and validate the ack handle first.
     AckHandleP ackHandle;
     try {
       ackHandle = AckHandleP.parseFrom(acknowledgeHandle.getHandleData());
-    } catch (InvalidProtocolBufferException exception) {
+    } catch (ValidationException exception) {
       logger.warning("Bad ack handle : %s",
-        CommonProtoStrings2.toLazyCompactString(acknowledgeHandle.getHandleData()));
-      statistics.recordError(ClientErrorType.ACKNOWLEDGE_HANDLE_FAILURE);
-      return;
-    }
-
-    // 2. Validate ack handle - it should have a valid invalidation.
-    if (!ackHandle.hasInvalidation() ||
-        !msgValidator.isValid(ackHandle.getInvalidation())) {
-      logger.warning("Incorrect ack handle data: %s", acknowledgeHandle);
+          Bytes.toLazyCompactString(acknowledgeHandle.getHandleData()));
       statistics.recordError(ClientErrorType.ACKNOWLEDGE_HANDLE_FAILURE);
       return;
     }
 
     // Currently, only invalidations have non-trivial ack handle.
-    InvalidationP invalidation = ackHandle.getInvalidation();
+    InvalidationP invalidation = ackHandle.getNullableInvalidation();
+    if (invalidation == null) {
+      logger.warning("Ack handle without invalidation : %s",
+          Bytes.toLazyCompactString(acknowledgeHandle.getHandleData()));
+      statistics.recordError(ClientErrorType.ACKNOWLEDGE_HANDLE_FAILURE);
+      return;
+    }
+
+    // Don't send the payload back.
     if (invalidation.hasPayload()) {
-      // Don't send the payload back.
-      invalidation = invalidation.toBuilder().clearPayload().build();
+      InvalidationP.Builder builder = invalidation.toBuilder();
+      builder.payload = null;
+      invalidation = builder.build();
     }
     statistics.recordIncomingOperation(IncomingOperationType.ACKNOWLEDGE);
     protocolHandler.sendInvalidationAck(invalidation, batchingTask);
@@ -1027,7 +1021,7 @@
   //
 
   @Override
-  public ByteString getClientToken() {
+  public Bytes getClientToken() {
     Preconditions.checkState((clientToken == null) || (nonce == null));
     return clientToken;
   }
@@ -1112,11 +1106,11 @@
     // Then, handle any work remaining in the message.
     if (parsedMessage.invalidationMessage != null) {
       statistics.recordReceivedMessage(ReceivedMessageType.INVALIDATION);
-      handleInvalidations(parsedMessage.invalidationMessage.getInvalidationList());
+      handleInvalidations(parsedMessage.invalidationMessage.getInvalidation());
     }
     if (parsedMessage.registrationStatusMessage != null) {
       statistics.recordReceivedMessage(ReceivedMessageType.REGISTRATION_STATUS);
-      handleRegistrationStatus(parsedMessage.registrationStatusMessage.getRegistrationStatusList());
+      handleRegistrationStatus(parsedMessage.registrationStatusMessage.getRegistrationStatus());
     }
     if (parsedMessage.registrationSyncRequestMessage != null) {
       statistics.recordReceivedMessage(ReceivedMessageType.REGISTRATION_SYNC_REQUEST);
@@ -1124,7 +1118,7 @@
     }
     if (parsedMessage.infoRequestMessage != null) {
       statistics.recordReceivedMessage(ReceivedMessageType.INFO_REQUEST);
-      handleInfoMessage(parsedMessage.infoRequestMessage.getInfoTypeList());
+      handleInfoMessage(parsedMessage.infoRequestMessage.getInfoType());
     }
     if (parsedMessage.errorMessage != null) {
       statistics.recordReceivedMessage(ReceivedMessageType.ERROR);
@@ -1138,7 +1132,7 @@
    * @param headerToken token in the server message
    * @param newToken the new token provided, or {@code null} if this is a destroy message.
    */
-  private void handleTokenChanged(ByteString headerToken, final ByteString newToken) {
+  private void handleTokenChanged(Bytes headerToken, final Bytes newToken) {
     Preconditions.checkState(internalScheduler.isRunningOnThread(), "Not on internal thread");
 
     // The server is either supplying a new token in response to an InitializeMessage, spontaneously
@@ -1146,18 +1140,15 @@
 
     if (newToken != null) {
       // Note: headerToken cannot be null, so a null nonce or clientToken will always be non-equal.
-      boolean headerTokenMatchesNonce = TypedUtil.<ByteString>equals(headerToken, nonce);
-      boolean headerTokenMatchesExistingToken =
-          TypedUtil.<ByteString>equals(headerToken, clientToken);
+      boolean headerTokenMatchesNonce = TypedUtil.<Bytes>equals(headerToken, nonce);
+      boolean headerTokenMatchesExistingToken = TypedUtil.<Bytes>equals(headerToken, clientToken);
       boolean shouldAcceptToken = headerTokenMatchesNonce || headerTokenMatchesExistingToken;
       if (!shouldAcceptToken) {
         logger.info("Ignoring new token; %s does not match nonce = %s or existing token = %s",
             newToken, nonce, clientToken);
         return;
       }
-      logger.info("New token being assigned at client: %s, Old = %s",
-          CommonProtoStrings2.toLazyCompactString(newToken),
-          CommonProtoStrings2.toLazyCompactString(clientToken));
+      logger.info("New token being assigned at client: %s, Old = %s", newToken, clientToken);
 
       // Start the regular heartbeats now.
       heartbeatTask.ensureScheduled("Heartbeat-after-new-token");
@@ -1165,8 +1156,7 @@
       setClientToken(newToken);
       persistentWriteTask.ensureScheduled("Write-after-new-token");
     } else {
-      logger.info("Destroying existing token: %s",
-          CommonProtoStrings2.toLazyCompactString(clientToken));
+      logger.info("Destroying existing token: %s", clientToken);
       acquireToken("Destroy");
     }
   }
@@ -1177,20 +1167,20 @@
     Preconditions.checkState(nonce == null,
         "Cannot process server header with non-null nonce (have %s): %s", nonce, header);
     if (header.registrationSummary != null) {
-      // We've received a summary from the server, so if we were suppressing
-      // registrations, we should now allow them to go to the registrar.
+      // We've received a summary from the server, so if we were suppressing registrations, we
+      // should now allow them to go to the registrar.
       shouldSendRegistrations = true;
 
       // Pass the registration summary to the registration manager. If we are now in agreement
       // with the server and we had any pending operations, we can tell the listener that those
       // operations have succeeded.
-      Set<ProtoWrapper<RegistrationP>> upcalls =
+      Set<RegistrationP> upcalls =
           registrationManager.informServerRegistrationSummary(header.registrationSummary);
       logger.fine("Receivced new server registration summary (%s); will make %s upcalls",
           header.registrationSummary, upcalls.size());
-      for (ProtoWrapper<RegistrationP> upcall : upcalls) {
-        RegistrationP registration = upcall.getProto();
-        ObjectId objectId = ProtoConverter.convertFromObjectIdProto(registration.getObjectId());
+      for (RegistrationP registration : upcalls) {
+        ObjectId objectId =
+            ProtoWrapperConverter.convertFromObjectIdProto(registration.getObjectId());
         RegistrationState regState = convertOpTypeToRegState(registration.getOpType());
         listener.informRegistrationStatus(this, objectId, regState);
       }
@@ -1202,14 +1192,13 @@
     Preconditions.checkState(internalScheduler.isRunningOnThread(), "Not on internal thread");
 
     for (InvalidationP invalidation : invalidations) {
-      AckHandle ackHandle = AckHandle.newInstance(
-          CommonProtos2.newAckHandleP(invalidation).toByteArray());
-      if (CommonProtos2.isAllObjectId(invalidation.getObjectId())) {
+      AckHandle ackHandle = AckHandle.newInstance(AckHandleP.create(invalidation).toByteArray());
+      if (CommonProtos.isAllObjectId(invalidation.getObjectId())) {
         logger.info("Issuing invalidate all");
         listener.invalidateAll(InvalidationClientCore.this, ackHandle);
       } else {
         // Regular object. Could be unknown version or not.
-        Invalidation inv = ProtoConverter.convertFromInvalidationProto(invalidation);
+        Invalidation inv = ProtoWrapperConverter.convertFromInvalidationProto(invalidation);
 
         boolean isSuppressed = invalidation.getIsTrickleRestart();
         logger.info("Issuing invalidate (known-version = %s, is-trickle-restart = %s): %s",
@@ -1244,19 +1233,19 @@
       boolean wasSuccess = localProcessingStatuses.get(i);
       logger.fine("Process reg status: %s", regStatus);
 
-      ObjectId objectId = ProtoConverter.convertFromObjectIdProto(
+      ObjectId objectId = ProtoWrapperConverter.convertFromObjectIdProto(
         regStatus.getRegistration().getObjectId());
       if (wasSuccess) {
         // Server operation was both successful and agreed with what the client wanted.
-        OpType regOpType = regStatus.getRegistration().getOpType();
+        int regOpType = regStatus.getRegistration().getOpType();
         InvalidationListener.RegistrationState regState = convertOpTypeToRegState(regOpType);
         listener.informRegistrationStatus(InvalidationClientCore.this, objectId, regState);
       } else {
         // Server operation either failed or disagreed with client's intent (e.g., successful
         // unregister, but the client wanted a registration).
-        String description = CommonProtos2.isSuccess(regStatus.getStatus()) ?
-            "Registration discrepancy detected" : regStatus.getStatus().getDescription();
-        boolean isPermanent = CommonProtos2.isPermanentFailure(regStatus.getStatus());
+        String description = CommonProtos.isSuccess(regStatus.getStatus())
+            ? "Registration discrepancy detected" : regStatus.getStatus().getDescription();
+        boolean isPermanent = CommonProtos.isPermanentFailure(regStatus.getStatus());
         listener.informRegistrationFailure(InvalidationClientCore.this, objectId, !isPermanent,
             description);
       }
@@ -1274,10 +1263,10 @@
   }
 
   /** Handles an info message request. */
-  private void handleInfoMessage(Collection<InfoType> infoTypes) {
+  private void handleInfoMessage(Collection<Integer> infoTypes) {
     Preconditions.checkState(internalScheduler.isRunningOnThread(), "Not on internal thread");
     boolean mustSendPerformanceCounters = false;
-    for (InfoType infoType : infoTypes) {
+    for (int infoType : infoTypes) {
       mustSendPerformanceCounters = (infoType == InfoType.GET_PERFORMANCE_COUNTERS);
       if (mustSendPerformanceCounters) {
         break;
@@ -1288,8 +1277,7 @@
   }
 
   /** Handles an error message. */
-  private void handleErrorMessage(ServerMessageHeader header,
-      ErrorMessage.Code code, String description) {
+  private void handleErrorMessage(ServerMessageHeader header, int code, String description) {
     Preconditions.checkState(internalScheduler.isRunningOnThread(), "Not on internal thread");
 
     // If it is an auth failure, we shut down the ticl.
@@ -1298,12 +1286,10 @@
     // Translate the code to error reason.
     int reason;
     switch (code) {
-      case AUTH_FAILURE:
+      case ErrorMessage.Code.AUTH_FAILURE:
         reason = ErrorInfo.ErrorReason.AUTH_FAILURE;
         break;
-      case UNKNOWN_FAILURE:
-        reason = ErrorInfo.ErrorReason.UNKNOWN_FAILURE;
-        break;
+      case ErrorMessage.Code.UNKNOWN_FAILURE:
       default:
         reason = ErrorInfo.ErrorReason.UNKNOWN_FAILURE;
         break;
@@ -1319,13 +1305,12 @@
     }
 
     // If there are any registrations, remove them and issue registration failure.
-    Collection<ProtoWrapper<ObjectIdP>> desiredRegistrations =
-        registrationManager.removeRegisteredObjects();
+    Collection<ObjectIdP> desiredRegistrations = registrationManager.removeRegisteredObjects();
     logger.warning("Issuing failure for %s objects", desiredRegistrations.size());
-    for (ProtoWrapper<ObjectIdP> objectIdWrapper : desiredRegistrations) {
-      ObjectIdP objectId = objectIdWrapper.getProto();
+    for (ObjectIdP objectId : desiredRegistrations) {
       listener.informRegistrationFailure(this,
-        ProtoConverter.convertFromObjectIdProto(objectId), false, "Auth error: " + description);
+          ProtoWrapperConverter.convertFromObjectIdProto(objectId), false,
+          "Auth error: " + description);
     }
   }
 
@@ -1336,25 +1321,22 @@
   private boolean validateToken(ParsedMessage parsedMessage) {
     if (clientToken != null) {
       // Client token case.
-      if (!TypedUtil.<ByteString>equals(clientToken, parsedMessage.header.token)) {
+      if (!TypedUtil.<Bytes>equals(clientToken, parsedMessage.header.token)) {
         logger.info("Incoming message has bad token: server = %s, client = %s",
-            CommonProtoStrings2.toLazyCompactString(parsedMessage.header.token),
-            CommonProtoStrings2.toLazyCompactString(clientToken));
+            parsedMessage.header.token, clientToken);
         statistics.recordError(ClientErrorType.TOKEN_MISMATCH);
         return false;
       }
       return true;
     } else if (nonce != null) {
       // Nonce case.
-      if (!TypedUtil.<ByteString>equals(nonce, parsedMessage.header.token)) {
+      if (!TypedUtil.<Bytes>equals(nonce, parsedMessage.header.token)) {
         statistics.recordError(ClientErrorType.NONCE_MISMATCH);
         logger.info("Rejecting server message with mismatched nonce: Client = %s, Server = %s",
-            CommonProtoStrings2.toLazyCompactString(nonce),
-            CommonProtoStrings2.toLazyCompactString(parsedMessage.header.token));
+            nonce, parsedMessage.header.token);
         return false;
       } else {
-        logger.info("Accepting server message with matching nonce: %s",
-            CommonProtoStrings2.toLazyCompactString(nonce));
+        logger.info("Accepting server message with matching nonce: %s", nonce);
         return true;
       }
     }
@@ -1421,8 +1403,7 @@
    * Converts an operation type {@code regOpType} to a
    * {@code InvalidationListener.RegistrationState}.
    */
-  private static InvalidationListener.RegistrationState convertOpTypeToRegState(
-      RegistrationP.OpType regOpType) {
+  private static InvalidationListener.RegistrationState convertOpTypeToRegState(int regOpType) {
     InvalidationListener.RegistrationState regState =
         regOpType == RegistrationP.OpType.REGISTER ?
             InvalidationListener.RegistrationState.REGISTERED :
@@ -1437,7 +1418,7 @@
    * The goal is to ensure that a nonce is never set unless there is no
    * client token, unless the nonce is being cleared.
    */
-  private void setNonce(ByteString newNonce) {
+  private void setNonce(Bytes newNonce) {
     Preconditions.checkState((newNonce == null) || (clientToken == null),
         "Tried to set nonce with existing token %s", clientToken);
     this.nonce = newNonce;
@@ -1447,13 +1428,11 @@
    * Returns a randomly generated nonce. Visible for testing only.
    */
   
-  public static ByteString generateNonce(Random random) {
+  public static Bytes generateNonce(Random random) {
     // Generate 8 random bytes.
     byte[] randomBytes = new byte[8];
     random.nextBytes(randomBytes);
-
-    // Return the bytes as a ByteString.
-    return ByteString.copyFrom(randomBytes);
+    return new Bytes(randomBytes);
   }
 
   /**
@@ -1463,7 +1442,7 @@
    * The goal is to ensure that a token is never set unless there is no
    * nonce, unless the token is being cleared.
    */
-  private void setClientToken(ByteString newClientToken) {
+  private void setClientToken(Bytes newClientToken) {
     Preconditions.checkState((newClientToken == null) || (nonce == null),
         "Tried to set token with existing nonce %s", nonce);
 
@@ -1522,39 +1501,30 @@
 
   @Override
   public void toCompactString(TextBuilder builder) {
-    builder.appendFormat("Client: %s, %s, %s", applicationClientId,
-        CommonProtoStrings2.toLazyCompactString(clientToken), ticlState);
+    builder.append("Client: ").append(applicationClientId).append(", ")
+        .append(clientToken).append(", ").append(ticlState);
   }
 
   @Override
   public InvalidationClientState marshal() {
     Preconditions.checkState(internalScheduler.isRunningOnThread(),
         "Not running on internal thread");
-    InvalidationClientState.Builder builder = InvalidationClientState.newBuilder();
-    if (clientToken != null) {
-      builder.setClientToken(clientToken);
-    }
-    builder.setLastMessageSendTimeMs(lastMessageSendTimeMs);
-    if (nonce != null) {
-      builder.setNonce(nonce);
-    }
-    builder.setProtocolHandlerState(protocolHandler.marshal())
-      .setRegistrationManagerState(registrationManager.marshal())
-      .setShouldSendRegistrations(shouldSendRegistrations)
-      .setRunState(ticlState.marshal())
-      .setIsOnline(isOnline)
-      .setAcquireTokenTaskState(acquireTokenTask.marshal())
-      .setPersistentWriteTaskState(persistentWriteTask.marshal())
-      .setRegSyncHeartbeatTaskState(regSyncHeartbeatTask.marshal())
-      .setHeartbeatTaskState(heartbeatTask.marshal())
-      .setBatchingTaskState(batchingTask.marshal())
-      .setStatisticsState(statistics.marshal());
-    if (clientToken != null) {
-      builder.setClientToken(clientToken);
-    }
-    if (persistentWriteTask.lastWrittenState.get() != null) {
-      builder.setLastWrittenState(persistentWriteTask.lastWrittenState.get().getProto());
-    }
+    InvalidationClientState.Builder builder = new InvalidationClientState.Builder();
+    builder.runState = ticlState.marshal();
+    builder.clientToken = clientToken;
+    builder.nonce = nonce;
+    builder.shouldSendRegistrations = shouldSendRegistrations;
+    builder.lastMessageSendTimeMs = lastMessageSendTimeMs;
+    builder.isOnline = isOnline;
+    builder.protocolHandlerState = protocolHandler.marshal();
+    builder.registrationManagerState = registrationManager.marshal();
+    builder.acquireTokenTaskState = acquireTokenTask.marshal();
+    builder.regSyncHeartbeatTaskState = regSyncHeartbeatTask.marshal();
+    builder.persistentWriteTaskState = persistentWriteTask.marshal();
+    builder.heartbeatTaskState = heartbeatTask.marshal();
+    builder.batchingTaskState = batchingTask.marshal();
+    builder.lastWrittenState = persistentWriteTask.lastWrittenState.get();
+    builder.statisticsState = statistics.marshal();
     return builder.build();
   }
 }
diff --git a/java/com/google/ipc/invalidation/ticl/InvalidationClientImpl.java b/java/com/google/ipc/invalidation/ticl/InvalidationClientImpl.java
index c30176c..4ba7337 100644
--- a/java/com/google/ipc/invalidation/ticl/InvalidationClientImpl.java
+++ b/java/com/google/ipc/invalidation/ticl/InvalidationClientImpl.java
@@ -21,7 +21,7 @@
 import com.google.ipc.invalidation.external.client.SystemResources;
 import com.google.ipc.invalidation.external.client.types.AckHandle;
 import com.google.ipc.invalidation.external.client.types.ObjectId;
-import com.google.protos.ipc.invalidation.ClientProtocol.ClientConfigP;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.ClientConfigP;
 
 import java.util.Collection;
 import java.util.Random;
diff --git a/java/com/google/ipc/invalidation/ticl/PersistenceUtils.java b/java/com/google/ipc/invalidation/ticl/PersistenceUtils.java
index 817c571..e25a4a8 100644
--- a/java/com/google/ipc/invalidation/ticl/PersistenceUtils.java
+++ b/java/com/google/ipc/invalidation/ticl/PersistenceUtils.java
@@ -16,14 +16,13 @@
 
 package com.google.ipc.invalidation.ticl;
 
-import com.google.ipc.invalidation.common.CommonProtos2;
 import com.google.ipc.invalidation.common.DigestFunction;
 import com.google.ipc.invalidation.external.client.SystemResources.Logger;
+import com.google.ipc.invalidation.ticl.proto.Client.PersistentStateBlob;
+import com.google.ipc.invalidation.ticl.proto.Client.PersistentTiclState;
+import com.google.ipc.invalidation.util.Bytes;
+import com.google.ipc.invalidation.util.ProtoWrapper.ValidationException;
 import com.google.ipc.invalidation.util.TypedUtil;
-import com.google.protobuf.ByteString;
-import com.google.protobuf.InvalidProtocolBufferException;
-import com.google.protos.ipc.invalidation.Client.PersistentStateBlob;
-import com.google.protos.ipc.invalidation.Client.PersistentTiclState;
 
 /**
  * Utility methods for handling the Ticl persistent state.
@@ -35,8 +34,8 @@
   /** Serializes a Ticl state blob. */
   
   public static byte[] serializeState(PersistentTiclState state, DigestFunction digestFn) {
-    ByteString mac = generateMac(state, digestFn);
-    return CommonProtos2.newPersistentStateBlob(state, mac).toByteArray();
+    Bytes mac = generateMac(state, digestFn);
+    return PersistentStateBlob.create(state, mac).toByteArray();
   }
 
   /**
@@ -49,15 +48,15 @@
     try {
       // Try parsing the envelope protocol buffer.
       stateBlob = PersistentStateBlob.parseFrom(stateBlobBytes);
-    } catch (InvalidProtocolBufferException exception) {
+    } catch (ValidationException exception) {
       logger.severe("Failed deserializing Ticl state: %s", exception.getMessage());
       return null;
     }
 
     // Check the mac in the envelope against the recomputed mac from the state.
     PersistentTiclState ticlState = stateBlob.getTiclState();
-    ByteString mac = generateMac(ticlState, digestFn);
-    if (!TypedUtil.<ByteString>equals(mac, stateBlob.getAuthenticationCode())) {
+    Bytes mac = generateMac(ticlState, digestFn);
+    if (!TypedUtil.<Bytes>equals(mac, stateBlob.getAuthenticationCode())) {
       logger.warning("Ticl state failed MAC check: computed %s vs %s", mac,
           stateBlob.getAuthenticationCode());
       return null;
@@ -66,10 +65,10 @@
   }
 
   /** Returns a message authentication code over {@code state}. */
-  private static ByteString generateMac(PersistentTiclState state, DigestFunction digestFn) {
+  private static Bytes generateMac(PersistentTiclState state, DigestFunction digestFn) {
     digestFn.reset();
     digestFn.update(state.toByteArray());
-    return ByteString.copyFrom(digestFn.getDigest());
+    return new Bytes(digestFn.getDigest());
   }
 
   private PersistenceUtils() {
diff --git a/java/com/google/ipc/invalidation/ticl/ProtoWrapper.java b/java/com/google/ipc/invalidation/ticl/ProtoWrapper.java
index 94a2fe0..99e435d 100644
--- a/java/com/google/ipc/invalidation/ticl/ProtoWrapper.java
+++ b/java/com/google/ipc/invalidation/ticl/ProtoWrapper.java
@@ -70,7 +70,6 @@
    */
   @Override
   public boolean equals(Object o) {
-    Class<?> msgClass = proto.getClass();
     if (!(o instanceof ProtoWrapper)) {
       return false;
     }
@@ -89,6 +88,6 @@
   public String toString() {
     // Don't print exactly the protocol buffer because that could be extremely confusing when
     // debugging, since this object isn't actually a protocol buffer.
-    return "PW-" + proto.toString();
+    return "PW-" + proto;
   }
 }
diff --git a/java/com/google/ipc/invalidation/ticl/ProtoConverter.java b/java/com/google/ipc/invalidation/ticl/ProtoWrapperConverter.java
similarity index 64%
rename from java/com/google/ipc/invalidation/ticl/ProtoConverter.java
rename to java/com/google/ipc/invalidation/ticl/ProtoWrapperConverter.java
index dfa2035..f6c585b 100644
--- a/java/com/google/ipc/invalidation/ticl/ProtoConverter.java
+++ b/java/com/google/ipc/invalidation/ticl/ProtoWrapperConverter.java
@@ -17,24 +17,22 @@
 package com.google.ipc.invalidation.ticl;
 
 import com.google.common.base.Preconditions;
-import com.google.ipc.invalidation.common.CommonProtos2;
-import com.google.ipc.invalidation.common.TrickleState;
 import com.google.ipc.invalidation.external.client.types.Invalidation;
 import com.google.ipc.invalidation.external.client.types.ObjectId;
-import com.google.protobuf.ByteString;
-import com.google.protos.ipc.invalidation.ClientProtocol.InvalidationP;
-import com.google.protos.ipc.invalidation.ClientProtocol.ObjectIdP;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationP;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP;
+import com.google.ipc.invalidation.ticl.proto.CommonProtos;
+import com.google.ipc.invalidation.util.Bytes;
 
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.List;
 
 /**
- * Utilities to convert between protobufs and externally-exposed types in the Ticl.
- *
+ * Utilities to convert between {@link com.google.ipc.invalidation.util.ProtoWrapper ProtoWrapper}
+ * wrappers and externally-exposed types in the Ticl.
  */
 
-public class ProtoConverter {
+public class ProtoWrapperConverter {
 
   /**
    * Converts an object id protocol buffer {@code objectId} to the
@@ -42,7 +40,7 @@
    */
   public static ObjectId convertFromObjectIdProto(ObjectIdP objectIdProto) {
     Preconditions.checkNotNull(objectIdProto);
-    return ObjectId.newInstance(objectIdProto.getSource(), objectIdProto.getName().toByteArray());
+    return ObjectId.newInstance(objectIdProto.getSource(), objectIdProto.getName().getByteArray());
   }
 
   /**
@@ -52,32 +50,34 @@
   
   public static ObjectIdP convertToObjectIdProto(ObjectId objectId) {
     Preconditions.checkNotNull(objectId);
-    return CommonProtos2.newObjectIdP(objectId.getSource(),
-        ByteString.copyFrom(objectId.getName()));
+    return ObjectIdP.create(objectId.getSource(), new Bytes(objectId.getName()));
   }
 
   /**
    * Returns a list of {@link ObjectIdP} by converting each element of {@code objectIds} to
    * an {@code ObjectIdP}.
    */
-  public static List<ObjectIdP> convertToObjectIdProtoList(Collection<ObjectId> objectIds) {
-    List<ObjectIdP> objectIdPs = new ArrayList<ObjectIdP>(objectIds.size());
+  public static Collection<ObjectIdP> convertToObjectIdProtoCollection(
+      Iterable<ObjectId> objectIds) {
+    int expectedSize = (objectIds instanceof Collection) ? ((Collection<?>) objectIds).size() : 1;
+    ArrayList<ObjectIdP> objectIdPs = new ArrayList<ObjectIdP>(expectedSize);
     for (ObjectId objectId : objectIds) {
-      objectIdPs.add(ProtoConverter.convertToObjectIdProto(objectId));
+      objectIdPs.add(convertToObjectIdProto(objectId));
     }
     return objectIdPs;
   }
 
   /**
-   * Returns a list of {@link ObjectId} by converting each element of {@code oidPs} to
+   * Returns a list of {@link ObjectId} by converting each element of {@code objectIdProtos} to
    * an {@code ObjectId}.
    */
-  public static List<ObjectId> convertToObjectIdList(List<ObjectIdP> oidPs) {
-    List<ObjectId> objects = new ArrayList<ObjectId>(oidPs.size());
-    for (ObjectIdP oidP : oidPs) {
-      objects.add(ObjectId.newInstance(oidP.getSource(), oidP.getName().toByteArray()));
+  public static Collection<ObjectId> convertFromObjectIdProtoCollection(
+      Collection<ObjectIdP> objectIdProtos) {
+    ArrayList<ObjectId> objectIds = new ArrayList<ObjectId>(objectIdProtos.size());
+    for (ObjectIdP objectIdProto : objectIdProtos) {
+      objectIds.add(convertFromObjectIdProto(objectIdProto));
     }
-    return objects;
+    return objectIds;
   }
 
   /**
@@ -90,7 +90,7 @@
 
     // No bridge arrival time in invalidation.
     return Invalidation.newInstance(objectId, invalidation.getVersion(),
-        invalidation.hasPayload() ? invalidation.getPayload().toByteArray() : null,
+        invalidation.hasPayload() ? invalidation.getPayload().getByteArray() : null,
             invalidation.getIsTrickleRestart());
   }
 
@@ -106,11 +106,10 @@
     // to suppress earlier invalidations and acks implicitly acknowledge all previous
     // invalidations. Therefore the correct semanantics are provided by setting isTrickleRestart to
     // true.
-    return CommonProtos2.newInvalidationP(objectId, invalidation.getVersion(),
-        TrickleState.fromBoolean(invalidation.getIsTrickleRestartForInternalUse()),
-        invalidation.getPayload() == null ? null : ByteString.copyFrom(invalidation.getPayload()));
+    return CommonProtos.newInvalidationP(objectId, invalidation.getVersion(),
+        invalidation.getIsTrickleRestartForInternalUse(), invalidation.getPayload());
   }
 
-  private ProtoConverter() { // To prevent instantiation.
+  private ProtoWrapperConverter() { // To prevent instantiation.
   }
 }
diff --git a/java/com/google/ipc/invalidation/ticl/ProtocolHandler.java b/java/com/google/ipc/invalidation/ticl/ProtocolHandler.java
index b3b8be8..2234087 100644
--- a/java/com/google/ipc/invalidation/ticl/ProtocolHandler.java
+++ b/java/com/google/ipc/invalidation/ticl/ProtocolHandler.java
@@ -17,10 +17,6 @@
 package com.google.ipc.invalidation.ticl;
 
 import com.google.common.base.Preconditions;
-import com.google.ipc.invalidation.common.CommonInvalidationConstants2;
-import com.google.ipc.invalidation.common.CommonProtoStrings2;
-import com.google.ipc.invalidation.common.CommonProtos2;
-import com.google.ipc.invalidation.common.TiclMessageValidator2;
 import com.google.ipc.invalidation.external.client.SystemResources;
 import com.google.ipc.invalidation.external.client.SystemResources.Logger;
 import com.google.ipc.invalidation.external.client.SystemResources.NetworkChannel;
@@ -30,42 +26,47 @@
 import com.google.ipc.invalidation.ticl.Statistics.ClientErrorType;
 import com.google.ipc.invalidation.ticl.Statistics.ReceivedMessageType;
 import com.google.ipc.invalidation.ticl.Statistics.SentMessageType;
+import com.google.ipc.invalidation.ticl.proto.ClientConstants;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.ApplicationClientIdP;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.ClientConfigP;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.ClientHeader;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.ClientToServerMessage;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.ClientVersion;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.ConfigChangeMessage;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.ErrorMessage;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.InfoMessage;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.InfoRequestMessage;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.InitializeMessage;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.InitializeMessage.DigestSerializationType;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationMessage;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationP;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.PropertyRecord;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.ProtocolHandlerConfigP;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.RateLimitP;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationMessage;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationP;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationP.OpType;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationStatusMessage;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSubtree;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSummary;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSyncMessage;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSyncRequestMessage;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.ServerHeader;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.ServerToClientMessage;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.TokenControlMessage;
+import com.google.ipc.invalidation.ticl.proto.CommonProtos;
+import com.google.ipc.invalidation.ticl.proto.JavaClient.BatcherState;
+import com.google.ipc.invalidation.ticl.proto.JavaClient.ProtocolHandlerState;
+import com.google.ipc.invalidation.util.Bytes;
 import com.google.ipc.invalidation.util.InternalBase;
 import com.google.ipc.invalidation.util.Marshallable;
+import com.google.ipc.invalidation.util.ProtoWrapper;
+import com.google.ipc.invalidation.util.ProtoWrapper.ValidationException;
 import com.google.ipc.invalidation.util.Smearer;
 import com.google.ipc.invalidation.util.TextBuilder;
-import com.google.protobuf.ByteString;
-import com.google.protobuf.InvalidProtocolBufferException;
-import com.google.protos.ipc.invalidation.ClientProtocol.ApplicationClientIdP;
-import com.google.protos.ipc.invalidation.ClientProtocol.ClientConfigP;
-import com.google.protos.ipc.invalidation.ClientProtocol.ClientHeader;
-import com.google.protos.ipc.invalidation.ClientProtocol.ClientToServerMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.ClientVersion;
-import com.google.protos.ipc.invalidation.ClientProtocol.ConfigChangeMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.ErrorMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.InfoMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.InfoRequestMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.InitializeMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.InitializeMessage.DigestSerializationType;
-import com.google.protos.ipc.invalidation.ClientProtocol.InvalidationMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.InvalidationP;
-import com.google.protos.ipc.invalidation.ClientProtocol.ObjectIdP;
-import com.google.protos.ipc.invalidation.ClientProtocol.PropertyRecord;
-import com.google.protos.ipc.invalidation.ClientProtocol.ProtocolHandlerConfigP;
-import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationP;
-import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationP.OpType;
-import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationStatusMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationSubtree;
-import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationSummary;
-import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationSyncMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationSyncRequestMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.ServerHeader;
-import com.google.protos.ipc.invalidation.ClientProtocol.ServerToClientMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.TokenControlMessage;
-import com.google.protos.ipc.invalidation.JavaClient.BatcherState;
-import com.google.protos.ipc.invalidation.JavaClient.ProtocolHandlerState;
 
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -98,16 +99,13 @@
     private final SystemResources resources;
 
     /** Set of pending registrations stored as a map for overriding later operations. */
-    private final Map<ProtoWrapper<ObjectIdP>, RegistrationP.OpType> pendingRegistrations =
-        new HashMap<ProtoWrapper<ObjectIdP>, RegistrationP.OpType>();
+    private final Map<ObjectIdP, Integer> pendingRegistrations = new HashMap<ObjectIdP, Integer>();
 
     /** Set of pending invalidation acks. */
-    private final Set<ProtoWrapper<InvalidationP>> pendingAckedInvalidations =
-        new HashSet<ProtoWrapper<InvalidationP>>();
+    private final Set<InvalidationP> pendingAckedInvalidations = new HashSet<InvalidationP>();
 
     /** Set of pending registration sub trees for registration sync. */
-    private final Set<ProtoWrapper<RegistrationSubtree>> pendingRegSubtrees =
-        new HashSet<ProtoWrapper<RegistrationSubtree>>();
+    private final Set<RegistrationSubtree> pendingRegSubtrees = new HashSet<RegistrationSubtree>();
 
     /** Pending initialization message to send to the server, if any. */
     private InitializeMessage pendingInitializeMessage = null;
@@ -124,21 +122,19 @@
     /** Creates a batcher from {@code marshalledState}. */
     Batcher(SystemResources resources, Statistics statistics, BatcherState marshalledState) {
       this(resources, statistics);
-      for (ObjectIdP registration : marshalledState.getRegistrationList()) {
-        pendingRegistrations.put(ProtoWrapper.of(registration), RegistrationP.OpType.REGISTER);
+      for (ObjectIdP registration : marshalledState.getRegistration()) {
+        pendingRegistrations.put(registration, RegistrationP.OpType.REGISTER);
       }
-      for (ObjectIdP unregistration : marshalledState.getUnregistrationList()) {
-        pendingRegistrations.put(ProtoWrapper.of(unregistration), RegistrationP.OpType.UNREGISTER);
+      for (ObjectIdP unregistration : marshalledState.getUnregistration()) {
+        pendingRegistrations.put(unregistration, RegistrationP.OpType.UNREGISTER);
       }
-      for (InvalidationP ack : marshalledState.getAcknowledgementList()) {
-        pendingAckedInvalidations.add(ProtoWrapper.of(ack));
+      for (InvalidationP ack : marshalledState.getAcknowledgement()) {
+        pendingAckedInvalidations.add(ack);
       }
-      for (RegistrationSubtree subtree : marshalledState.getRegistrationSubtreeList()) {
-        pendingRegSubtrees.add(ProtoWrapper.of(subtree));
+      for (RegistrationSubtree subtree : marshalledState.getRegistrationSubtree()) {
+        pendingRegSubtrees.add(subtree);
       }
-      if (marshalledState.hasInitializeMessage()) {
-        pendingInitializeMessage = marshalledState.getInitializeMessage();
-      }
+      pendingInitializeMessage = marshalledState.getNullableInitializeMessage();
       if (marshalledState.hasInfoMessage()) {
         pendingInfoMessage = marshalledState.getInfoMessage();
       }
@@ -155,18 +151,18 @@
     }
 
     /** Adds a registration on {@code oid} of {@code opType} to the registrations to be sent. */
-    void addRegistration(ObjectIdP oid, RegistrationP.OpType opType) {
-      pendingRegistrations.put(ProtoWrapper.of(oid), opType);
+    void addRegistration(ObjectIdP oid, Integer opType) {
+      pendingRegistrations.put(oid, opType);
     }
 
     /** Adds {@code ack} to the set of acknowledgements to be sent. */
     void addAck(InvalidationP ack) {
-      pendingAckedInvalidations.add(ProtoWrapper.of(ack));
+      pendingAckedInvalidations.add(ack);
     }
 
     /** Adds {@code subtree} to the set of registration subtrees to be sent. */
     void addRegSubtree(RegistrationSubtree subtree) {
-      pendingRegSubtrees.add(ProtoWrapper.of(subtree));
+      pendingRegSubtrees.add(subtree);
     }
 
     /**
@@ -174,22 +170,29 @@
      * the builder does <b>NOT</b> include the message header.
      * @param hasClientToken whether the client currently holds a token
      */
-    ClientToServerMessage.Builder toBuilder(boolean hasClientToken) {
-      ClientToServerMessage.Builder builder = ClientToServerMessage.newBuilder();
+    ClientToServerMessage toMessage(final ClientHeader header, boolean hasClientToken) {
+      final InitializeMessage initializeMessage;
+      final RegistrationMessage registrationMessage;
+      final RegistrationSyncMessage registrationSyncMessage;
+      final InvalidationMessage invalidationAckMessage;
+      final InfoMessage infoMessage;
+
       if (pendingInitializeMessage != null) {
         statistics.recordSentMessage(SentMessageType.INITIALIZE);
-        builder.setInitializeMessage(pendingInitializeMessage);
+        initializeMessage = pendingInitializeMessage;
         pendingInitializeMessage = null;
+      } else {
+        initializeMessage = null;
       }
 
       // Note: Even if an initialize message is being sent, we can send additional
       // messages such as regisration messages, etc to the server. But if there is no token
       // and an initialize message is not being sent, we cannot send any other message.
 
-      if (!hasClientToken && !builder.hasInitializeMessage()) {
+      if (!hasClientToken && (initializeMessage == null)) {
         // Cannot send any message
         resources.getLogger().warning(
-            "Cannot send message since no token and no initialize msg: %s", builder);
+            "Cannot send message since no token and no initialize msg");
         statistics.recordError(ClientErrorType.TOKEN_MISSING_FAILURE);
         return null;
       }
@@ -198,33 +201,43 @@
 
       // Add reg, acks, reg subtrees - clear them after adding.
       if (!pendingAckedInvalidations.isEmpty()) {
-        builder.setInvalidationAckMessage(createInvalidationAckMessage());
+        invalidationAckMessage = createInvalidationAckMessage();
         statistics.recordSentMessage(SentMessageType.INVALIDATION_ACK);
+      } else {
+        invalidationAckMessage = null;
       }
 
       // Check regs.
       if (!pendingRegistrations.isEmpty()) {
-        builder.setRegistrationMessage(createRegistrationMessage());
+        registrationMessage = createRegistrationMessage();
         statistics.recordSentMessage(SentMessageType.REGISTRATION);
+      } else {
+        registrationMessage = null;
       }
 
       // Check reg substrees.
       if (!pendingRegSubtrees.isEmpty()) {
-        for (ProtoWrapper<RegistrationSubtree> subtree : pendingRegSubtrees) {
-          builder.setRegistrationSyncMessage(RegistrationSyncMessage.newBuilder()
-              .addSubtree(subtree.getProto()));
-        }
+        // If there are multiple pending reg subtrees, only one is sent.
+        ArrayList<RegistrationSubtree> regSubtrees = new ArrayList<RegistrationSubtree>(1);
+        regSubtrees.add(pendingRegSubtrees.iterator().next());
+        registrationSyncMessage = RegistrationSyncMessage.create(regSubtrees);
         pendingRegSubtrees.clear();
         statistics.recordSentMessage(SentMessageType.REGISTRATION_SYNC);
+      } else {
+        registrationSyncMessage = null;
       }
 
       // Check if an info message has to be sent.
       if (pendingInfoMessage != null) {
         statistics.recordSentMessage(SentMessageType.INFO);
-        builder.setInfoMessage(pendingInfoMessage);
+        infoMessage = pendingInfoMessage;
         pendingInfoMessage = null;
+      } else {
+        infoMessage = null;
       }
-      return builder;
+
+      return ClientToServerMessage.create(header, initializeMessage, registrationMessage,
+          registrationSyncMessage, invalidationAckMessage, infoMessage);
     }
 
     /**
@@ -235,17 +248,15 @@
      */
     private RegistrationMessage createRegistrationMessage() {
       Preconditions.checkState(!pendingRegistrations.isEmpty());
-      RegistrationMessage.Builder regMessage = RegistrationMessage.newBuilder();
 
       // Run through the pendingRegistrations map.
-      for (Map.Entry<ProtoWrapper<ObjectIdP>, RegistrationP.OpType> entry :
-           pendingRegistrations.entrySet()) {
-        RegistrationP reg = CommonProtos2.newRegistrationP(entry.getKey().getProto(),
-            entry.getValue() == RegistrationP.OpType.REGISTER);
-        regMessage.addRegistration(reg);
+      List<RegistrationP> pendingRegistrations =
+          new ArrayList<RegistrationP>(this.pendingRegistrations.size());
+      for (Map.Entry<ObjectIdP, Integer> entry : this.pendingRegistrations.entrySet()) {
+        pendingRegistrations.add(RegistrationP.create(entry.getKey(), entry.getValue()));
       }
-      pendingRegistrations.clear();
-      return regMessage.build();
+      this.pendingRegistrations.clear();
+      return RegistrationMessage.create(pendingRegistrations);
     }
 
     /**
@@ -256,53 +267,34 @@
      */
     private InvalidationMessage createInvalidationAckMessage() {
       Preconditions.checkState(!pendingAckedInvalidations.isEmpty());
-      InvalidationMessage.Builder ackMessage = InvalidationMessage.newBuilder();
-      for (ProtoWrapper<InvalidationP> wrapper : pendingAckedInvalidations) {
-        ackMessage.addInvalidation(wrapper.getProto());
-      }
+      InvalidationMessage ackMessage =
+          InvalidationMessage.create(new ArrayList<InvalidationP>(pendingAckedInvalidations));
       pendingAckedInvalidations.clear();
-      return ackMessage.build();
+      return ackMessage;
     }
 
     @Override
     public BatcherState marshal() {
-      BatcherState.Builder builder = BatcherState.newBuilder();
-
       // Marshall (un)registrations.
-      for (Map.Entry<ProtoWrapper<ObjectIdP>, RegistrationP.OpType> entry :
-          pendingRegistrations.entrySet()) {
-        OpType opType = entry.getValue();
-        ObjectIdP oid = entry.getKey().getProto();
+      ArrayList<ObjectIdP> registrations = new ArrayList<ObjectIdP>(pendingRegistrations.size());
+      ArrayList<ObjectIdP> unregistrations = new ArrayList<ObjectIdP>(pendingRegistrations.size());
+      for (Map.Entry<ObjectIdP, Integer> entry : pendingRegistrations.entrySet()) {
+        Integer opType = entry.getValue();
+        ObjectIdP oid = entry.getKey();
+            new ArrayList<ObjectIdP>(pendingRegistrations.size());
         switch (opType) {
-          case REGISTER:
-            builder.addRegistration(oid);
+          case OpType.REGISTER:
+            registrations.add(oid);
             break;
-          case UNREGISTER:
-            builder.addUnregistration(oid);
+          case OpType.UNREGISTER:
+            unregistrations.add(oid);
             break;
           default:
             throw new IllegalArgumentException(opType.toString());
         }
       }
-
-      // Marshall acks.
-      for (ProtoWrapper<InvalidationP> ack : pendingAckedInvalidations) {
-        builder.addAcknowledgement(ack.getProto());
-      }
-
-      // Marshall registration subtrees.
-      for (ProtoWrapper<RegistrationSubtree> subtree : pendingRegSubtrees) {
-        builder.addRegistrationSubtree(subtree.getProto());
-      }
-
-      // Marshall initialize and info messages if present.
-      if (pendingInitializeMessage != null) {
-        builder.setInitializeMessage(pendingInitializeMessage);
-      }
-      if (pendingInfoMessage != null) {
-        builder.setInfoMessage(pendingInfoMessage);
-      }
-      return builder.build();
+      return BatcherState.create(registrations, unregistrations, pendingAckedInvalidations,
+          pendingRegSubtrees, pendingInitializeMessage, pendingInfoMessage);
     }
   }
 
@@ -314,33 +306,31 @@
      * @param token server-sent token
      * @param registrationSummary summary over server registration state
      */
-    ServerMessageHeader(ByteString token, RegistrationSummary registrationSummary) {
+    ServerMessageHeader(Bytes token, RegistrationSummary registrationSummary) {
       this.token = token;
       this.registrationSummary = registrationSummary;
     }
 
     /** Server-sent token. */
-    ByteString token;
+    Bytes token;
 
     /** Summary of the client's registration state at the server. */
     RegistrationSummary registrationSummary;
 
     @Override
     public void toCompactString(TextBuilder builder) {
-      builder.appendFormat("Token: %s, Summary: %s", CommonProtoStrings2.toLazyCompactString(token),
-          registrationSummary);
+      builder.appendFormat("Token: %s, Summary: %s", token, registrationSummary);
     }
   }
 
   /**
    * Representation of a message receiver for the server. Such a message is guaranteed to be
-   * valid (i.e. checked by {@link TiclMessageValidator2}, but the session token is <b>not</b>
-   * checked.
+   * valid, but the session token is <b>not</b> checked.
    */
   static class ParsedMessage {
     /*
      * Each of these fields corresponds directly to a field in the ServerToClientMessage protobuf.
-     * It is non-null iff the correspondig hasYYY method in the protobuf would return true.
+     * It is non-null iff the corresponding hasYYY method in the protobuf would return true.
      */
     final ServerMessageHeader header;
     final TokenControlMessage tokenControlMessage;
@@ -356,20 +346,17 @@
       // For each field, assign it to the corresponding protobuf field if present, else null.
       ServerHeader messageHeader = rawMessage.getHeader();
       header = new ServerMessageHeader(messageHeader.getClientToken(),
-          messageHeader.hasRegistrationSummary() ? messageHeader.getRegistrationSummary() : null);
-      tokenControlMessage = rawMessage.hasTokenControlMessage() ?
-          rawMessage.getTokenControlMessage() : null;
-      invalidationMessage = rawMessage.hasInvalidationMessage() ?
-          rawMessage.getInvalidationMessage() : null;
-      registrationStatusMessage = rawMessage.hasRegistrationStatusMessage() ?
-          rawMessage.getRegistrationStatusMessage() : null;
-      registrationSyncRequestMessage = rawMessage.hasRegistrationSyncRequestMessage() ?
-          rawMessage.getRegistrationSyncRequestMessage() : null;
-      configChangeMessage = rawMessage.hasConfigChangeMessage() ?
-          rawMessage.getConfigChangeMessage() : null;
-      infoRequestMessage = rawMessage.hasInfoRequestMessage() ?
-          rawMessage.getInfoRequestMessage() : null;
-      errorMessage = rawMessage.hasErrorMessage() ? rawMessage.getErrorMessage() : null;
+          messageHeader.getNullableRegistrationSummary());
+      tokenControlMessage =
+          rawMessage.hasTokenControlMessage() ? rawMessage.getTokenControlMessage() : null;
+      invalidationMessage = rawMessage.getNullableInvalidationMessage();
+      registrationStatusMessage = rawMessage.getNullableRegistrationStatusMessage();
+      registrationSyncRequestMessage = rawMessage.hasRegistrationSyncRequestMessage()
+          ? rawMessage.getRegistrationSyncRequestMessage() : null;
+      configChangeMessage =
+          rawMessage.hasConfigChangeMessage() ? rawMessage.getConfigChangeMessage() : null;
+      infoRequestMessage = rawMessage.getNullableInfoRequestMessage();
+      errorMessage = rawMessage.getNullableErrorMessage();
     }
   }
 
@@ -385,7 +372,7 @@
     RegistrationSummary getRegistrationSummary();
 
     /** Returns the current server-assigned client token, if any. */
-    ByteString getClientToken();
+    Bytes getClientToken();
   }
 
   /** Information about the client, e.g., application name, OS, etc. */
@@ -403,9 +390,6 @@
   /** The protocol listener. */
   private final ProtocolListener listener;
 
-  /** Checks that messages (inbound and outbound) conform to basic validity constraints. */
-  private final TiclMessageValidator2 msgValidator;
-
   /** Batches messages to the server. */
   private final Batcher batcher;
 
@@ -442,15 +426,13 @@
    */
   ProtocolHandler(ProtocolHandlerConfigP config, final SystemResources resources,
       Smearer smearer, Statistics statistics, int clientType, String applicationName,
-      ProtocolListener listener, TiclMessageValidator2 msgValidator,
-      ProtocolHandlerState marshalledState) {
+      ProtocolListener listener, ProtocolHandlerState marshalledState) {
     this.logger = resources.getLogger();
     this.statistics = statistics;
     this.internalScheduler = resources.getInternalScheduler();
     this.network = resources.getNetwork();
     this.listener = listener;
-    this.msgValidator = msgValidator;
-    this.clientVersion = CommonProtos2.newClientVersion(resources.getPlatform(), "Java",
+    this.clientVersion = CommonProtos.newClientVersion(resources.getPlatform(), "Java",
         applicationName);
     this.clientType = clientType;
     if (marshalledState == null) {
@@ -468,20 +450,21 @@
   }
 
   /** Returns a default config for the protocol handler. */
-  static ProtocolHandlerConfigP.Builder createConfig() {
+  static ProtocolHandlerConfigP createConfig() {
     // Allow at most 3 messages every 5 seconds.
     int windowMs = 5 * 1000;
     int numMessagesPerWindow = 3;
 
-    return ProtocolHandlerConfigP.newBuilder()
-        .addRateLimit(CommonProtos2.newRateLimitP(windowMs, numMessagesPerWindow));
+    List<RateLimitP> rateLimits = new ArrayList<RateLimitP>();
+    rateLimits.add(RateLimitP.create(windowMs, numMessagesPerWindow));
+    return ProtocolHandlerConfigP.create(null, rateLimits);
   }
 
   /** Returns a configuration object with parameters set for unit tests. */
-  static ProtocolHandlerConfigP.Builder createConfigForTest() {
+  static ProtocolHandlerConfigP createConfigForTest() {
     // No rate limits
     int smallBatchDelayForTest = 200;
-    return ProtocolHandlerConfigP.newBuilder().setBatchingDelayMs(smallBatchDelayForTest);
+    return ProtocolHandlerConfigP.create(smallBatchDelayForTest, new ArrayList<RateLimitP>(0));
   }
 
   /**
@@ -507,23 +490,15 @@
     ServerToClientMessage message;
     try {
       message = ServerToClientMessage.parseFrom(incomingMessage);
-    } catch (InvalidProtocolBufferException exception) {
-      logger.warning("Incoming message is unparseable: %s",
-          CommonProtoStrings2.toLazyCompactString(incomingMessage));
-      return null;
-    }
-
-    // Validate the message. If this passes, we can blindly assume valid messages from here on.
-    logger.fine("Incoming message: %s", message);
-    if (!msgValidator.isValid(message)) {
+    } catch (ValidationException exception) {
       statistics.recordError(ClientErrorType.INCOMING_MESSAGE_FAILURE);
-      logger.severe("Received invalid message: %s", message);
+      logger.warning("Incoming message is invalid: %s", Bytes.toLazyCompactString(incomingMessage));
       return null;
     }
 
     // Check the version of the message.
     if (message.getHeader().getProtocolVersion().getVersion().getMajorVersion() !=
-        CommonInvalidationConstants2.PROTOCOL_MAJOR_VERSION) {
+        ClientConstants.PROTOCOL_MAJOR_VERSION) {
       statistics.recordError(ClientErrorType.PROTOCOL_VERSION_FAILURE);
       logger.severe("Dropping message with incompatible version: %s", message);
       return null;
@@ -552,7 +527,7 @@
    * @param nonce nonce for the request
    * @param debugString information to identify the caller
    */
-  void sendInitializeMessage(ApplicationClientIdP applicationClientId, ByteString nonce,
+  void sendInitializeMessage(ApplicationClientIdP applicationClientId, Bytes nonce,
       BatchingTask batchingTask, String debugString) {
     Preconditions.checkState(internalScheduler.isRunningOnThread(), "Not on internal thread");
     if (applicationClientId.getClientType() != clientType) {
@@ -563,8 +538,8 @@
     }
 
     // Simply store the message in pendingInitializeMessage and send it when the batching task runs.
-    InitializeMessage initializeMsg = CommonProtos2.newInitializeMessage(clientType,
-        applicationClientId, nonce, DigestSerializationType.BYTE_BASED);
+    InitializeMessage initializeMsg = InitializeMessage.create(clientType, nonce,
+        applicationClientId, DigestSerializationType.BYTE_BASED);
     batcher.setInitializeMessage(initializeMsg);
     logger.info("Batching initialize message for client: %s, %s", debugString, initializeMsg);
     batchingTask.ensureScheduled(debugString);
@@ -582,26 +557,17 @@
       ClientConfigP clientConfig, boolean requestServerRegistrationSummary,
       BatchingTask batchingTask) {
     Preconditions.checkState(internalScheduler.isRunningOnThread(), "Not on internal thread");
-    InfoMessage.Builder infoMessage = InfoMessage.newBuilder()
-        .setClientVersion(clientVersion);
 
-    // Add configuration parameters.
-    if (clientConfig != null) {
-      infoMessage.setClientConfig(clientConfig);
+    List<PropertyRecord> performanceCounterRecords =
+        new ArrayList<PropertyRecord>(performanceCounters.size());
+    for (SimplePair<String, Integer> counter : performanceCounters) {
+      performanceCounterRecords.add(PropertyRecord.create(counter.first, counter.second));
     }
-
-    // Add performance counters.
-    for (SimplePair<String, Integer> performanceCounter : performanceCounters) {
-      PropertyRecord counter =
-          CommonProtos2.newPropertyRecord(performanceCounter.first, performanceCounter.second);
-      infoMessage.addPerformanceCounter(counter);
-    }
-
-    // Indicate whether we want the server's registration summary sent back.
-    infoMessage.setServerRegistrationSummaryRequested(requestServerRegistrationSummary);
+    InfoMessage infoMessage = InfoMessage.create(clientVersion, /* configParameter */ null,
+        performanceCounterRecords, requestServerRegistrationSummary, clientConfig);
 
     // Simply store the message in pendingInfoMessage and send it when the batching task runs.
-    batcher.setInfoMessage(infoMessage.build());
+    batcher.setInfoMessage(infoMessage);
     batchingTask.ensureScheduled("Send-info");
   }
 
@@ -611,7 +577,7 @@
    * @param objectIds object ids on which to (un)register
    * @param regOpType whether to register or unregister
    */
-  void sendRegistrations(Collection<ObjectIdP> objectIds, RegistrationP.OpType regOpType,
+  void sendRegistrations(Collection<ObjectIdP> objectIds, Integer regOpType,
       BatchingTask batchingTask) {
     Preconditions.checkState(internalScheduler.isRunningOnThread(), "Not on internal thread");
     for (ObjectIdP objectId : objectIds) {
@@ -623,7 +589,8 @@
   /** Sends an acknowledgement for {@code invalidation} to the server. */
   void sendInvalidationAck(InvalidationP invalidation, BatchingTask batchingTask) {
     Preconditions.checkState(internalScheduler.isRunningOnThread(), "Not on internal thread");
-    // We could do squelching - we don't since it is unlikely to be too beneficial here.
+    // We could summarize acks when there are suppressing invalidations - we don't since it is
+    // unlikely to be too beneficial here.
     logger.fine("Sending ack for invalidation %s", invalidation);
     batcher.addAck(invalidation);
     batchingTask.ensureScheduled("Send-Ack");
@@ -651,27 +618,23 @@
     }
 
     // Create the message from the batcher.
-    ClientToServerMessage.Builder msgBuilder =
-        batcher.toBuilder(listener.getClientToken() != null);
-    if (msgBuilder == null) {
-      // Happens when we don't have a token and are not sending an initialize message. Logged
-      // in batcher.toBuilder().
-      return;
-    }
-    msgBuilder.setHeader(createClientHeader());
-    ++messageId;
-
-    // Validate the message and send it.
-    ClientToServerMessage message = msgBuilder.build();
-    if (!msgValidator.isValid(message)) {
-      logger.severe("Tried to send invalid message: %s", message);
+    ClientToServerMessage message;
+    try {
+      message = batcher.toMessage(createClientHeader(), listener.getClientToken() != null);
+      if (message == null) {
+        // Happens when we don't have a token and are not sending an initialize message. Logged
+        // in batcher.toMessage().
+        return;
+      }
+    } catch (ProtoWrapper.ValidationArgumentException exception) {
+      logger.severe("Tried to send invalid message: %s", batcher);
       statistics.recordError(ClientErrorType.OUTGOING_MESSAGE_FAILURE);
       return;
     }
+    ++messageId;
 
     statistics.recordSentMessage(SentMessageType.TOTAL);
-    logger.fine("Sending message to server: %s",
-        CommonProtoStrings2.toLazyCompactString(message, true));
+    logger.fine("Sending message to server: %s", message);
     network.sendMessage(message.toByteArray());
 
     // Record that the message was sent. We're invoking the listener directly, rather than
@@ -682,31 +645,17 @@
   }
 
   /** Returns the header to include on a message to the server. */
-  private ClientHeader.Builder createClientHeader() {
+  private ClientHeader createClientHeader() {
     Preconditions.checkState(internalScheduler.isRunningOnThread(), "Not on internal thread");
-    ClientHeader.Builder builder = ClientHeader.newBuilder()
-        .setProtocolVersion(CommonInvalidationConstants2.PROTOCOL_VERSION)
-        .setClientTimeMs(internalScheduler.getCurrentTimeMs())
-        .setMessageId(Integer.toString(messageId))
-        .setMaxKnownServerTimeMs(lastKnownServerTimeMs)
-        .setRegistrationSummary(listener.getRegistrationSummary())
-        .setClientType(clientType);
-    ByteString clientToken = listener.getClientToken();
-    if (clientToken != null) {
-      logger.fine("Sending token on client->server message: %s",
-          CommonProtoStrings2.toLazyCompactString(clientToken));
-      builder.setClientToken(clientToken);
-    }
-    return builder;
+    return ClientHeader.create(ClientConstants.PROTOCOL_VERSION,
+        listener.getClientToken(), listener.getRegistrationSummary(),
+        internalScheduler.getCurrentTimeMs(),  lastKnownServerTimeMs, Integer.toString(messageId),
+        clientType);
   }
 
   @Override
   public ProtocolHandlerState marshal() {
-    ProtocolHandlerState.Builder builder = ProtocolHandlerState.newBuilder();
-    builder.setLastKnownServerTimeMs(lastKnownServerTimeMs);
-    builder.setMessageId(messageId);
-    builder.setNextMessageSendTimeMs(nextMessageSendTimeMs);
-    builder.setBatcherState(batcher.marshal());
-    return builder.build();
+    return ProtocolHandlerState.create(messageId, lastKnownServerTimeMs, nextMessageSendTimeMs,
+        batcher.marshal());
   }
 }
diff --git a/java/com/google/ipc/invalidation/ticl/RecurringTask.java b/java/com/google/ipc/invalidation/ticl/RecurringTask.java
index 1364bc9..32dd3a2 100644
--- a/java/com/google/ipc/invalidation/ticl/RecurringTask.java
+++ b/java/com/google/ipc/invalidation/ticl/RecurringTask.java
@@ -19,13 +19,14 @@
 import com.google.common.base.Preconditions;
 import com.google.ipc.invalidation.external.client.SystemResources.Logger;
 import com.google.ipc.invalidation.external.client.SystemResources.Scheduler;
+import com.google.ipc.invalidation.ticl.proto.Client.ExponentialBackoffState;
+import com.google.ipc.invalidation.ticl.proto.JavaClient.RecurringTaskState;
 import com.google.ipc.invalidation.util.ExponentialBackoffDelayGenerator;
 import com.google.ipc.invalidation.util.InternalBase;
 import com.google.ipc.invalidation.util.Marshallable;
 import com.google.ipc.invalidation.util.NamedRunnable;
 import com.google.ipc.invalidation.util.Smearer;
 import com.google.ipc.invalidation.util.TextBuilder;
-import com.google.protos.ipc.invalidation.JavaClient.RecurringTaskState;
 
 
 /**
@@ -239,14 +240,9 @@
 
   @Override
   public RecurringTaskState marshal() {
-    RecurringTaskState.Builder builder = RecurringTaskState.newBuilder()
-        .setInitialDelayMs(initialDelayMs)
-        .setScheduled(isScheduled)
-        .setTimeoutDelayMs(timeoutDelayMs);
-    if (delayGenerator != null) {
-      builder.setBackoffState(delayGenerator.marshal());
-    }
-    return builder.build();
+    ExponentialBackoffState backoffState =
+        (delayGenerator == null) ? null : delayGenerator.marshal();
+    return RecurringTaskState.create(initialDelayMs, timeoutDelayMs, isScheduled, backoffState);
   }
 
   @Override
diff --git a/java/com/google/ipc/invalidation/ticl/RegistrationManager.java b/java/com/google/ipc/invalidation/ticl/RegistrationManager.java
index 534322a..97adc0d 100644
--- a/java/com/google/ipc/invalidation/ticl/RegistrationManager.java
+++ b/java/com/google/ipc/invalidation/ticl/RegistrationManager.java
@@ -16,23 +16,23 @@
 
 package com.google.ipc.invalidation.ticl;
 
-import com.google.ipc.invalidation.common.CommonProtoStrings2;
-import com.google.ipc.invalidation.common.CommonProtos2;
 import com.google.ipc.invalidation.common.DigestFunction;
 import com.google.ipc.invalidation.external.client.SystemResources.Logger;
 import com.google.ipc.invalidation.ticl.Statistics.ClientErrorType;
 import com.google.ipc.invalidation.ticl.TestableInvalidationClient.RegistrationManagerState;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationP;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationP.OpType;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationStatus;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSubtree;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSummary;
+import com.google.ipc.invalidation.ticl.proto.CommonProtos;
+import com.google.ipc.invalidation.ticl.proto.JavaClient.RegistrationManagerStateP;
+import com.google.ipc.invalidation.util.Bytes;
 import com.google.ipc.invalidation.util.InternalBase;
 import com.google.ipc.invalidation.util.Marshallable;
 import com.google.ipc.invalidation.util.TextBuilder;
 import com.google.ipc.invalidation.util.TypedUtil;
-import com.google.protos.ipc.invalidation.ClientProtocol.ObjectIdP;
-import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationP;
-import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationP.OpType;
-import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationStatus;
-import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationSubtree;
-import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationSummary;
-import com.google.protos.ipc.invalidation.JavaClient.RegistrationManagerStateP;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -62,7 +62,7 @@
   private final Statistics statistics;
 
   /** Latest known server registration state summary. */
-  private ProtoWrapper<RegistrationSummary> lastKnownServerSummary;
+  private RegistrationSummary lastKnownServerSummary;
 
   /**
    * Map of object ids and operation types for which we have not yet issued any registration-status
@@ -75,8 +75,7 @@
    * we issue, which isn't necessarily true (i.e., the server might send back an unregistration
    * status in response to a registration request).
    */
-  private final Map<ProtoWrapper<ObjectIdP>, RegistrationP.OpType> pendingOperations =
-      new HashMap<ProtoWrapper<ObjectIdP>, RegistrationP.OpType>();
+  private final Map<ObjectIdP, Integer> pendingOperations = new HashMap<ObjectIdP, Integer>();
 
   private final Logger logger;
 
@@ -90,13 +89,16 @@
       // Initialize the server summary with a 0 size and the digest corresponding
       // to it.  Using defaultInstance would wrong since the server digest will
       // not match unnecessarily and result in an info message being sent.
-      this.lastKnownServerSummary = ProtoWrapper.of(getRegistrationSummary());
+      this.lastKnownServerSummary = getRegistrationSummary();
     } else {
-      this.lastKnownServerSummary =
-        ProtoWrapper.of(registrationManagerState.getLastKnownServerSummary());
-      desiredRegistrations.add(registrationManagerState.getRegistrationsList());
-      for (RegistrationP regOp : registrationManagerState.getPendingOperationsList()) {
-        pendingOperations.put(ProtoWrapper.of(regOp.getObjectId()), regOp.getOpType());
+      this.lastKnownServerSummary = registrationManagerState.getNullableLastKnownServerSummary();
+      if (this.lastKnownServerSummary == null) {
+        // If no server summary is set, use a default with size 0.
+        this.lastKnownServerSummary = getRegistrationSummary();
+      }
+      desiredRegistrations.add(registrationManagerState.getRegistrations());
+      for (RegistrationP regOp : registrationManagerState.getPendingOperations()) {
+        pendingOperations.put(regOp.getObjectId(), regOp.getOpType());
       }
     }
   }
@@ -108,14 +110,10 @@
    * InvalidationClientImpl's internal thread.
    */
   
-  RegistrationManagerState getRegistrationManagerStateCopyForTest(DigestFunction digestFunction) {
+  RegistrationManagerState getRegistrationManagerStateCopyForTest() {
     List<ObjectIdP> registeredObjects = new ArrayList<ObjectIdP>();
-    for (ObjectIdP oid : desiredRegistrations.getElements(EMPTY_PREFIX, 0)) {
-      registeredObjects.add(oid);
-    }
-    return new RegistrationManagerState(
-        RegistrationSummary.newBuilder(getRegistrationSummary()).build(),
-        RegistrationSummary.newBuilder(lastKnownServerSummary.getProto()).build(),
+    registeredObjects.addAll(desiredRegistrations.getElements(EMPTY_PREFIX, 0));
+    return new RegistrationManagerState(getRegistrationSummary(), lastKnownServerSummary,
         registeredObjects);
   }
 
@@ -127,7 +125,7 @@
   
   void setDigestStoreForTest(DigestStore<ObjectIdP> digestStore) {
     this.desiredRegistrations = digestStore;
-    this.lastKnownServerSummary = ProtoWrapper.of(getRegistrationSummary());
+    this.lastKnownServerSummary = getRegistrationSummary();
   }
 
   
@@ -136,11 +134,10 @@
   }
 
   /** Perform registration/unregistation for all objects in {@code objectIds}. */
-  Collection<ObjectIdP> performOperations(Collection<ObjectIdP> objectIds,
-      RegistrationP.OpType regOpType) {
+  Collection<ObjectIdP> performOperations(Collection<ObjectIdP> objectIds, int regOpType) {
     // Record that we have pending operations on the objects.
     for (ObjectIdP objectId : objectIds) {
-      pendingOperations.put(ProtoWrapper.of(objectId), regOpType);
+      pendingOperations.put(objectId, regOpType);
     }
     // Update the digest appropriately.
     if (regOpType == RegistrationP.OpType.REGISTER) {
@@ -156,11 +153,7 @@
    * whose digest prefix does not match {@code digestPrefix}.
    */
   RegistrationSubtree getRegistrations(byte[] digestPrefix, int prefixLen) {
-    RegistrationSubtree.Builder builder = RegistrationSubtree.newBuilder();
-    for (ObjectIdP objectId : desiredRegistrations.getElements(digestPrefix, prefixLen)) {
-      builder.addRegisteredObject(objectId);
-    }
-    return builder.build();
+    return RegistrationSubtree.create(desiredRegistrations.getElements(digestPrefix, prefixLen));
   }
 
   /**
@@ -181,14 +174,14 @@
       // The object is no longer pending, since we have received a server status for it, so
       // remove it from the pendingOperations map. (It may or may not have existed in the map,
       // since we can receive spontaneous status messages from the server.)
-      TypedUtil.remove(pendingOperations, ProtoWrapper.of(objectIdProto));
+      TypedUtil.remove(pendingOperations, objectIdProto);
 
       // We start off with the local-processing set as success, then potentially fail.
       boolean isSuccess = true;
 
       // if the server operation succeeded, then local processing fails on "incompatibility" as
       // defined above.
-      if (CommonProtos2.isSuccess(registrationStatus.getStatus())) {
+      if (CommonProtos.isSuccess(registrationStatus.getStatus())) {
         boolean appWantsRegistration = desiredRegistrations.contains(objectIdProto);
         boolean isOpRegistration =
             registrationStatus.getRegistration().getOpType() == RegistrationP.OpType.REGISTER;
@@ -200,15 +193,13 @@
           statistics.recordError(ClientErrorType.REGISTRATION_DISCREPANCY);
           logger.info("Ticl discrepancy detected: registered = %s, requested = %s. " +
               "Removing %s from requested",
-              isOpRegistration, appWantsRegistration,
-              CommonProtoStrings2.toLazyCompactString(objectIdProto));
+              isOpRegistration, appWantsRegistration, objectIdProto);
           isSuccess = false;
         }
       } else {
         // If the server operation failed, then also local processing fails.
         desiredRegistrations.remove(objectIdProto);
-        logger.fine("Removing %s from committed",
-            CommonProtoStrings2.toLazyCompactString(objectIdProto));
+        logger.fine("Removing %s from committed", objectIdProto);
         isSuccess = false;
       }
       localStatuses.add(isSuccess);
@@ -223,12 +214,10 @@
    * REQUIRES: the caller issue a permanent failure upcall to the listener for all returned object
    * ids.
    */
-  Collection<ProtoWrapper<ObjectIdP>> removeRegisteredObjects() {
+  Collection<ObjectIdP> removeRegisteredObjects() {
     int numObjects = desiredRegistrations.size() + pendingOperations.size();
-    Set<ProtoWrapper<ObjectIdP>> failureCalls = new HashSet<ProtoWrapper<ObjectIdP>>(numObjects);
-    for (ObjectIdP objectId : desiredRegistrations.removeAll()) {
-      failureCalls.add(ProtoWrapper.of(objectId));
-    }
+    Set<ObjectIdP> failureCalls = new HashSet<ObjectIdP>(numObjects);
+    failureCalls.addAll(desiredRegistrations.removeAll());
     failureCalls.addAll(pendingOperations.keySet());
     pendingOperations.clear();
     return failureCalls;
@@ -240,8 +229,8 @@
 
   /** Returns a summary of the desired registrations. */
   RegistrationSummary getRegistrationSummary() {
-    return CommonProtos2.newRegistrationSummary(desiredRegistrations.size(),
-        desiredRegistrations.getDigest());
+    return RegistrationSummary.create(desiredRegistrations.size(),
+        new Bytes(desiredRegistrations.getDigest()));
   }
 
   /**
@@ -249,21 +238,19 @@
    * Returns a possibly-empty map of <object-id, reg-op-type>. For each entry in the map,
    * the caller should make an inform-registration-status upcall on the listener.
    */
-  Set<ProtoWrapper<RegistrationP>> informServerRegistrationSummary(
+  Set<RegistrationP> informServerRegistrationSummary(
       RegistrationSummary regSummary) {
     if (regSummary != null) {
-      this.lastKnownServerSummary = ProtoWrapper.of(regSummary);
+      this.lastKnownServerSummary = regSummary;
     }
     if (isStateInSyncWithServer()) {
       // If we are now in sync with the server, then the caller should make inform-reg-status
       // upcalls for all operations that we had pending, if any; they are also no longer pending.
-      Set<ProtoWrapper<RegistrationP>> upcallsToMake =
-          new HashSet<ProtoWrapper<RegistrationP>>(pendingOperations.size());
-      for (Map.Entry<ProtoWrapper<ObjectIdP>, RegistrationP.OpType> entry :
-          pendingOperations.entrySet()) {
-        ObjectIdP objectId = entry.getKey().getProto();
+      Set<RegistrationP> upcallsToMake = new HashSet<RegistrationP>(pendingOperations.size());
+      for (Map.Entry<ObjectIdP, Integer> entry : pendingOperations.entrySet()) {
+        ObjectIdP objectId = entry.getKey();
         boolean isReg = entry.getValue() == OpType.REGISTER;
-        upcallsToMake.add(ProtoWrapper.of(CommonProtos2.newRegistrationP(objectId, isReg)));
+        upcallsToMake.add(CommonProtos.newRegistrationP(objectId, isReg));
       }
       pendingOperations.clear();
       return upcallsToMake;
@@ -278,7 +265,7 @@
    * received server summary (from {@link #informServerRegistrationSummary}).
    */
   boolean isStateInSyncWithServer() {
-    return TypedUtil.equals(lastKnownServerSummary, ProtoWrapper.of(getRegistrationSummary()));
+    return TypedUtil.<RegistrationSummary>equals(lastKnownServerSummary, getRegistrationSummary());
   }
 
   @Override
@@ -289,15 +276,14 @@
 
   @Override
   public RegistrationManagerStateP marshal() {
-    RegistrationManagerStateP.Builder builder = RegistrationManagerStateP.newBuilder();
-    builder.setLastKnownServerSummary(lastKnownServerSummary.getProto());
-    builder.addAllRegistrations(desiredRegistrations.getElements(EMPTY_PREFIX, 0));
-    for (Map.Entry<ProtoWrapper<ObjectIdP>, RegistrationP.OpType> pendingOp :
-        pendingOperations.entrySet()) {
-      ObjectIdP objectId = pendingOp.getKey().getProto();
-      boolean isReg = pendingOp.getValue() == OpType.REGISTER;
-      builder.addPendingOperations(CommonProtos2.newRegistrationP(objectId, isReg));
+    List<ObjectIdP> desiredRegistrations =
+        new ArrayList<ObjectIdP>(this.desiredRegistrations.getElements(EMPTY_PREFIX, 0));
+    List<RegistrationP> pendingOperations =
+        new ArrayList<RegistrationP>(this.pendingOperations.size());
+    for (Map.Entry<ObjectIdP, Integer> entry : this.pendingOperations.entrySet()) {
+      pendingOperations.add(RegistrationP.create(entry.getKey(), entry.getValue()));
     }
-    return builder.build();
+    return RegistrationManagerStateP.create(desiredRegistrations, lastKnownServerSummary,
+        pendingOperations);
   }
 }
diff --git a/java/com/google/ipc/invalidation/ticl/RunState.java b/java/com/google/ipc/invalidation/ticl/RunState.java
index 62d2432..0cee26e 100644
--- a/java/com/google/ipc/invalidation/ticl/RunState.java
+++ b/java/com/google/ipc/invalidation/ticl/RunState.java
@@ -17,18 +17,17 @@
 package com.google.ipc.invalidation.ticl;
 
 import com.google.common.base.Preconditions;
+import com.google.ipc.invalidation.ticl.proto.Client.RunStateP;
 import com.google.ipc.invalidation.util.Marshallable;
-import com.google.protos.ipc.invalidation.Client.RunStateP;
 
 /**
  * An abstraction that keeps track of whether the caller is started or stopped and only allows
  * the following transitions NOT_STARTED -> STARTED -> STOPPED. This class is thread-safe.
  *
- *
  */
 public class RunState implements Marshallable<RunStateP> {
-  /** Current run state. */
-  private RunStateP.State currentState;
+  /** Current run state ({@link RunStateP}). */
+  private Integer currentState;
   private Object lock = new Object();
 
   /** Constructs a new instance in the {@code NOT_STARTED} state. */
@@ -85,7 +84,7 @@
 
   @Override
   public RunStateP marshal() {
-    return RunStateP.newBuilder().setState(currentState).build();
+    return RunStateP.create(currentState);
   }
 
   @Override
diff --git a/java/com/google/ipc/invalidation/ticl/SimpleRegistrationStore.java b/java/com/google/ipc/invalidation/ticl/SimpleRegistrationStore.java
index dfb2b24..3ecbef9 100644
--- a/java/com/google/ipc/invalidation/ticl/SimpleRegistrationStore.java
+++ b/java/com/google/ipc/invalidation/ticl/SimpleRegistrationStore.java
@@ -16,13 +16,12 @@
 
 package com.google.ipc.invalidation.ticl;
 
-import com.google.ipc.invalidation.common.CommonProtoStrings2;
 import com.google.ipc.invalidation.common.DigestFunction;
 import com.google.ipc.invalidation.common.ObjectIdDigestUtils;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP;
 import com.google.ipc.invalidation.util.Bytes;
 import com.google.ipc.invalidation.util.InternalBase;
 import com.google.ipc.invalidation.util.TextBuilder;
-import com.google.protos.ipc.invalidation.ClientProtocol.ObjectIdP;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -51,7 +50,8 @@
 
   @Override
   public boolean add(ObjectIdP oid) {
-    if (registrations.put(ObjectIdDigestUtils.getDigest(oid, digestFunction), oid) == null) {
+    if (registrations.put(ObjectIdDigestUtils.getDigest(oid.getSource(),
+        oid.getName().getByteArray(), digestFunction), oid) == null) {
       recomputeDigest();
       return true;
     }
@@ -62,7 +62,8 @@
   public Collection<ObjectIdP> add(Collection<ObjectIdP> oids) {
     Collection<ObjectIdP> addedOids = new ArrayList<ObjectIdP>();
     for (ObjectIdP oid : oids) {
-      if (registrations.put(ObjectIdDigestUtils.getDigest(oid, digestFunction), oid) == null) {
+      if (registrations.put(ObjectIdDigestUtils.getDigest(oid.getSource(),
+          oid.getName().getByteArray(), digestFunction), oid) == null) {
         // There was no previous value, so this is a new item.
         addedOids.add(oid);
       }
@@ -76,7 +77,8 @@
 
   @Override
   public boolean remove(ObjectIdP oid) {
-    if (registrations.remove(ObjectIdDigestUtils.getDigest(oid, digestFunction)) != null) {
+    if (registrations.remove(ObjectIdDigestUtils.getDigest(oid.getSource(),
+        oid.getName().getByteArray(), digestFunction)) != null) {
       recomputeDigest();
       return true;
     }
@@ -87,7 +89,8 @@
   public Collection<ObjectIdP> remove(Collection<ObjectIdP> oids) {
     Collection<ObjectIdP> removedOids = new ArrayList<ObjectIdP>();
     for (ObjectIdP oid : oids) {
-      if (registrations.remove(ObjectIdDigestUtils.getDigest(oid, digestFunction)) != null) {
+      if (registrations.remove(ObjectIdDigestUtils.getDigest(oid.getSource(),
+          oid.getName().getByteArray(), digestFunction)) != null) {
         removedOids.add(oid);
       }
     }
@@ -108,7 +111,8 @@
 
   @Override
   public boolean contains(ObjectIdP oid) {
-    return registrations.containsKey(ObjectIdDigestUtils.getDigest(oid, digestFunction));
+    return registrations.containsKey(ObjectIdDigestUtils.getDigest(oid.getSource(),
+        oid.getName().getByteArray(), digestFunction));
   }
 
   @Override
@@ -134,9 +138,11 @@
 
   @Override
   public void toCompactString(TextBuilder builder) {
-    builder.append("<SimpleRegistrationStore: registrations=");
-    CommonProtoStrings2.toCompactStringForObjectIds(builder, registrations.values());
-    builder.append(", digest=").append(digest)
+    builder
+        .append("<SimpleRegistrationStore: registrations=")
+        .append(registrations.values())
+        .append(", digest=")
+        .append(digest)
         .append(">");
   }
 }
diff --git a/java/com/google/ipc/invalidation/ticl/Statistics.java b/java/com/google/ipc/invalidation/ticl/Statistics.java
index 288254c..6bfd25a 100644
--- a/java/com/google/ipc/invalidation/ticl/Statistics.java
+++ b/java/com/google/ipc/invalidation/ticl/Statistics.java
@@ -16,15 +16,14 @@
 
 package com.google.ipc.invalidation.ticl;
 
-import com.google.ipc.invalidation.common.CommonProtos2;
 import com.google.ipc.invalidation.external.client.SystemResources.Logger;
 import com.google.ipc.invalidation.external.client.types.SimplePair;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.PropertyRecord;
+import com.google.ipc.invalidation.ticl.proto.JavaClient.StatisticsState;
 import com.google.ipc.invalidation.util.InternalBase;
 import com.google.ipc.invalidation.util.Marshallable;
 import com.google.ipc.invalidation.util.TextBuilder;
 import com.google.ipc.invalidation.util.TypedUtil;
-import com.google.protos.ipc.invalidation.ClientProtocol.PropertyRecord;
-import com.google.protos.ipc.invalidation.JavaClient.StatisticsState;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -282,13 +281,13 @@
   public StatisticsState marshal() {
     // Get all the non-zero counters, convert them to proto PropertyRecord messages, and return
     // a StatisticsState containing the records.
-    StatisticsState.Builder builder = StatisticsState.newBuilder();
     List<SimplePair<String, Integer>> counters = new ArrayList<SimplePair<String, Integer>>();
     getNonZeroStatistics(counters);
+    List<PropertyRecord> propertyRecords = new ArrayList<PropertyRecord>(counters.size());
     for (SimplePair<String, Integer> counter : counters) {
-      builder.addCounter(CommonProtos2.newPropertyRecord(counter.getFirst(), counter.getSecond()));
+      propertyRecords.add(PropertyRecord.create(counter.getFirst(), counter.getSecond()));
     }
-    return builder.build();
+    return StatisticsState.create(propertyRecords);
   }
 
   /**
diff --git a/java/com/google/ipc/invalidation/ticl/TestableInvalidationClient.java b/java/com/google/ipc/invalidation/ticl/TestableInvalidationClient.java
index dfb683e..1cb3b1f 100644
--- a/java/com/google/ipc/invalidation/ticl/TestableInvalidationClient.java
+++ b/java/com/google/ipc/invalidation/ticl/TestableInvalidationClient.java
@@ -17,19 +17,19 @@
 package com.google.ipc.invalidation.ticl;
 
 import com.google.common.base.Preconditions;
-import com.google.ipc.invalidation.common.CommonProtoStrings2;
 import com.google.ipc.invalidation.common.DigestFunction;
 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.ticl.proto.ChannelCommon.NetworkEndpointId;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.ClientConfigP;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSummary;
+import com.google.ipc.invalidation.util.Bytes;
 import com.google.ipc.invalidation.util.InternalBase;
 import com.google.ipc.invalidation.util.TextBuilder;
-import com.google.protobuf.ByteString;
-import com.google.protos.ipc.invalidation.ChannelCommon.NetworkEndpointId;
-import com.google.protos.ipc.invalidation.ClientProtocol.ClientConfigP;
-import com.google.protos.ipc.invalidation.ClientProtocol.ObjectIdP;
-import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationSummary;
 
+import java.util.ArrayList;
 import java.util.Collection;
 
 
@@ -52,6 +52,14 @@
     private final Collection<ObjectIdP> registeredObjects;
 
     public RegistrationManagerState(RegistrationSummary clientSummary,
+        RegistrationSummary serverSummary, ObjectIdP[] registeredObjects) {
+      this(clientSummary, serverSummary, new ArrayList<ObjectIdP>(registeredObjects.length));
+      for (ObjectIdP registeredObject : registeredObjects) {
+        this.registeredObjects.add(registeredObject);
+      }
+    }
+
+    public RegistrationManagerState(RegistrationSummary clientSummary,
         RegistrationSummary serverSummary, Collection<ObjectIdP> registeredObjects) {
       this.clientSummary = Preconditions.checkNotNull(clientSummary);
       this.serverSummary = Preconditions.checkNotNull(serverSummary);
@@ -72,13 +80,9 @@
 
     @Override
     public void toCompactString(TextBuilder builder) {
-      builder.append("<RegistrationManagerState: clientSummary=");
-      CommonProtoStrings2.toCompactString(builder, clientSummary);
-      builder.append(", serverSummary=");
-      CommonProtoStrings2.toCompactString(builder, serverSummary);
-      builder.append(", registeredObjects=");
-      CommonProtoStrings2.toCompactStringForObjectIds(builder, registeredObjects);
-      builder.append(">");
+      builder.append("<RegistrationManagerState: clientSummary=").append(clientSummary);
+      builder.append(", serverSummary=").append(serverSummary);
+      builder.append(", registeredObjects=<").append(registeredObjects).append(">");
     }
   }
 
@@ -136,7 +140,7 @@
   InvalidationListener getInvalidationListenerForTest();
 
   /** Returns the current client token. */
-  ByteString getClientTokenForTest();
+  Bytes getClientTokenForTest();
 
   /** Returns the single key used to write all the Ticl state. */
   String getClientTokenKeyForTest();
diff --git a/java/com/google/ipc/invalidation/ticl/TestableNetworkChannel.java b/java/com/google/ipc/invalidation/ticl/TestableNetworkChannel.java
index 0d64925..79cc662 100644
--- a/java/com/google/ipc/invalidation/ticl/TestableNetworkChannel.java
+++ b/java/com/google/ipc/invalidation/ticl/TestableNetworkChannel.java
@@ -17,7 +17,7 @@
 package com.google.ipc.invalidation.ticl;
 
 import com.google.ipc.invalidation.external.client.SystemResources;
-import com.google.protos.ipc.invalidation.ChannelCommon.NetworkEndpointId;
+import com.google.ipc.invalidation.ticl.proto.ChannelCommon.NetworkEndpointId;
 
 /**
  * Extension of {@link com.google.ipc.invalidation.external.client.SystemResources.NetworkChannel}
diff --git a/java/com/google/ipc/invalidation/ticl/TiclExponentialBackoffDelayGenerator.java b/java/com/google/ipc/invalidation/ticl/TiclExponentialBackoffDelayGenerator.java
index a75cfed..fd6d826 100644
--- a/java/com/google/ipc/invalidation/ticl/TiclExponentialBackoffDelayGenerator.java
+++ b/java/com/google/ipc/invalidation/ticl/TiclExponentialBackoffDelayGenerator.java
@@ -15,9 +15,9 @@
  */
 package com.google.ipc.invalidation.ticl;
 
+import com.google.ipc.invalidation.ticl.proto.Client.ExponentialBackoffState;
 import com.google.ipc.invalidation.util.ExponentialBackoffDelayGenerator;
 import com.google.ipc.invalidation.util.Marshallable;
-import com.google.protos.ipc.invalidation.Client.ExponentialBackoffState;
 
 import java.util.Random;
 
@@ -52,9 +52,6 @@
 
   @Override
   public ExponentialBackoffState marshal() {
-    return ExponentialBackoffState.newBuilder()
-      .setCurrentMaxDelay(getCurrentMaxDelay())
-      .setInRetryMode(getInRetryMode())
-      .build();
+    return ExponentialBackoffState.create(getCurrentMaxDelay(), getInRetryMode());
   }
 }
diff --git a/java/com/google/ipc/invalidation/ticl/android/AbstractInvalidationService.java b/java/com/google/ipc/invalidation/ticl/android/AbstractInvalidationService.java
deleted file mode 100644
index 886617a..0000000
--- a/java/com/google/ipc/invalidation/ticl/android/AbstractInvalidationService.java
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * 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.android;
-
-import com.google.ipc.invalidation.external.client.SystemResources.Logger;
-import com.google.ipc.invalidation.external.client.android.service.AndroidLogger;
-import com.google.ipc.invalidation.external.client.android.service.Event;
-import com.google.ipc.invalidation.external.client.android.service.InvalidationService;
-import com.google.ipc.invalidation.external.client.android.service.ListenerService;
-import com.google.ipc.invalidation.external.client.android.service.Request;
-import com.google.ipc.invalidation.external.client.android.service.Request.Action;
-import com.google.ipc.invalidation.external.client.android.service.Response;
-import com.google.ipc.invalidation.external.client.android.service.Response.Status;
-
-import android.app.Service;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.RemoteException;
-
-/**
- * Abstract base class for implementing the Android invalidation service. The service implements the
- * set of actions defined in {@link Action}. For each supported action, the service will extract the
- * action parameters and invoke an abstract methods that will be implemented by subclasses to
- * provide the action-specific processing.
- * <p>
- * This class acquires a lock before calling into the subclass and releases it after the call.
- * It also ensures that no call into the subclass will be made after the service has been destroyed.
- * <p>
- * The class also provides {@code sendEvent} methods that can be used to generate events back to the
- * client.
- *
- */
-public abstract class AbstractInvalidationService extends Service {
-
-  private static final Logger logger = AndroidLogger.forTag("InvService");
-
-  /**
-   * Simple service stub that delegates back to methods on the service.
-   */
-  private final InvalidationService.Stub serviceBinder = new InvalidationService.Stub() {
-
-    @Override
-    public void handleRequest(Bundle input, Bundle output) {
-      AbstractInvalidationService.this.handleRequest(input, output);
-    }
-  };
-
-  /** Lock over all state in this class. */
-  final Object lock = new Object();
-
-  /** Whether the service is in the created state. */
-  private boolean isCreated = false;
-
-  @Override
-  public void onCreate() {
-    synchronized (lock) {
-      super.onCreate();
-      logger.fine("onCreate: %s", this.getClass());
-      this.isCreated = true;
-    }
-  }
-
-  @Override
-  public void onDestroy() {
-    synchronized (lock) {
-      logger.fine("onDestroy: %s", this.getClass());
-      this.isCreated = false;
-      super.onDestroy();
-    }
-  }
-
-  @Override
-  public int onStartCommand(Intent intent, int flags, int startId) {
-    return START_NOT_STICKY;
-  }
-
-  @Override
-  public IBinder onBind(Intent intent) {
-    return serviceBinder;
-  }
-
-  /** Returns whether the service is started. */
-  boolean isCreatedForTest() {
-    synchronized (lock) {
-      return isCreated;
-    }
-  }
-
-  protected void handleRequest(Bundle input, Bundle output) {
-    synchronized (lock) {
-      if (!isCreated) {
-        logger.warning("Dropping bundle since not created: %s", input);
-        return;
-      }
-      Request request = new Request(input);
-      Response.Builder response = Response.newBuilder(request.getActionOrdinal(), output);
-      Action action = request.getAction();
-      logger.fine("%s request from %s", action, request.getClientKey());
-      try {
-        switch(action) {
-          case CREATE:
-            create(request, response);
-            break;
-          case RESUME:
-            resume(request, response);
-            break;
-          case START:
-            start(request, response);
-            break;
-          case STOP:
-            stop(request, response);
-            break;
-          case REGISTER:
-            register(request, response);
-            break;
-          case UNREGISTER:
-            unregister(request, response);
-            break;
-          case ACKNOWLEDGE:
-            acknowledge(request, response);
-            break;
-          case DESTROY:
-            destroy(request, response);
-            break;
-          default:
-            throw new IllegalStateException("Unknown action:" + action);
-        }
-      } catch (Exception e) {
-        logger.severe("Client request error", e);
-        response.setStatus(Status.RUNTIME_ERROR); // Subclass might already have set status.
-        response.setException(e);
-      }
-    }
-  }
-
-  protected abstract void create(Request request, Response.Builder response);
-
-  protected abstract void resume(Request request, Response.Builder response);
-
-  protected abstract void start(Request request, Response.Builder response);
-
-  protected abstract void stop(Request request, Response.Builder response);
-
-  protected abstract void register(Request request, Response.Builder response);
-
-  protected abstract void unregister(Request request, Response.Builder response);
-
-  protected abstract void acknowledge(Request request, Response.Builder response);
-
-  protected abstract void destroy(Request request, Response.Builder response);
-
-  /**
-   * Send event messages to application clients and provides common processing
-   * of the response.
-   */
-  protected void sendEvent(ListenerService listenerService, Event event) {
-    try {
-      logger.fine("Sending %s event", event.getAction());
-      Bundle responseBundle = new Bundle();
-      listenerService.handleEvent(event.getBundle(), responseBundle);
-
-      // Wrap the response bundle and throw on any failure from the client
-      Response response = new Response(responseBundle);
-      response.warnOnFailure();
-    } catch (RemoteException exception) {
-      logger.severe("Unable to send event", exception);
-      throw new RuntimeException("Unable to send event", exception);
-    }
-  }
-}
diff --git a/java/com/google/ipc/invalidation/ticl/android/AndroidC2DMConstants.java b/java/com/google/ipc/invalidation/ticl/android/AndroidC2DMConstants.java
deleted file mode 100644
index 184ba9c..0000000
--- a/java/com/google/ipc/invalidation/ticl/android/AndroidC2DMConstants.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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.android;
-
-/**
- * Defines constants related to Invalidation C2DM messages.
- *
- */
-public class AndroidC2DMConstants {
-
-  /**
-   * The default account name associated with delivered C2DM messages.  Alternate sender IDs
-   * may be used when sharing C2DM within an application.
-   */
-  public static final String SENDER_ID = "[email protected]";
-
-  /**
-   * The prefix that is added to data items when C2DM messages are generated.  This prefix
-   * <b>does not</b> appear on the data items in the received C2DM intent extra bundle.
-   */
-  public static final String DATA_PREFIX = "data.";
-
-  /** Name of C2DM parameter containing the client key. */
-  public static final String CLIENT_KEY_PARAM = "tid";
-
-  /**
-   * Name of C2DM parameter containing message content.  If not set, data is not present. (We drop
-   * it if it is too big.)
-   */
-  public static final String CONTENT_PARAM = "content";
-
-  /** Name of the C2DM parameter containing an opaque token to be echoed on HTTP requests. */
-  public static final String ECHO_PARAM = "echo-token";
-}
diff --git a/java/com/google/ipc/invalidation/ticl/android/AndroidChannel.java b/java/com/google/ipc/invalidation/ticl/android/AndroidChannel.java
deleted file mode 100644
index 091fb5f..0000000
--- a/java/com/google/ipc/invalidation/ticl/android/AndroidChannel.java
+++ /dev/null
@@ -1,462 +0,0 @@
-/*
- * 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.android;
-
-import com.google.android.gcm.GCMRegistrar;
-import com.google.common.base.Preconditions;
-import com.google.ipc.invalidation.common.CommonProtos2;
-import com.google.ipc.invalidation.external.client.SystemResources;
-import com.google.ipc.invalidation.external.client.SystemResources.Logger;
-import com.google.ipc.invalidation.external.client.SystemResources.NetworkChannel;
-import com.google.ipc.invalidation.external.client.android.service.AndroidLogger;
-import com.google.ipc.invalidation.ticl.TestableNetworkChannel;
-import com.google.ipc.invalidation.util.ExponentialBackoffDelayGenerator;
-import com.google.protobuf.InvalidProtocolBufferException;
-import com.google.protos.ipc.invalidation.AndroidChannel.AddressedAndroidMessage;
-import com.google.protos.ipc.invalidation.AndroidChannel.MajorVersion;
-import com.google.protos.ipc.invalidation.ChannelCommon.NetworkEndpointId;
-import com.google.protos.ipc.invalidation.ClientProtocol.Version;
-
-import android.accounts.AccountManager;
-import android.accounts.AccountManagerCallback;
-import android.accounts.AccountManagerFuture;
-import android.accounts.AuthenticatorException;
-import android.accounts.OperationCanceledException;
-import android.content.Context;
-import android.net.http.AndroidHttpClient;
-import android.os.Build;
-import android.os.Bundle;
-import android.util.Base64;
-
-import org.apache.http.client.HttpClient;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Random;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.atomic.AtomicInteger;
-
-
-/**
- * Provides a bidirectional channel for Android devices using GCM (data center to device) and the
- * Android HTTP frontend (device to data center). The android channel computes a network endpoint id
- * based upon the GCM registration ID for the containing application ID and the client key of the
- * client using the channel. If an attempt is made to send messages on the channel before a GCM
- * registration ID has been assigned, it will temporarily buffer the outbound messages and send them
- * when the registration ID is eventually assigned.
- *
- */
-class AndroidChannel extends AndroidChannelBase implements TestableNetworkChannel {
-
-  private static final Logger logger = AndroidLogger.forTag("InvChannel");
-
-  /**
-   * The maximum number of outbound messages that will be buffered while waiting for async delivery
-   * of the GCM registration ID and authentication token.   The general flow for a new client is
-   * that an 'initialize' message is sent (and resent on a timed interval) until a session token is
-   * sent back and this just prevents accumulation a large number of initialize messages (and
-   * consuming memory) in a long delay or failure scenario.
-   */
-  private static final int MAX_BUFFERED_MESSAGES = 10;
-
-  /** The channel version expected by this channel implementation */
-  
-  static final Version CHANNEL_VERSION =
-      CommonProtos2.newVersion(MajorVersion.INITIAL.getNumber(), 0);
-
-  /** How to long to wait initially before retrying a failed auth token request. */
-  private static final int INITIAL_AUTH_TOKEN_RETRY_DELAY_MS = 1 * 1000;  // 1 second
-
-  /** Largest exponential backoff factor to use for auth token retries. */
-  private static final int MAX_AUTH_TOKEN_RETRY_FACTOR = 60 * 60 * 12; // 12 hours
-
-  /** Number of C2DM messages for unknown clients. */
-  
-  static final AtomicInteger numGcmInvalidClients = new AtomicInteger();
-
-  /** Invalidation client proxy using the channel. */
-  private final AndroidClientProxy proxy;
-
-  /** Android context used to retrieve registration IDs. */
-  private final Context context;
-
-  /** System resources for this channel */
-  private SystemResources resources;
-
-  /**
-   * When set, this registration ID is used rather than checking
-   * {@link GCMRegistrar#getRegistrationId}. It should not be read directly: call
-   * {@link #getRegistrationId} instead.
-   */
-  private String registrationIdForTest;
-
-  /** The authentication token that can be used in channel requests to the server */
-  private String authToken;
-
-  /** Listener for network events. */
-  private NetworkChannel.NetworkListener listener;
-
-  // TODO: Add code to track time of last network activity (in either direction)
-  // so inactive clients can be detected and periodically flushed from memory.
-
-  /**
-   * List that holds outbound messages while waiting for a registration ID.   Allocated on
-   * demand since it is only needed when there is no registration id.
-   */
-  private List<byte[]> pendingMessages = null;
-
-  /**
-   * Testing only flag that disables interactions with the AcccountManager for mock tests.
-   */
-   static boolean disableAccountManager = false;
-
-  /**
-   * Returns the default HTTP client to use for requests from the channel based upon its execution
-   * context.  The format of the User-Agent string is "<application-pkg>(<android-release>)".
-   */
-  static AndroidHttpClient getDefaultHttpClient(Context context) {
-    return AndroidHttpClient.newInstance(
-       context.getApplicationInfo().className + "(" + Build.VERSION.RELEASE + ")");
-  }
-
-  /** Executor used for HTTP calls to send messages to . */
-  
-  final ExecutorService scheduler = Executors.newSingleThreadExecutor();
-
-  /**
-   * Creates a new AndroidChannel.
-   *
-   * @param proxy the client proxy associated with the channel
-   * @param httpClient the HTTP client to use to communicate with the Android invalidation frontend
-   * @param context Android context
-   */
-  AndroidChannel(AndroidClientProxy proxy, HttpClient httpClient, Context context) {
-    super(httpClient, proxy.getAuthType(), proxy.getService().getChannelUrl());
-    this.proxy = Preconditions.checkNotNull(proxy);
-    this.context = Preconditions.checkNotNull(context);
-  }
-
-  /**
-   * Returns the GCM registration ID associated with the channel. Checks the {@link GCMRegistrar}
-   * unless {@link #setRegistrationIdForTest} has been called.
-   */
-  String getRegistrationId() {
-    String registrationId = (registrationIdForTest != null) ? registrationIdForTest :
-        GCMRegistrar.getRegistrationId(context);
-
-    // Callers check for null registration ID rather than "null or empty", so replace empty strings
-    // with null here.
-    if ("".equals(registrationId)) {
-      registrationId = null;
-    }
-    return registrationId;
-  }
-
-  /** Returns the client proxy that is using the channel */
-   AndroidClientProxy getClientProxy() {
-    return proxy;
-  }
-
-  /**
-   * Retrieves the list of pending messages in the channel (or {@code null} if there are none).
-   */
-   List<byte[]> getPendingMessages() {
-    return pendingMessages;
-  }
-
-  @Override
-  
-  protected String getAuthToken() {
-    return authToken;
-  }
-
-  /** A completion callback for an asynchronous operation. */
-  interface CompletionCallback {
-    void success();
-    void failure();
-  }
-
-  /** An asynchronous runnable that calls a completion callback. */
-  interface AsyncRunnable {
-    void run(CompletionCallback callback);
-  }
-
-  /**
-   * A utility function to run an async runnable with exponential backoff after failures.
-   * @param runnable the asynchronous runnable.
-   * @param scheduler used to schedule retries.
-   * @param backOffGenerator a backoff generator that returns how to long to wait between retries.
-   *     The client must pass a new instance or reset the backoff generator before calling this
-   *     method.
-   */
-  
-  static void retryUntilSuccessWithBackoff(final SystemResources.Scheduler scheduler,
-      final ExponentialBackoffDelayGenerator backOffGenerator, final AsyncRunnable runnable) {
-    logger.fine("Running %s", runnable);
-    runnable.run(new CompletionCallback() {
-        @Override
-        public void success() {
-          logger.fine("%s succeeded", runnable);
-        }
-
-        @Override
-        public void failure() {
-          int nextDelay = backOffGenerator.getNextDelay();
-          logger.fine("%s failed, retrying after %s ms", nextDelay);
-          scheduler.schedule(nextDelay, new Runnable() {
-            @Override
-            public void run() {
-              retryUntilSuccessWithBackoff(scheduler, backOffGenerator, runnable);
-            }
-          });
-        }
-    });
-  }
-
-  /**
-   * Initiates acquisition of an authentication token that can be used with channel HTTP requests.
-   * Android token acquisition is asynchronous since it may require HTTP interactions with the
-   * ClientLogin servers to obtain the token.
-   */
-  @SuppressWarnings("deprecation")
-  
-  synchronized void requestAuthToken(final CompletionCallback callback) {
-    // If there is currently no token and no pending request, initiate one.
-    if (disableAccountManager) {
-      logger.fine("Not requesting auth token since account manager disabled");
-      return;
-    }
-    if (authToken == null) {
-      // Ask the AccountManager for the token, with a pending future to store it on the channel
-      // once available.
-      final AndroidChannel theChannel = this;
-      AccountManager accountManager = AccountManager.get(proxy.getService());
-      accountManager.getAuthToken(proxy.getAccount(), proxy.getAuthType(), true,
-          new AccountManagerCallback<Bundle>() {
-            @Override
-            public void run(AccountManagerFuture<Bundle> future) {
-              try {
-                Bundle result = future.getResult();
-                if (result.containsKey(AccountManager.KEY_INTENT)) {
-                  // TODO: Handle case where there are no authentication
-                  // credentials associated with the client account
-                  logger.severe("Token acquisition requires user login");
-                  callback.success(); // No further retries.
-                }
-                setAuthToken(result.getString(AccountManager.KEY_AUTHTOKEN));
-              } catch (OperationCanceledException exception) {
-                logger.warning("Auth cancelled", exception);
-                // TODO: Send error to client
-              } catch (AuthenticatorException exception) {
-                logger.warning("Auth error acquiring token", exception);
-                callback.failure();
-              } catch (IOException exception) {
-                logger.warning("IO Exception acquiring token", exception);
-                callback.failure();
-              }
-            }
-      }, null);
-    } else {
-      logger.fine("Auth token request already pending");
-      callback.success();
-    }
-  }
-
-  /*
-   * Updates the registration ID for this channel, flushing any pending outbound messages that
-   * were waiting for an id.
-   */
-  synchronized void setRegistrationIdForTest(String updatedRegistrationId) {
-    // Synchronized to avoid concurrent access to pendingMessages
-    if (registrationIdForTest != updatedRegistrationId) {
-      logger.fine("Setting registration ID for test for client key %s", proxy.getClientKey());
-      registrationIdForTest = updatedRegistrationId;
-      informRegistrationIdChanged();
-    }
-  }
-
-  /**
-   * Call to inform the Android channel that the registration ID has changed. May kick loose some
-   * pending outbound messages.
-   */
-  synchronized void informRegistrationIdChanged() {
-    checkReady();
-  }
-
-  /**
-   * Sets the authentication token to use for HTTP requests to the invalidation frontend and
-   * flushes any pending messages (if appropriate).
-   *
-   * @param authToken the authentication token
-   */
-  synchronized void setAuthToken(String authToken) {
-    logger.fine("Auth token received fo %s", proxy.getClientKey());
-    this.authToken = authToken;
-    checkReady();
-  }
-
-  @Override
-  public void setListener(NetworkChannel.NetworkListener listener) {
-    this.listener = Preconditions.checkNotNull(listener);
-  }
-
-  @Override
-  public synchronized void sendMessage(final byte[] outgoingMessage) {
-    // synchronized to avoid concurrent access to pendingMessages
-
-    // If there is no registration id, we cannot compute a network endpoint id. If there is no
-    // auth token, then we cannot authenticate the send request.  Defer sending messages until both
-    // are received.
-    String registrationId = getRegistrationId();
-    if ((registrationId == null) || (authToken == null)) {
-      if (pendingMessages == null) {
-        pendingMessages = new ArrayList<byte[]>();
-      }
-      logger.fine("Buffering outbound message: hasRegId: %s, hasAuthToken: %s",
-          registrationId != null, authToken != null);
-      if (pendingMessages.size() < MAX_BUFFERED_MESSAGES) {
-        pendingMessages.add(outgoingMessage);
-      } else {
-        logger.warning("Exceeded maximum number of buffered messages, dropping outbound message");
-      }
-      return;
-    }
-
-    // Do the actual HTTP I/O on a separate thread, since we may be called on the main
-    // thread for the application.
-    scheduler.execute(new Runnable() {
-      @Override
-      public void run() {
-        if (resources.isStarted()) {
-          deliverOutboundMessage(outgoingMessage);
-        } else {
-          logger.warning("Dropping outbound messages because resources are stopped");
-        }
-      }
-    });
-  }
-
-  /**
-   * Called when either the registration or authentication token has been received to check to
-   * see if channel is ready for network activity.  If so, the status receiver is notified and
-   * any pending messages are flushed.
-   */
-  private synchronized void checkReady() {
-    String registrationId = getRegistrationId();
-    if ((registrationId != null) && (authToken != null)) {
-
-      logger.fine("Enabling network endpoint: %s", getWebEncodedEndpointId());
-
-      // Notify the network listener that we are now network enabled
-      if (listener != null) {
-        listener.onOnlineStatusChange(true);
-      }
-
-      // Flush any pending messages
-      if (pendingMessages != null) {
-        for (byte [] message : pendingMessages) {
-          sendMessage(message);
-        }
-        pendingMessages = null;
-      }
-    }
-  }
-
-  void receiveMessage(byte[] inboundMessage) {
-    try {
-      AddressedAndroidMessage addrMessage = AddressedAndroidMessage.parseFrom(inboundMessage);
-      tryDeliverMessage(addrMessage);
-    } catch (InvalidProtocolBufferException exception) {
-      logger.severe("Failed decoding AddressedAndroidMessage as C2DM payload", exception);
-    }
-  }
-
-  /**
-   * Delivers the payload of {@code addrMessage} to the {@code callbackReceiver} if the client key
-   * of the addressed message matches that of the {@link #proxy}.
-   */
-  @Override
-  protected void tryDeliverMessage(AddressedAndroidMessage addrMessage) {
-    String clientKey = proxy.getClientKey();
-    if (addrMessage.getClientKey().equals(clientKey)) {
-      logger.fine("Deliver to %s message %s", clientKey, addrMessage);
-      listener.onMessageReceived(addrMessage.getMessage().toByteArray());
-    } else {
-      logger.severe("Not delivering message due to key mismatch: %s vs %s",
-          addrMessage.getClientKey(), clientKey);
-      numGcmInvalidClients.incrementAndGet();
-    }
-  }
-
-  /** Returns the web encoded version of the channel network endpoint ID for HTTP requests. */
-  @Override
-  protected String getWebEncodedEndpointId() {
-    NetworkEndpointId networkEndpointId = getNetworkId();
-    return Base64.encodeToString(networkEndpointId.toByteArray(),
-        Base64.URL_SAFE | Base64.NO_WRAP  | Base64.NO_PADDING);
-  }
-
-  @Override
-  public void setSystemResources(SystemResources resources) {
-    this.resources = resources;
-
-    // Prefetch the auth sub token.  Since this might require an HTTP round trip, we do this
-    // as soon as the resources are available.
-    // TODO: Find a better place to fetch the auth token; this method
-    // doesn't sound like one that should be doing work.
-    retryUntilSuccessWithBackoff(resources.getInternalScheduler(),
-        new ExponentialBackoffDelayGenerator(
-            new Random(), INITIAL_AUTH_TOKEN_RETRY_DELAY_MS, MAX_AUTH_TOKEN_RETRY_FACTOR),
-        new AsyncRunnable() {
-          @Override
-          public void run(CompletionCallback callback) {
-            requestAuthToken(callback);
-          }
-        });
-  }
-
-  @Override
-  public NetworkEndpointId getNetworkIdForTest() {
-    return getNetworkId();
-  }
-
-  @Override
-  protected Logger getLogger() {
-    return resources.getLogger();
-  }
-
-  private NetworkEndpointId getNetworkId() {
-    String registrationId = getRegistrationId();
-    return CommonProtos2.newAndroidEndpointId(registrationId, proxy.getClientKey(),
-        proxy.getService().getPackageName(), CHANNEL_VERSION);
-  }
-
-  ExecutorService getExecutorServiceForTest() {
-    return scheduler;
-  }
-
-  @Override
-  void setHttpClientForTest(HttpClient client) {
-    if (this.httpClient instanceof AndroidHttpClient) {
-      // Release the previous client if any.
-      ((AndroidHttpClient) this.httpClient).close();
-    }
-    super.setHttpClientForTest(client);
-  }
-}
diff --git a/java/com/google/ipc/invalidation/ticl/android/AndroidChannelBase.java b/java/com/google/ipc/invalidation/ticl/android/AndroidChannelBase.java
deleted file mode 100644
index 6dd106b..0000000
--- a/java/com/google/ipc/invalidation/ticl/android/AndroidChannelBase.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * 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.android;
-
-import com.google.common.base.Preconditions;
-import com.google.ipc.invalidation.external.client.SystemResources.Logger;
-import com.google.protos.ipc.invalidation.AndroidChannel.AddressedAndroidMessage;
-
-import org.apache.http.client.ClientProtocolException;
-import org.apache.http.client.HttpClient;
-import org.apache.http.client.methods.HttpPost;
-import org.apache.http.entity.ByteArrayEntity;
-import org.apache.http.impl.client.BasicResponseHandler;
-
-import java.io.IOException;
-
-
-/**
- * Implementation of the HTTP communication used by {@code AndroidChannel}. Factored into
- * a separate class that can be run outside the Android environment to improve testing.
- *
- */
-
-public abstract class AndroidChannelBase {
-  /** Http client to use when making requests to . */
-  HttpClient httpClient;
-
-  /** Authentication type for  frontends. */
-  private final String authType;
-
-  /** URL of the frontends. */
-  private final String channelUrl;
-
-  /** The token that will be echoed to the data center in the headers of all HTTP requests. */
-  private String echoToken = null;
-
-  /**
-   * Creates an instance that uses {@code httpClient} to send requests to {@code channelUrl}
-   * using an auth type of {@code authType}.
-   */
-  protected AndroidChannelBase(HttpClient httpClient, String authType, String channelUrl) {
-    this.httpClient = httpClient;
-    this.authType = authType;
-    this.channelUrl = channelUrl;
-  }
-
-  /** Sends {@code outgoingMessage} to . */
-  void deliverOutboundMessage(final byte[] outgoingMessage) {
-    getLogger().fine("Delivering outbound message: %s bytes", outgoingMessage.length);
-    StringBuilder target = new StringBuilder();
-
-    // Build base URL that targets the inbound request service with the encoded network endpoint id
-    target.append(channelUrl);
-    target.append(AndroidHttpConstants.REQUEST_URL);
-    target.append(getWebEncodedEndpointId());
-
-    // Add query parameter indicating the service to authenticate against
-    target.append('?');
-    target.append(AndroidHttpConstants.SERVICE_PARAMETER);
-    target.append('=');
-    target.append(authType);
-
-    // Construct entity containing the outbound protobuf msg
-    ByteArrayEntity contentEntity = new ByteArrayEntity(outgoingMessage);
-    contentEntity.setContentType(AndroidHttpConstants.PROTO_CONTENT_TYPE);
-
-    // Construct POST request with the entity content and appropriate authorization
-    HttpPost httpPost = new HttpPost(target.toString());
-    httpPost.setEntity(contentEntity);
-    setPostHeaders(httpPost);
-    try {
-      String response = httpClient.execute(httpPost, new BasicResponseHandler());
-    } catch (ClientProtocolException exception) {
-      // TODO: Distinguish between key HTTP error codes and handle more specifically
-      // where appropriate.
-      getLogger().warning("Error from server on request: %s", exception);
-    } catch (IOException exception) {
-      getLogger().warning("Error writing request: %s", exception);
-    } catch (RuntimeException exception) {
-      getLogger().warning("Runtime exception writing request: %s", exception);
-    }
-  }
-
-  /** Sets the Authorization and echo headers on {@code httpPost}. */
-  private void setPostHeaders(HttpPost httpPost) {
-    httpPost.setHeader("Authorization", "GoogleLogin auth=" + getAuthToken());
-    if (echoToken != null) {
-      // If we have a token to echo to the server, echo it.
-      httpPost.setHeader(AndroidHttpConstants.ECHO_HEADER, echoToken);
-    }
-  }
-
-  /**
-   * If {@code echoToken} is not {@code null}, updates the token that will be sent in the header
-   * of all HTTP requests.
-   */
-  void updateEchoToken(String echoToken) {
-    if (echoToken != null) {
-      this.echoToken = echoToken;
-    }
-  }
-
-  /** Returns the token that will be sent in the header of all HTTP requests. */
-  String getEchoTokenForTest() {
-    return this.echoToken;
-  }
-
-  /** Sets the HTTP client to {@code client}. */
-  void setHttpClientForTest(HttpClient client) {
-    this.httpClient = Preconditions.checkNotNull(client);
-  }
-
-  /** Returns the base-64-encoded network endpoint id for the client. */
-  protected abstract String getWebEncodedEndpointId();
-
-  /** Returns the current authentication token for the client for web requests to . */
-  protected abstract String getAuthToken();
-
-  /** Returns the logger to use. */
-  protected abstract Logger getLogger();
-
-  /** Attempts to deliver a {@code message} from  to the local client. */
-  protected abstract void tryDeliverMessage(AddressedAndroidMessage message);
-}
diff --git a/java/com/google/ipc/invalidation/ticl/android/AndroidClientManager.java b/java/com/google/ipc/invalidation/ticl/android/AndroidClientManager.java
deleted file mode 100644
index c2dd46e..0000000
--- a/java/com/google/ipc/invalidation/ticl/android/AndroidClientManager.java
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * 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.android;
-
-import com.google.ipc.invalidation.external.client.SystemResources.Logger;
-import com.google.ipc.invalidation.external.client.android.service.AndroidClientException;
-import com.google.ipc.invalidation.external.client.android.service.AndroidLogger;
-import com.google.ipc.invalidation.external.client.android.service.Response.Status;
-import com.google.ipc.invalidation.ticl.InvalidationClientCore;
-import com.google.ipc.invalidation.util.TypedUtil;
-import com.google.protos.ipc.invalidation.ClientProtocol.ClientConfigP;
-
-import android.accounts.Account;
-import android.content.Context;
-import android.content.Intent;
-
-import java.util.HashMap;
-import java.util.Map;
-
-
-/**
- * Manages active client instances for the Android invalidation service. The client manager contains
- * the code to create, persist, load, and lookup client instances, as well as handling the
- * propagation of any C2DM registration notifications to active clients.
- *
- */
-public class AndroidClientManager {
-
-  /** Logger */
-  private static final Logger logger = AndroidLogger.forTag("InvClientManager");
-
-  /**
-   * The client configuration used creating new invalidation client instances.   This is normally
-   * a constant but may be varied for testing.
-   */
-  private static ClientConfigP clientConfig = InvalidationClientCore.createConfig().build();
-
-  /** The invalidation service associated with this manager */
-  private final AndroidInvalidationService service;
-
-  /**
-   * When set, this registration ID is used rather than the ID returned by
-   * {@code GCMRegistrar.getRegistrationId()}.
-   */
-  private static String registrationIdForTest;
-
-  /** A map from client key to client proxy instances for in-memory client instances */
-  private final Map<String, AndroidClientProxy> clientMap =
-      new HashMap<String, AndroidClientProxy>();
-
-  /** All client manager operations are synchronized on this lock */
-  private final Object lock = new Object();
-
-  /** Creates a new client manager instance associated with the provided service */
-  AndroidClientManager(AndroidInvalidationService service) {
-    this.service = service;
-  }
-
-  /**
-   * Returns the number of managed clients.
-   */
-  int getClientCount() {
-    synchronized (lock) {
-      return clientMap.size();
-    }
-  }
-
-  /**
-   * Creates a new Android client proxy with the provided attributes. Before creating, will check to
-   * see if there is an existing client with attributes that match and return it if found. If there
-   * is an existing client with the same key but attributes that do not match, an exception will be
-   * thrown. If no client with a matching key exists, a new client proxy will be created and
-   * returned.
-   *
-   * @param clientKey key that uniquely identifies the client on the device.
-   * @param clientType client type.
-   * @param account user account associated with the client.
-   * @param authType authentication type for the client.
-   * @param eventIntent intent that can be used to bind to an event listener for the client.
-   * @return an android invalidation client instance representing the client.
-   */
-  AndroidClientProxy create(String clientKey, int clientType, Account account, String authType,
-      Intent eventIntent) {
-    synchronized (lock) {
-
-      // First check to see if an existing client is found
-      AndroidClientProxy proxy = lookup(clientKey);
-      if (proxy != null) {
-        if (!proxy.getAccount().equals(account) || !proxy.getAuthType().equals(authType)) {
-          throw new AndroidClientException(
-              Status.INVALID_CLIENT, "Account does not match existing client");
-        }
-        return proxy;
-      }
-
-      // If not found, create a new client proxy instance to represent the client.
-      AndroidStorage store = createAndroidStorage(service, clientKey);
-      store.create(clientType, account, authType, eventIntent);
-      proxy = new AndroidClientProxy(service, store, clientConfig);
-      if (registrationIdForTest != null) {
-        proxy.getChannel().setRegistrationIdForTest(registrationIdForTest);
-      }
-      clientMap.put(clientKey, proxy);
-      logger.fine("Client %s created", clientKey);
-      return proxy;
-    }
-  }
-
-  /**
-   * Retrieves an existing client that matches the provided key, loading it if necessary. If no
-   * matching client can be found, an exception is thrown.
-   *
-   * @param clientKey the client key for the client to retrieve.
-   * @return the matching client instance
-   */
-  AndroidClientProxy get(String clientKey) {
-    synchronized (lock) {
-      return lookup(clientKey);
-    }
-  }
-
-  /**
-   * Removes any client proxy instance associated with the provided key from memory but leaves the
-   * instance persisted. The client may subsequently be loaded again by calling {@code #get}.
-   *
-   * @param clientKey the client key of the instance to remove from memory.
-   */
-  void remove(String clientKey) {
-    synchronized (lock) {
-      // Remove the proxy from the managed set and release any associated resources
-      AndroidClientProxy proxy = clientMap.remove(clientKey);
-      if (proxy != null) {
-        proxy.release();
-      }
-    }
-  }
-
-  /**
-   * Looks up the client proxy instance associated with the provided key and returns it (or {@code
-   * null} if not found).
-   *
-   * @param clientKey the client key to look up
-   * @return the client instance or {@code null}.
-   */
-  
-  AndroidClientProxy lookup(String clientKey) {
-    synchronized (lock) {
-      // See if the client is already resident in memory
-      AndroidClientProxy client = clientMap.get(clientKey);
-      if (client == null) {
-        // Attempt to load the client from the store
-        AndroidStorage storage = createAndroidStorage(service, clientKey);
-        if (storage.load()) {
-          logger.fine("Client %s loaded from disk", clientKey);
-          client = new AndroidClientProxy(service, storage, clientConfig);
-          clientMap.put(clientKey, client);
-        }
-      }
-      return client;
-    }
-  }
-
-  /**
-   * Sets the GCM registration ID that should be used for all managed clients (new and existing).
-   */
-  void informRegistrationIdChanged() {
-    synchronized (lock) {
-      // Propagate the value to all existing clients
-      for (AndroidClientProxy proxy : clientMap.values()) {
-        proxy.getChannel().informRegistrationIdChanged();
-      }
-    }
-  }
-
-  /**
-   * Releases all managed clients and drops them from the managed set.
-   */
-  void releaseAll() {
-    synchronized (lock) {
-      for (AndroidClientProxy clientProxy : clientMap.values()) {
-        clientProxy.release();
-      }
-      clientMap.clear();
-    }
-  }
-
-  /**
-   * Returns an android storage instance for managing client state.
-   */
-  
-  protected AndroidStorage createAndroidStorage(Context context, String clientKey) {
-    synchronized (lock) {
-      return new AndroidStorage(context, clientKey);
-    }
-  }
-
-  
-  static ClientConfigP setConfigForTest(ClientConfigP newConfig) {
-    logger.info("Setting client configuration: %s", newConfig);
-    ClientConfigP currentConfig = clientConfig;
-    clientConfig = newConfig;
-    return clientConfig;
-  }
-
-  
-  public static void setRegistrationIdForTest(String registrationIdForTest) {
-    AndroidClientManager.registrationIdForTest = registrationIdForTest;
-  }
-
-  /** Returns whether all loaded clients are stopped. */
-  public boolean areAllClientsStopped() {
-    synchronized (lock) {
-      for (AndroidClientProxy proxy : clientMap.values()) {
-        if (proxy.isStarted()) {
-          return false;
-        }
-      }
-      return true;
-    }
-  }
-
-  /** Returns whether the client with key {@code clientKey} is in memory. */
-  public boolean isLoadedForTest(String clientKey) {
-    synchronized (lock) {
-      return TypedUtil.containsKey(clientMap, clientKey);
-    }
-  }
-}
diff --git a/java/com/google/ipc/invalidation/ticl/android/AndroidClientProxy.java b/java/com/google/ipc/invalidation/ticl/android/AndroidClientProxy.java
deleted file mode 100644
index 927e71b..0000000
--- a/java/com/google/ipc/invalidation/ticl/android/AndroidClientProxy.java
+++ /dev/null
@@ -1,387 +0,0 @@
-/*
- * 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.android;
-
-import com.google.common.base.Preconditions;
-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.android.AndroidInvalidationClient;
-import com.google.ipc.invalidation.external.client.android.service.AndroidLogger;
-import com.google.ipc.invalidation.external.client.android.service.Event;
-import com.google.ipc.invalidation.external.client.android.service.ListenerBinder;
-import com.google.ipc.invalidation.external.client.android.service.ListenerService;
-import com.google.ipc.invalidation.external.client.android.service.ServiceBinder.BoundWork;
-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.InvalidationClientImpl;
-import com.google.protos.ipc.invalidation.AndroidState.ClientMetadata;
-import com.google.protos.ipc.invalidation.ClientProtocol.ClientConfigP;
-
-import android.accounts.Account;
-import android.content.Context;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.net.http.AndroidHttpClient;
-
-import java.util.Collection;
-import java.util.Random;
-
-
-/**
- * A bidirectional client proxy that wraps and delegates requests to a TICL instance and routes
- * events generated by the TICL back to the associated listener.
- *
- */
-class AndroidClientProxy implements AndroidInvalidationClient {
-
-  private static final Logger logger = AndroidLogger.forTag("InvClientProxy");
-
-  /**
-   * A reverse proxy for delegating raised invalidation events back to the client (via the
-   * associated service).
-   */
-  class AndroidListenerProxy implements InvalidationListener {
-
-    /** Binder that can be use to bind back to event listener service */
-    
-    final ListenerBinder binder;
-
-    /**
-     * Creates a new listener reverse proxy.
-     */
-    private AndroidListenerProxy() {
-      this.binder = new ListenerBinder(service, Event.LISTENER_INTENT, metadata.getListenerClass());
-    }
-
-    @Override
-    public void ready(InvalidationClient client) {
-      Event event = Event.newBuilder(Event.Action.READY).setClientKey(clientKey).build();
-      sendEvent(event);
-    }
-
-    @Override
-    public void informRegistrationStatus(
-        InvalidationClient client, ObjectId objectId, RegistrationState regState) {
-      Event event = Event.newBuilder(Event.Action.INFORM_REGISTRATION_STATUS)
-          .setClientKey(clientKey).setObjectId(objectId).setRegistrationState(regState).build();
-      sendEvent(event);
-    }
-
-    @Override
-    public void informRegistrationFailure(
-        InvalidationClient client, ObjectId objectId, boolean isTransient, String errorMessage) {
-      Event event = Event.newBuilder(Event.Action.INFORM_REGISTRATION_FAILURE)
-          .setClientKey(clientKey).setObjectId(objectId).setIsTransient(isTransient)
-          .setError(errorMessage).build();
-      sendEvent(event);
-    }
-
-    @Override
-    public void invalidate(
-        InvalidationClient client, Invalidation invalidation, AckHandle ackHandle) {
-      Event event = Event.newBuilder(Event.Action.INVALIDATE)
-          .setClientKey(clientKey).setInvalidation(invalidation).setAckHandle(ackHandle).build();
-      sendEvent(event);
-    }
-
-    @Override
-    public void invalidateAll(InvalidationClient client, AckHandle ackHandle) {
-      Event event = Event.newBuilder(Event.Action.INVALIDATE_ALL)
-          .setClientKey(clientKey).setAckHandle(ackHandle).build();
-      sendEvent(event);
-    }
-
-    @Override
-    public void invalidateUnknownVersion(
-        InvalidationClient client, ObjectId objectId, AckHandle ackHandle) {
-      Event event = Event.newBuilder(Event.Action.INVALIDATE_UNKNOWN)
-          .setClientKey(clientKey).setObjectId(objectId).setAckHandle(ackHandle).build();
-      sendEvent(event);
-    }
-
-    @Override
-    public void reissueRegistrations(InvalidationClient client, byte[] prefix, int prefixLength) {
-      Event event = Event.newBuilder(Event.Action.REISSUE_REGISTRATIONS)
-          .setClientKey(clientKey).setPrefix(prefix, prefixLength).build();
-      sendEvent(event);
-    }
-
-    @Override
-    public void informError(InvalidationClient client, ErrorInfo errorInfo) {
-      Event event = Event.newBuilder(Event.Action.INFORM_ERROR)
-          .setClientKey(clientKey).setErrorInfo(errorInfo).build();
-      sendEvent(event);
-    }
-
-    /**
-     * Releases any resources associated with the proxy listener.
-     */
-    public void release() {
-      binder.release();
-    }
-
-    /**
-     * Send event messages to application clients and provides common processing of the response.
-     */
-    private void sendEvent(final Event event) {
-      binder.runWhenBound(new BoundWork<ListenerService>() {
-        @Override
-        public void run(ListenerService listenerService) {
-          logger.fine("Sending %s event to %s", event.getAction(), clientKey);
-          service.sendEvent(listenerService, event);
-        }
-      });
-    }
-  }
-
-  /** The service associated with this proxy */
-  private final AndroidInvalidationService service;
-
-  /** the client key for this client proxy */
-  private final String clientKey;
-
-  /** The invalidation client to delegate requests to */
-  
-  final InvalidationClient delegate;
-
-  /** The reverse listener proxy for this client proxy */
-  private final AndroidListenerProxy listener;
-
-  /** The stored state associated with this client */
-  private final ClientMetadata metadata;
-
-  /** The channel for this client */
-  private final AndroidChannel channel;
-
-  /** The system resources for this client */
-  private final SystemResources resources;
-
-  /** The HTTP client used by the underlying channel */
-  private final AndroidHttpClient httpClient;
-
-  /** {@code true} if client is started */
-  private boolean started;
-
-  /**
-   * Creates a new client proxy instance.
-   *
-   * @param service the service within which the client proxy is executing.
-   * @param storage the storage instance that contains client metadata and can be used to read or
-   *        write client properties.
-   */
-  AndroidClientProxy(AndroidInvalidationService service, AndroidStorage storage,
-      ClientConfigP config) {
-    this.service = service;
-    this.metadata = storage.getClientMetadata();
-    this.clientKey = metadata.getClientKey();
-    this.listener = new AndroidListenerProxy();
-    this.httpClient =  AndroidChannel.getDefaultHttpClient(service);
-
-    this.channel = new AndroidChannel(this, httpClient, service);
-    this.resources =
-        AndroidResourcesFactory.createResourcesBuilder(clientKey, channel, storage).build();
-    String applicationName = getApplicationNameWithVersion(service,
-        storage.getClientMetadata().getListenerPkg());
-    this.delegate = createClient(resources, metadata.getClientType(), clientKey.getBytes(),
-        applicationName, listener, config);
-  }
-
-  /**
-   * Returns the application name string to pass to the Ticl, computed as a combination of the
-   * listener package and the application version.
-   */
-  
-  static String getApplicationNameWithVersion(Context context, String listenerPackage) {
-    String appVersion = "unknown";
-    try {
-      PackageInfo packageInfo =
-          context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
-      String retrievedVersion = packageInfo.versionName;
-      if (retrievedVersion != null) {
-        appVersion = retrievedVersion;
-      }
-    } catch (NameNotFoundException exception) {
-      // AndroidLogger does not use setSystemResources, so it's safe to use the logger here.
-      logger.warning("Cannot retrieve current application version: %s", exception);
-    }
-    return listenerPackage + "#" + appVersion;
-  }
-
-  public final Account getAccount() {
-    return new Account(metadata.getAccountName(), metadata.getAccountType());
-  }
-
-  public final String getAuthType() {
-    return metadata.getAuthType();
-  }
-
-  @Override
-  public final String getClientKey() {
-    return metadata.getClientKey();
-  }
-
-  /** Returns the android service that is asociated with this proxy. */
-  final AndroidInvalidationService getService() {
-    return service;
-  }
-
-  /** Returns the network channel for this proxy. */
-  final AndroidChannel getChannel() {
-    return channel;
-  }
-
-  /** Returns the underlying invalidation client instance or {@code null} */
-  
-  final InvalidationClient getDelegate() {
-    return delegate;
-  }
-
-  /** Returns the invalidation listener for this proxy */
-  
-  final AndroidListenerProxy getListener() {
-    return listener;
-  }
-
-  /** Returns the storage used by the proxy. */
- final AndroidStorage getStorage() {
-   return (AndroidStorage) resources.getStorage();
- }
-
-  boolean isStarted() {
-    return started;
-  }
-
-  @Override
-  public void start() {
-    if (started) {
-      logger.info("Not starting Ticl since already started");
-      return;
-    }
-    resources.start();
-    delegate.start();
-    started = true;
-  }
-
-  @Override
-  public void stop() {
-    // When a client is stopped, stop the TICL and its resources and remove it from the client
-    // manager.   This means that any subsequent requests (like another start) will be executed
-    // against a clean TICL instance w/ no preexisting state from before the stop.
-    if (!started) {
-      logger.info("Not stopping Ticl since already stopped");
-      return;
-    }
-    stopTicl();
-    resources.stop();
-    AndroidInvalidationService.getClientManager().remove(clientKey);
-  }
-
-  @Override
-  public void register(Collection<ObjectId> objectIds) {
-    delegate.register(objectIds);
-  }
-
-  @Override
-  public void register(ObjectId objectId) {
-    delegate.register(objectId);
-  }
-
-  @Override
-  public void unregister(Collection<ObjectId> objectIds) {
-    delegate.unregister(objectIds);
-  }
-
-  @Override
-  public void unregister(ObjectId objectId) {
-    delegate.unregister(objectId);
-  }
-
-  @Override
-  public void acknowledge(AckHandle ackHandle) {
-    delegate.acknowledge(ackHandle);
-  }
-
-  /**
-   * Called when the client proxy is being removed from memory and will no longer be in use.
-   * Releases any resources associated with the client proxy.
-   */
-  @Override
-  public void release() {
-    // Release the listener associated with the proxy
-    listener.release();
-
-    // Stop system resources associated with the client
-    if (resources.isStarted()) {
-      resources.stop();
-    }
-
-    // Close the HTTP client
-    httpClient.close();
-  }
-
-  @Override
-  public void destroy() {
-
-    // Stop the client if started.  This will also remove the client from the client manager
-    if (started) {
-      stop();
-    }
-
-    // Delete the storage associated with the client
-    AndroidStorage storage = (AndroidStorage) resources.getStorage();
-    storage.delete();
-
-    // Remove any cached instance for this client.
-    AndroidInvalidationService.getClientManager().remove(clientKey);
-  }
-
-  /**
-   * Creates a new InvalidationClient instance that the proxy will delegate requests to and listen
-   * for events from.
-   */
-  // Overridden by tests to inject mock clients or for listener interception
-  
-  InvalidationClient createClient(SystemResources resources, int clientType, byte[] clientName,
-      String applicationName, InvalidationListener listener, ClientConfigP config) {
-    // We always use C2DM, so set the channel-supports-offline-delivery bit on our config.
-    final ClientConfigP.Builder configBuilder;
-    if (config == null) {
-      configBuilder = InvalidationClientCore.createConfig();
-    } else {
-      configBuilder = ClientConfigP.newBuilder(config);
-    }
-    configBuilder.setChannelSupportsOfflineDelivery(true);
-    config = configBuilder.build();
-    Random random = new Random(resources.getInternalScheduler().getCurrentTimeMs());
-    return new InvalidationClientImpl(resources, random, clientType, clientName, config,
-        applicationName, listener);
-  }
-
-
-  /** Stops the underlying TICL instance but does not stop system resources. */
-  
-  void stopTicl() {
-    Preconditions.checkState(started);
-    delegate.stop();
-    started = false;
-  }
-}
diff --git a/java/com/google/ipc/invalidation/ticl/android/AndroidHttpConstants.java b/java/com/google/ipc/invalidation/ticl/android/AndroidHttpConstants.java
deleted file mode 100644
index 5779866..0000000
--- a/java/com/google/ipc/invalidation/ticl/android/AndroidHttpConstants.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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.android;
-
-/**
- * Defines shared constants values used in the Android Invalidation HTTP interface.
- *
- */
-public class AndroidHttpConstants {
-
-  /** The URL of the invalidation channel service */
-  public static final String CHANNEL_URL = "https://clients4.google.com/";
-
-  /** The MIME content type to use for requests that contain binary protobuf */
-  public static final String PROTO_CONTENT_TYPE = "application/x-protobuffer";
-
-  /** The relative URL to use to send inbound client requests to the Android frontend */
-  public static final String REQUEST_URL = "/invalidation/android/request/";
-
-  /**
-   * The name of the query parameter that contains the service name that should be used to
-   * validate the authentication token provided with the request.
-   */
-  public static final String SERVICE_PARAMETER = "service";
-
-  /**
-   * The name of the header that contains the echoed token. This token is included in all C2DM
-   * messages to the client and is echoed back under this header on all client HTTP requests.
-   */
-  public static final String ECHO_HEADER = "echo-token";
-}
diff --git a/java/com/google/ipc/invalidation/ticl/android/AndroidInvalidationService.java b/java/com/google/ipc/invalidation/ticl/android/AndroidInvalidationService.java
deleted file mode 100644
index 4cbb0e0..0000000
--- a/java/com/google/ipc/invalidation/ticl/android/AndroidInvalidationService.java
+++ /dev/null
@@ -1,597 +0,0 @@
-/*
- * 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.android;
-
-import com.google.ipc.invalidation.common.DigestFunction;
-import com.google.ipc.invalidation.common.ObjectIdDigestUtils;
-import com.google.ipc.invalidation.external.client.SystemResources.Logger;
-import com.google.ipc.invalidation.external.client.android.AndroidInvalidationClient;
-import com.google.ipc.invalidation.external.client.android.service.AndroidLogger;
-import com.google.ipc.invalidation.external.client.android.service.Request;
-import com.google.ipc.invalidation.external.client.android.service.Response;
-import com.google.ipc.invalidation.external.client.android.service.Response.Status;
-import com.google.ipc.invalidation.external.client.contrib.MultiplexingGcmListener;
-import com.google.ipc.invalidation.external.client.types.AckHandle;
-import com.google.ipc.invalidation.external.client.types.ObjectId;
-import com.google.ipc.invalidation.ticl.InvalidationClientCore;
-import com.google.ipc.invalidation.ticl.PersistenceUtils;
-import com.google.ipc.invalidation.util.TypedUtil;
-import com.google.protos.ipc.invalidation.Client.PersistentTiclState;
-
-import android.accounts.Account;
-import android.content.Context;
-import android.content.Intent;
-import android.os.IBinder;
-import android.util.Base64;
-
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicReference;
-
-
-/**
- * The AndroidInvalidationService class provides an Android service implementation that bridges
- * between the {@code InvalidationService} interface and invalidation client service instances
- * executing within the scope of that service. The invalidation service will have an associated
- * {@link AndroidClientManager} that is managing the set of active (in memory) clients associated
- * with the service.  It processes requests from invalidation applications (as invocations on
- * the {@code InvalidationService} bound service interface along with GCM registration and
- * activity (from {@link ReceiverService}).
- *
- */
-public class AndroidInvalidationService extends AbstractInvalidationService {
-
-  /**
-   * Service that handles system GCM messages (with support from the base class). It receives
-   * intents for GCM registration, errors and message delivery. It does some basic processing and
-   * then forwards the messages to the {@link AndroidInvalidationService} for handling.
-   */
-  public static class ReceiverService extends MultiplexingGcmListener.AbstractListener {
-
-    /**
-     * Receiver for broadcasts by the multiplexed GCM service. It forwards them to
-     * AndroidMessageReceiverService.
-     */
-    public static class Receiver extends MultiplexingGcmListener.AbstractListener.Receiver {
-      /* This class is public so that it can be instantiated by the Android runtime. */
-      @Override
-      protected Class<?> getServiceClass() {
-        return ReceiverService.class;
-      }
-    }
-
-    public ReceiverService() {
-      super("MsgRcvrSvc");
-    }
-
-    @Override
-    public void onRegistered(String registrationId) {
-      logger.info("GCM Registration received: %s", registrationId);
-
-      // Upon receiving a new updated GCM ID, notify the invalidation service
-      Intent serviceIntent =
-          AndroidInvalidationService.createRegistrationIntent(this, registrationId);
-      startService(serviceIntent);
-    }
-
-    @Override
-    public void onUnregistered(String registrationId) {
-      logger.info("GCM unregistered");
-    }
-
-    @Override
-    protected void onMessage(Intent intent) {
-      // Extract expected fields and do basic syntactic checks (but no value checking)
-      // and forward the result on to the AndroidInvalidationService for processing.
-      Intent serviceIntent;
-      String clientKey = intent.getStringExtra(AndroidC2DMConstants.CLIENT_KEY_PARAM);
-      if (clientKey == null) {
-        logger.severe("GCM Intent does not contain client key value: %s", intent);
-        return;
-      }
-      String encodedData = intent.getStringExtra(AndroidC2DMConstants.CONTENT_PARAM);
-      String echoToken = intent.getStringExtra(AndroidC2DMConstants.ECHO_PARAM);
-      if (encodedData != null) {
-        try {
-          byte [] rawData = Base64.decode(encodedData, Base64.URL_SAFE);
-          serviceIntent = AndroidInvalidationService.createDataIntent(this, clientKey, echoToken,
-              rawData);
-        } catch (IllegalArgumentException exception) {
-          logger.severe("Unable to decode intent data", exception);
-          return;
-        }
-      } else {
-        logger.severe("Received mailbox intent: %s", intent);
-        return;
-      }
-      startService(serviceIntent);
-    }
-
-    @Override
-    protected void onDeletedMessages(int total) {
-      // This method must be implemented if we start using non-collapsable messages with GCM. For
-      // now, there is nothing to do.
-    }
-  }
-
-  /** The last created instance, for testing. */
-  
-  static AtomicReference<AndroidInvalidationService> lastInstanceForTest =
-      new AtomicReference<AndroidInvalidationService>();
-
-  /** For tests only, the number of C2DM errors received. */
-  static final AtomicInteger numGcmErrorsForTest = new AtomicInteger(0);
-
-  /** For tests only, the number of C2DM registration messages received. */
-  static final AtomicInteger numGcmRegistrationForTest = new AtomicInteger(0);
-
-  /** For tests only, the number of C2DM messages received. */
-  static final AtomicInteger numGcmMessagesForTest = new AtomicInteger(0);
-
-  /** For tests only, the number of onCreate calls made. */
-  static final AtomicInteger numCreateForTest = new AtomicInteger(0);
-
-  /** The client manager tracking in-memory client instances */
-  
-  protected static AndroidClientManager clientManager;
-
-  private static final Logger logger = AndroidLogger.forTag("InvService");
-
-  /** The HTTP URL of the channel service. */
-  private static String channelUrl = AndroidHttpConstants.CHANNEL_URL;
-
-  // The AndroidInvalidationService handles a set of internal intents that are used for
-  // communication and coordination between the it and the GCM handling service.   These
-  // are documented here with action and extra names documented with package private
-  // visibility since they are not intended for use by external components.
-
-  /**
-   * Sent when a new GCM registration activity occurs for the service. This can occur the first
-   * time the service is run or at any subsequent time if the Android C2DM service decides to issue
-   * a new GCM registration ID.
-   */
-  static final String REGISTRATION_ACTION = "register";
-
-  /**
-   * The name of the String extra that contains the registration ID for a register intent.  If this
-   * extra is not present, then it indicates that a C2DM notification regarding unregistration has
-   * been received (not expected during normal operation conditions).
-   */
-  static final String REGISTER_ID = "id";
-
-  /**
-   * This intent is sent when a GCM message targeting the service is received.
-   */
-  static final String MESSAGE_ACTION = "message";
-
-  /**
-   * The name of the String extra that contains the client key for the GCM message.
-   */
-  static final String MESSAGE_CLIENT_KEY = "clientKey";
-
-  /**
-   * The name of the byte array extra that contains the encoded event for the GCM message.
-   */
-  static final String MESSAGE_DATA = "data";
-
-  /** The name of the string extra that contains the echo token in the GCM message. */
-  static final String MESSAGE_ECHO = "echo-token";
-
-  /**
-   * This intent is sent when GCM registration has failed irrevocably.
-   */
-  static final String ERROR_ACTION = "error";
-
-  /**
-   * The name of the String extra that contains the error message describing the registration
-   * failure.
-   */
-  static final String ERROR_MESSAGE = "message";
-
-  /** Returns the client manager for this service */
-  static AndroidClientManager getClientManager() {
-    return clientManager;
-  }
-
-  /**
-   * Creates a new registration intent that notifies the service of a registration ID change
-   */
-  static Intent createRegistrationIntent(Context context, String registrationId) {
-    Intent intent = new Intent(REGISTRATION_ACTION);
-    intent.setClass(context, AndroidInvalidationService.class);
-    if (registrationId != null) {
-      intent.putExtra(AndroidInvalidationService.REGISTER_ID, registrationId);
-    }
-    return intent;
-  }
-
-  /**
-   * Creates a new message intent to contains event data to deliver directly to a client.
-   */
-  static Intent createDataIntent(Context context, String clientKey, String token,
-      byte [] data) {
-    Intent intent = new Intent(MESSAGE_ACTION);
-    intent.setClass(context, AndroidInvalidationService.class);
-    intent.putExtra(MESSAGE_CLIENT_KEY, clientKey);
-    intent.putExtra(MESSAGE_DATA, data);
-    if (token != null) {
-      intent.putExtra(MESSAGE_ECHO, token);
-    }
-    return intent;
-  }
-
-  /**
-   * Creates a new message intent that references event data to retrieve from a mailbox.
-   */
-  static Intent createMailboxIntent(Context context, String clientKey, String token) {
-    Intent intent = new Intent(MESSAGE_ACTION);
-    intent.setClass(context, AndroidInvalidationService.class);
-    intent.putExtra(MESSAGE_CLIENT_KEY, clientKey);
-    if (token != null) {
-      intent.putExtra(MESSAGE_ECHO, token);
-    }
-    return intent;
-  }
-
-  /**
-   * Creates a new error intent that notifies the service of a registration failure.
-   */
-  static Intent createErrorIntent(Context context, String errorId) {
-    Intent intent = new Intent(ERROR_ACTION);
-    intent.setClass(context, AndroidInvalidationService.class);
-    intent.putExtra(ERROR_MESSAGE, errorId);
-    return intent;
-  }
-
-  /**
-   * Overrides the channel URL set in package metadata to enable dynamic port assignment and
-   * configuration during testing.
-   */
-  
-  static void setChannelUrlForTest(String url) {
-    channelUrl = url;
-  }
-
-  /**
-   * Resets the state of the service to destroy any existing clients
-   */
-  
-  static void reset() {
-    if (clientManager != null) {
-      clientManager.releaseAll();
-    }
-  }
-
-  /** The function for computing persistence state digests when rewriting them. */
-  private final DigestFunction digestFn = new ObjectIdDigestUtils.Sha1DigestFunction();
-
-  public AndroidInvalidationService() {
-    lastInstanceForTest.set(this);
-  }
-
-  @Override
-  public void onCreate() {
-    synchronized (lock) {
-      super.onCreate();
-
-      // Create the client manager
-      if (clientManager == null) {
-        clientManager = new AndroidClientManager(this);
-      }
-      numCreateForTest.incrementAndGet();
-    }
-  }
-
-  @Override
-  public int onStartCommand(Intent intent, int flags, int startId) {
-    // Process GCM related messages from the ReceiverService. We do not check isCreated here because
-    // this is part of the stop/start lifecycle, not bind/unbind.
-    synchronized (lock) {
-      logger.fine("Received action = %s", intent.getAction());
-      if (MESSAGE_ACTION.equals(intent.getAction())) {
-        handleMessage(intent);
-      } else if (REGISTRATION_ACTION.equals(intent.getAction())) {
-        handleRegistration(intent);
-      } else if (ERROR_ACTION.equals(intent.getAction())) {
-        handleError(intent);
-      }
-      final int retval = super.onStartCommand(intent, flags, startId);
-
-      // Unless we are explicitly being asked to start, stop ourselves. Request.SERVICE_INTENT
-      // is the intent used by InvalidationBinder to bind the service, and
-      // AndroidInvalidationClientImpl uses the intent returned by InvalidationBinder.getIntent
-      // as the argument to its startService call.
-      if (!Request.SERVICE_INTENT.getAction().equals(intent.getAction())) {
-        stopServiceIfNoClientsRemain(intent.getAction());
-      }
-      return retval;
-    }
-  }
-
-  @Override
-  public void onDestroy() {
-    synchronized (lock) {
-      reset();
-      super.onDestroy();
-    }
-  }
-
-  @Override
-  public IBinder onBind(Intent intent) {
-    return super.onBind(intent);
-  }
-
-  @Override
-  public boolean onUnbind(Intent intent) {
-    synchronized (lock) {
-      logger.fine("onUnbind");
-      super.onUnbind(intent);
-
-      if ((clientManager != null) && (clientManager.getClientCount() > 0)) {
-        // This isn't wrong, per se, but it's potentially unusual.
-        logger.info(" clients still active in onUnbind");
-      }
-      stopServiceIfNoClientsRemain("onUnbind");
-
-      // We don't care about the onRebind event, which is what the documentation says a "true"
-      // return here will get us, but if we return false then we don't get a second onUnbind() event
-      // in a bind/unbind/bind/unbind cycle, which we require.
-      return true;
-    }
-  }
-
-  // The following protected methods are called holding "lock" by AbstractInvalidationService.
-
-  @Override
-  protected void create(Request request, Response.Builder response) {
-    String clientKey = request.getClientKey();
-    int clientType = request.getClientType();
-    Account account = request.getAccount();
-    String authType = request.getAuthType();
-    Intent eventIntent = request.getIntent();
-    clientManager.create(clientKey, clientType, account, authType, eventIntent);
-    response.setStatus(Status.SUCCESS);
-  }
-
-  @Override
-  protected void resume(Request request, Response.Builder response) {
-    String clientKey = request.getClientKey();
-    AndroidClientProxy client = clientManager.get(clientKey);
-    if (setResponseStatus(client, request, response)) {
-      response.setAccount(client.getAccount());
-      response.setAuthType(client.getAuthType());
-    }
-  }
-
-  @Override
-  protected void start(Request request, Response.Builder response) {
-    String clientKey = request.getClientKey();
-    AndroidInvalidationClient client = clientManager.get(clientKey);
-    if (setResponseStatus(client, request, response)) {
-      client.start();
-    }
-  }
-
-  @Override
-  protected void stop(Request request, Response.Builder response) {
-    String clientKey = request.getClientKey();
-    AndroidInvalidationClient client = clientManager.get(clientKey);
-    if (setResponseStatus(client, request, response)) {
-      client.stop();
-    }
-  }
-
-  @Override
-  protected void register(Request request, Response.Builder response) {
-    String clientKey = request.getClientKey();
-    AndroidInvalidationClient client = clientManager.get(clientKey);
-    if (setResponseStatus(client, request, response)) {
-      ObjectId objectId = request.getObjectId();
-      client.register(objectId);
-    }
-  }
-
-  @Override
-  protected void unregister(Request request, Response.Builder response) {
-    String clientKey = request.getClientKey();
-    AndroidInvalidationClient client = clientManager.get(clientKey);
-    if (setResponseStatus(client, request, response)) {
-      ObjectId objectId = request.getObjectId();
-      client.unregister(objectId);
-    }
-  }
-
-  @Override
-  protected void acknowledge(Request request, Response.Builder response) {
-    String clientKey = request.getClientKey();
-    AckHandle ackHandle = request.getAckHandle();
-    AndroidInvalidationClient client = clientManager.get(clientKey);
-    if (setResponseStatus(client, request, response)) {
-      client.acknowledge(ackHandle);
-    }
-  }
-
-  @Override
-  protected void destroy(Request request, Response.Builder response) {
-    String clientKey = request.getClientKey();
-    AndroidInvalidationClient client = clientManager.get(clientKey);
-    if (setResponseStatus(client, request, response)) {
-      client.destroy();
-    }
-  }
-
-  /**
-   * If {@code client} is {@code null}, sets the {@code response} status to an error. Otherwise,
-   * sets the status to {@code success}.
-   * @return whether {@code client} was non-{@code null}.   *
-   */
-  private boolean setResponseStatus(AndroidInvalidationClient client, Request request,
-      Response.Builder response) {
-    if (client == null) {
-      response.setError("Client does not exist: " + request);
-      response.setStatus(Status.INVALID_CLIENT);
-      return false;
-    } else {
-      response.setStatus(Status.SUCCESS);
-      return true;
-    }
-  }
-
-  /** Returns the base URL used to send messages to the outbound network channel */
-  String getChannelUrl() {
-    synchronized (lock) {
-      return channelUrl;
-    }
-  }
-
-  private void handleMessage(Intent intent) {
-    numGcmMessagesForTest.incrementAndGet();
-    String clientKey = intent.getStringExtra(MESSAGE_CLIENT_KEY);
-    AndroidClientProxy proxy = clientManager.get(clientKey);
-
-    // Client is unknown or unstarted; we can't deliver the message, but we need to
-    // remember that we dropped it if the client is known.
-    if ((proxy == null) || !proxy.isStarted()) {
-      logger.warning("Dropping GCM message for unknown or unstarted client: %s", clientKey);
-      handleGcmMessageForUnstartedClient(proxy);
-      return;
-    }
-
-    // We can deliver the message. Pass the new echo token to the channel.
-    String echoToken = intent.getStringExtra(MESSAGE_ECHO);
-    logger.fine("Update %s with new echo token: %s", clientKey, echoToken);
-    proxy.getChannel().updateEchoToken(echoToken);
-
-    byte [] message = intent.getByteArrayExtra(MESSAGE_DATA);
-    if (message != null) {
-      logger.fine("Deliver to %s message %s", clientKey, message);
-      proxy.getChannel().receiveMessage(message);
-    } else {
-      logger.severe("Got mailbox intent: %s", intent);
-    }
-  }
-
-  /**
-   * Handles receipt of a GCM message for a client that was unknown or not started. If the client
-   * was unknown, drops the message. If the client was not started, rewrites the client's
-   * persistent state to have a last-message-sent-time of 0, ensuring that the client will
-   * send a heartbeat to the server when restarted. Since we drop the received GCM message,
-   * the client will be disconnected by the invalidation pusher; this heartbeat ensures a
-   * timely reconnection.
-   */
-  private void handleGcmMessageForUnstartedClient(AndroidClientProxy proxy) {
-    if (proxy == null) {
-      // Unknown client; nothing to do.
-      return;
-    }
-
-    // Client is not started. Open its storage. We are going to use unsafe calls here that
-    // bypass the normal storage API. This is safe in this context because we hold a lock
-    // that prevents anyone else from starting this client or accessing its storage. We
-    // really should not be holding a lock across I/O, but at least this is only local
-    // file I/O, and we're only writing a few bytes. Additionally, since we currently only
-    // have one Ticl, we should only ever enter this function if we're not being used for
-    // anything else.
-    final String clientKey = proxy.getClientKey();
-    logger.info("Received message for unloaded client; rewriting state file: %s", clientKey);
-
-    // This storage must have been loaded, because we got this proxy from the client manager,
-    // which always ensures that its entries have that property.
-    AndroidStorage storageForClient = proxy.getStorage();
-    PersistentTiclState clientState = decodeTiclState(clientKey, storageForClient);
-    if (clientState == null) {
-      // Logging done in decodeTiclState.
-      return;
-    }
-
-    // Rewrite the last message sent time.
-    PersistentTiclState newState = PersistentTiclState.newBuilder(clientState)
-        .setLastMessageSendTimeMs(0).build();
-
-    // Serialize the new state.
-    byte[] newClientState = PersistenceUtils.serializeState(newState, digestFn);
-
-    // Write it out.
-    storageForClient.getPropertiesUnsafe().put(InvalidationClientCore.CLIENT_TOKEN_KEY,
-        newClientState);
-    storageForClient.storeUnsafe();
-  }
-
-  private void handleRegistration(Intent intent) {
-    // Notify the client manager of the updated registration ID
-    String id = intent.getStringExtra(REGISTER_ID);
-    clientManager.informRegistrationIdChanged();
-    numGcmRegistrationForTest.incrementAndGet();
-  }
-
-  private void handleError(Intent intent) {
-    logger.severe("Unable to perform GCM registration: %s", intent.getStringExtra(ERROR_MESSAGE));
-    numGcmErrorsForTest.incrementAndGet();
-  }
-
-  /**
-   * Stops the service if there are no clients in the client manager.
-   * @param debugInfo short string describing why the check was made
-   */
-  private void stopServiceIfNoClientsRemain(String debugInfo) {
-    if ((clientManager == null) || clientManager.areAllClientsStopped()) {
-      logger.info("Stopping AndroidInvalidationService since no clients remain: %s", debugInfo);
-      stopSelf();
-    } else {
-      logger.fine("Not stopping service since %s clients remain (%s)",
-          clientManager.getClientCount(), debugInfo);
-    }
-  }
-
-  /**
-   * Returns the persisted state for the client with key {@code clientKey} in
-   * {@code storageForClient}, or {@code null} if no valid state could be found.
-   * <p>
-   * REQUIRES: {@code storageForClient}.load() has been called successfully.
-   */
-  
-  
-  PersistentTiclState decodeTiclState(final String clientKey, AndroidStorage storageForClient) {
-    synchronized (lock) {
-      // Retrieve the serialized state.
-      final Map<String, byte[]> properties = storageForClient.getPropertiesUnsafe();
-      byte[] clientStateBytes = TypedUtil.mapGet(properties,
-          InvalidationClientCore.CLIENT_TOKEN_KEY);
-      if (clientStateBytes == null) {
-        logger.warning("No client state found in storage for %s: %s", clientKey,
-            properties.keySet());
-        return null;
-      }
-
-      // Deserialize it.
-      PersistentTiclState clientState =
-          PersistenceUtils.deserializeState(logger, clientStateBytes, digestFn);
-      if (clientState == null) {
-        logger.warning("Invalid client state found in storage for %s", clientKey);
-        return null;
-      }
-      return clientState;
-    }
-  }
-
-  /**
-   * Returns whether the client with {@code clientKey} is loaded in the client manager.
-   */
-  public static boolean isLoadedForTest(String clientKey) {
-    return (getClientManager() != null) && getClientManager().isLoadedForTest(clientKey);
-  }
-}
diff --git a/java/com/google/ipc/invalidation/ticl/android/AndroidResourcesFactory.java b/java/com/google/ipc/invalidation/ticl/android/AndroidResourcesFactory.java
deleted file mode 100644
index 0b2ad30..0000000
--- a/java/com/google/ipc/invalidation/ticl/android/AndroidResourcesFactory.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * 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.android;
-
-import com.google.ipc.invalidation.external.client.SystemResources;
-import com.google.ipc.invalidation.external.client.SystemResources.NetworkChannel;
-import com.google.ipc.invalidation.external.client.SystemResources.Scheduler;
-import com.google.ipc.invalidation.external.client.SystemResources.Storage;
-import com.google.ipc.invalidation.external.client.SystemResourcesBuilder;
-import com.google.ipc.invalidation.external.client.android.service.AndroidLogger;
-import com.google.ipc.invalidation.util.NamedRunnable;
-
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-
-
-/**
- * SystemResources creator for the Android system service.
- *
- */
-public class AndroidResourcesFactory {
-
-  /**
-   * Implementation of {@link SystemResources.Scheduler} based on {@code ThreadExecutor}.
-   *
-   */
-  private static class ExecutorBasedScheduler implements Scheduler {
-
-    private SystemResources systemResources;
-
-    /** Scheduler for running and scheduling tasks. */
-    private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
-
-    /** Thread that belongs to the scheduler. */
-    private Thread thread = null;
-
-    private final String threadName;
-
-    /** Creates a scheduler with thread {@code name} for internal logging, etc. */
-    private ExecutorBasedScheduler(final String name) {
-      threadName = name;
-    }
-
-    @Override
-    public long getCurrentTimeMs() {
-      return System.currentTimeMillis();
-    }
-
-    @Override
-    public void schedule(final int delayMs, final Runnable runnable) {
-      // For simplicity, schedule first and then check when the event runs later if the resources
-      // have been shut down.
-      scheduler.schedule(new NamedRunnable("AndroidScheduler") {
-        @Override
-        public void run() {
-          if (thread != Thread.currentThread()) {
-            // Either at initialization or if the thread has been killed or restarted by the
-            // Executor service.
-            thread = Thread.currentThread();
-            thread.setName(threadName);
-          }
-
-          if (systemResources.isStarted()) {
-            runnable.run();
-          } else {
-            systemResources.getLogger().warning("Not running on internal thread since resources " +
-              "not started %s, %s", delayMs, runnable);
-          }
-        }
-      }, delayMs, TimeUnit.MILLISECONDS);
-    }
-
-    @Override
-    public boolean isRunningOnThread() {
-      return (thread == null) || (Thread.currentThread() == thread);
-    }
-
-    @Override
-    public void setSystemResources(SystemResources resources) {
-      this.systemResources = resources;
-    }
-  }
-
-  //
-  // End of nested classes.
-  //
-
-  /**
-   * Constructs a {@link SystemResourcesBuilder} instance using default scheduling, Android-style
-   * logging, and storage, and using {@code network} to send and receive messages.
-   */
-  public static SystemResourcesBuilder createResourcesBuilder(String logPrefix,
-      NetworkChannel network, Storage storage) {
-    SystemResourcesBuilder builder = new SystemResourcesBuilder(AndroidLogger.forPrefix(logPrefix),
-          new ExecutorBasedScheduler("ticl" + logPrefix),
-          new ExecutorBasedScheduler("ticl-listener" + logPrefix),
-          network, storage);
-    builder.setPlatform("Android-" + android.os.Build.VERSION.RELEASE);
-    return builder;
-  }
-}
diff --git a/java/com/google/ipc/invalidation/ticl/android/AndroidStorage.java b/java/com/google/ipc/invalidation/ticl/android/AndroidStorage.java
deleted file mode 100644
index 7a320a8..0000000
--- a/java/com/google/ipc/invalidation/ticl/android/AndroidStorage.java
+++ /dev/null
@@ -1,331 +0,0 @@
-/*
- * 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.android;
-
-import com.google.common.base.Preconditions;
-import com.google.ipc.invalidation.external.client.SystemResources;
-import com.google.ipc.invalidation.external.client.SystemResources.Logger;
-import com.google.ipc.invalidation.external.client.SystemResources.Storage;
-import com.google.ipc.invalidation.external.client.android.service.AndroidLogger;
-import com.google.ipc.invalidation.external.client.types.Callback;
-import com.google.ipc.invalidation.external.client.types.SimplePair;
-import com.google.ipc.invalidation.external.client.types.Status;
-import com.google.ipc.invalidation.util.NamedRunnable;
-import com.google.protobuf.ByteString;
-import com.google.protos.ipc.invalidation.AndroidState.ClientMetadata;
-import com.google.protos.ipc.invalidation.AndroidState.ClientProperty;
-import com.google.protos.ipc.invalidation.AndroidState.StoredState;
-import com.google.protos.ipc.invalidation.ClientProtocol.Version;
-
-import android.accounts.Account;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-
-/**
- * Provides the storage and in-memory state model for Android client persistent state.   There is
- * one storage instance for each client instance that is responsible for loading, making state
- * available, and storing the persisted state.
- * <b>
- * The class is thread safe <b>after</b> the {@link #create} or {@link #load} method has been
- * called to populate it with initial state.
- *
- */
-public class AndroidStorage implements Storage {
-
-  /*
-   * The current storage format is based upon a single file containing protocol buffer data.  Each
-   * client instance will have a separate state file with a name based upon a client-key derived
-   * convention.   The design could easily be evolved later to leverage a shared SQLite database
-   * or other mechanisms without requiring any changes to the public interface.
-   */
-
-  /** Storage logger */
-  private static final Logger logger = AndroidLogger.forTag("InvStorage");
-
-  /** The version value that is stored within written state */
-  private static final Version CURRENT_VERSION =
-      Version.newBuilder().setMajorVersion(1).setMinorVersion(0).build();
-
-  /** The name of the subdirectory in the application files store where state files are stored */
-   static final String STATE_DIRECTORY = "InvalidationClient";
-
-  /** A simple success constant */
-  private static final Status SUCCESS = Status.newInstance(Status.Code.SUCCESS, "");
-
-  /**
-   * Deletes all persisted client state files stored in the state directory and then
-   * the directory itself.
-   */
-   public static void reset(Context context) {
-    File stateDir = context.getDir(STATE_DIRECTORY, Context.MODE_PRIVATE);
-    for (File stateFile : stateDir.listFiles()) {
-      stateFile.delete();
-    }
-    stateDir.delete();
-  }
-
-  /** The execution context */
-   final Context context;
-
-  /** The client key associated with this storage instance */
-   final String key;
-
-  /** the client metadata associated with the storage instance (or {@code null} if not loaded */
-  private ClientMetadata metadata;
-
-  /** Stores the client properties for a client */
-  private final Map<String, byte []> properties = new ConcurrentHashMap<String, byte[]>();
-
-  /** Executor used to schedule background reads and writes on a single shared thread */
-  
-  final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
-
-  /**
-   * Creates a new storage object for reading or writing state for the providing client key using
-   * the provided execution context.
-   */
-  
-  protected AndroidStorage(Context context, String key) {
-    Preconditions.checkNotNull(context, "context");
-    Preconditions.checkNotNull(key, "key");
-    this.key = key;
-    this.context = context;
-  }
-
-  ClientMetadata getClientMetadata() {
-    return metadata;
-  }
-
-  @Override
-  public void deleteKey(final String key, final Callback<Boolean> done) {
-    scheduler.execute(new NamedRunnable("AndroidStorage.deleteKey") {
-      @Override
-      public void run() {
-        properties.remove(key);
-        store();
-        done.accept(true);
-      }
-    });
-  }
-
-  @Override
-  public void readAllKeys(final Callback<SimplePair<Status, String>> keyCallback) {
-    scheduler.execute(new NamedRunnable("AndroidStorage.readAllKeys") {
-      @Override
-      public void run() {
-        for (String key : properties.keySet()) {
-          keyCallback.accept(SimplePair.of(SUCCESS, key));
-        }
-      }
-    });
-  }
-
-  @Override
-  public void readKey(final String key, final Callback<SimplePair<Status, byte[]>> done) {
-    scheduler.execute(new NamedRunnable("AndroidStorage.readKey") {
-      @Override
-      public void run() {
-          byte [] value = properties.get(key);
-          if (value != null) {
-            done.accept(SimplePair.of(SUCCESS, value));
-          } else {
-            Status status =
-                Status.newInstance(Status.Code.PERMANENT_FAILURE, "No value in map for " + key);
-            done.accept(SimplePair.of(status, (byte []) null));
-          }
-      }
-    });
-  }
-
-  @Override
-  public void writeKey(final String key, final byte[] value, final Callback<Status> done) {
-    scheduler.execute(new NamedRunnable("AndroidStorage.writeKey") {
-      @Override
-      public void run() {
-        properties.put(key, value);
-        store();
-        done.accept(SUCCESS);
-      }
-    });
-  }
-
-  @Override
-  public void setSystemResources(SystemResources resources) {}
-
-  /**
-   * Returns the file where client state for this storage instance is stored.
-   */
-   File getStateFile() {
-    File stateDir = context.getDir(STATE_DIRECTORY, Context.MODE_PRIVATE);
-    return new File(stateDir, key);
-  }
-
-  /**
-   * Returns the input stream that can be used to read state from the internal file storage for
-   * the application.
-   */
-  
-  protected InputStream getStateInputStream() throws FileNotFoundException {
-    return new FileInputStream(getStateFile());
-  }
-
-  /**
-   * Returns the output stream that can be used to write state to the internal file storage for
-   * the application.
-   */
-  
-  protected OutputStream getStateOutputStream() throws FileNotFoundException {
-    return new FileOutputStream(getStateFile());
-  }
-
-  void create(int clientType, Account account, String authType,
-      Intent eventIntent) {
-    ComponentName component = eventIntent.getComponent();
-    Preconditions.checkNotNull(component, "No component found in event intent");
-    metadata = ClientMetadata.newBuilder()
-        .setVersion(CURRENT_VERSION)
-        .setClientKey(key)
-        .setClientType(clientType)
-        .setAccountName(account.name)
-        .setAccountType(account.type)
-        .setAuthType(authType)
-        .setListenerPkg(component.getPackageName())
-        .setListenerClass(component.getClassName())
-        .build();
-    store();
-  }
-
-  /**
-   * Attempts to load any persisted client state for the stored client.
-   *
-   * @returns {@code true} if loaded successfully, false otherwise.
-   */
-  boolean load() {
-    InputStream inputStream = null;
-    try {
-      // Load the state from internal storage and parse it the protocol
-      inputStream = getStateInputStream();
-      StoredState fullState = StoredState.parseFrom(inputStream);
-      metadata = fullState.getMetadata();
-      if (!key.equals(metadata.getClientKey())) {
-        logger.severe("Unexpected client key mismatch: %s, %s", key, metadata.getClientKey());
-        return false;
-      }
-      logger.fine("Loaded metadata: %s", metadata);
-
-      // Unpack the client properties into a map for easy lookup / iteration / update
-      for (ClientProperty clientProperty : fullState.getPropertyList()) {
-        logger.fine("Loaded property: %s", clientProperty);
-        properties.put(clientProperty.getKey(), clientProperty.getValue().toByteArray());
-      }
-      logger.fine("Loaded state for %s", key);
-      return true;
-    } catch (FileNotFoundException e) {
-      // No state persisted on disk
-    } catch (IOException exception) {
-      // Log error regarding client state read and return null
-      logger.severe("Error reading client state", exception);
-    } finally {
-      if (inputStream != null) {
-        try {
-          inputStream.close();
-        } catch (IOException exception) {
-          logger.severe("Unable to close state file", exception);
-        }
-      }
-    }
-    return false;
-  }
-
-  /**
-   * Deletes all state associated with the storage instance.
-   */
-  void delete() {
-    File stateFile = getStateFile();
-    if (stateFile.exists()) {
-      stateFile.delete();
-      logger.info("Deleted state for %s from %s", key, stateFile.getName());
-    }
-  }
-
-  /**
-   * Store the current state into the persistent storage.
-   */
-  private void store() {
-    StoredState.Builder stateBuilder =
-        StoredState.newBuilder()
-            .mergeMetadata(metadata);
-    for (Map.Entry<String, byte []> entry : properties.entrySet()) {
-      stateBuilder.addProperty(
-          ClientProperty.newBuilder()
-              .setKey(entry.getKey())
-              .setValue(ByteString.copyFrom(entry.getValue()))
-              .build());
-    }
-    StoredState state = stateBuilder.build();
-    OutputStream outputStream = null;
-    try {
-      outputStream = getStateOutputStream();
-      state.writeTo(outputStream);
-      logger.info("State written for %s", key);
-    } catch (FileNotFoundException exception) {
-      // This should not happen when opening to create / replace
-      logger.severe("Unable to open state file", exception);
-    } catch (IOException exception) {
-      logger.severe("Error writing state", exception);
-    } finally {
-      if (outputStream != null) {
-        try {
-          outputStream.close();
-        } catch (IOException exception) {
-          logger.warning("Unable to close state file", exception);
-        }
-      }
-    }
-  }
-
-  /**
-   * Returns the underlying properties map for direct manipulation. This is extremely
-   * unsafe since it bypasses the concurrency control. It is intended only for use
-   * in {@code AndroidInvalidationService#handleC2dmMessageForUnstartedClient}.
-   */
-  Map<String, byte[]> getPropertiesUnsafe() {
-    return properties;
-  }
-
-  /**
-   * Stores the properties to disk. This is extremely unsafe since it bypasses the
-   * concurrency control. It is intended only for use in
-   * {@code AndroidInvalidationService#handleC2dmMessageForUnstartedClient}.
-   */
-  void storeUnsafe() {
-    store();
-  }
-}
diff --git a/java/com/google/ipc/invalidation/ticl/android/c2dm/BaseC2DMReceiver.java b/java/com/google/ipc/invalidation/ticl/android/c2dm/BaseC2DMReceiver.java
deleted file mode 100644
index 93adff6..0000000
--- a/java/com/google/ipc/invalidation/ticl/android/c2dm/BaseC2DMReceiver.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * 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.android.c2dm;
-
-
-import com.google.ipc.invalidation.external.client.SystemResources.Logger;
-import com.google.ipc.invalidation.external.client.android.service.AndroidLogger;
-
-import android.app.IntentService;
-import android.content.Context;
-import android.content.Intent;
-
-/**
- * Service base class that receives events for C2DM registrations and messages.  Subclasses
- * should override the {@code onYYY} event handler methods to add appropriate logic for
- * registration or message handling.
- */
-public abstract class BaseC2DMReceiver extends IntentService {
-  private static final Logger logger = AndroidLogger.forTag("BaseC2DMReceiver");
-
-  /**
-   * If {@code true} indicates that the wakelock associated with messages should be automatically
-   * released after the {onYYY} handler has been called. Otherwise, the subclass is responsible for
-   * releasing the lock (if any).
-   */
-  private final boolean automaticallyReleaseWakelock;
-
-  /**
-   * Creates a new receiver instance
-   *
-   * @param name the name for the receiver service.  Used only for debug logging.
-   * @param automaticallyReleaseWakeLock if {@code true} indicates that the wakelock associated with
-   *        messages should be automatically released after the {onYYY} handler has been called.
-   *        Otherwise, the subclass is responsible for releasing the lock (if any).
-   */
-  protected BaseC2DMReceiver(String name, boolean automaticallyReleaseWakeLock) {
-    super(name);
-    // Always redeliver if evicted while processing intents.
-    setIntentRedelivery(true);
-    this.automaticallyReleaseWakelock = automaticallyReleaseWakeLock;
-  }
-
-  @Override
-  protected void onHandleIntent(Intent intent) {
-    logger.fine("Handle intent: %s", intent);
-    if (intent == null) {
-      return;
-    }
-    try {
-      // Examine the action and raise the appropriate onYYY event
-      if (intent.getAction().equals(C2DMessaging.ACTION_MESSAGE)) {
-        onMessage(getApplicationContext(), intent);
-      } else if (intent.getAction().equals(C2DMessaging.ACTION_REGISTRATION_ERROR)) {
-        onRegistrationError(getApplicationContext(),
-            intent.getExtras().getString(C2DMessaging.EXTRA_REGISTRATION_ERROR));
-      } else if (intent.getAction().equals(C2DMessaging.ACTION_REGISTERED)) {
-        onRegistered(getApplicationContext(),
-            intent.getExtras().getString(C2DMessaging.EXTRA_REGISTRATION_ID));
-      } else if (intent.getAction().equals(C2DMessaging.ACTION_UNREGISTERED)) {
-        onUnregistered(getApplicationContext());
-      }
-    } finally {
-      if (automaticallyReleaseWakelock) {
-        releaseWakeLock(intent);
-      }
-    }
-  }
-
-  /**
-   * Called when a cloud message has been received.
-   *
-   * @param context the context the intent was received in
-   * @param intent the received intent
-   */
-  protected abstract void onMessage(Context context, Intent intent);
-
-  /**
-   * Called on registration error. Override to provide better error messages.
-   *
-   * This is called in the context of a Service - no dialog or UI.
-   *
-   * @param context the context the intent was received in
-   * @param errorId the errorId String
-   */
-  protected abstract void onRegistrationError(Context context, String errorId);
-
-  /**
-   * Called when a registration token has been received.
-   *
-   * @param context the context the intent was received in
-   * @param registrationId the registration ID received from C2DM
-   */
-  protected abstract void onRegistered(Context context, String registrationId);
-
-  /**
-   * Called when the device has been unregistered.
-   *
-   * @param context the context of the received intent
-   */
-  protected abstract void onUnregistered(Context context);
-
-  /**
-   * Releases the WakeLock registered to the current class.
-   *
-   * The WakeLock is only released if the extra C2DMessaging.EXTRA_RELEASE_WAKELOCK is true.
-   *
-   * @param intent the intent to check for the flag to release the wakelock
-   */
-  protected final void releaseWakeLock(Intent intent) {
-    if (intent.getBooleanExtra(C2DMessaging.EXTRA_RELEASE_WAKELOCK, false)) {
-      WakeLockManager.getInstance(getApplicationContext()).release(getClass());
-    }
-  }
-}
diff --git a/java/com/google/ipc/invalidation/ticl/android/c2dm/C2DMBroadcastReceiver.java b/java/com/google/ipc/invalidation/ticl/android/c2dm/C2DMBroadcastReceiver.java
deleted file mode 100644
index c0f5bfd..0000000
--- a/java/com/google/ipc/invalidation/ticl/android/c2dm/C2DMBroadcastReceiver.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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.android.c2dm;
-
-import android.app.Activity;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-
-/**
- * Helper class to handle BroadcastReceiver behavior. It can only run for a limited amount of time
- * so it starts the real service for longer activities (which then gets the power lock and releases
- * it when it is done).
- *
- * Based on the open source chrometophone project.
- */
-public class C2DMBroadcastReceiver extends BroadcastReceiver {
-
-    @Override
-    public final void onReceive(Context context, Intent intent) {
-        // To keep things in one place, we run everything in the base receiver intent service
-        C2DMManager.runIntentInService(context, intent);
-        setResult(Activity.RESULT_OK, null /* data */, null /* extra */);
-    }
-
-}
diff --git a/java/com/google/ipc/invalidation/ticl/android/c2dm/C2DMManager.java b/java/com/google/ipc/invalidation/ticl/android/c2dm/C2DMManager.java
deleted file mode 100644
index d15b6a7..0000000
--- a/java/com/google/ipc/invalidation/ticl/android/c2dm/C2DMManager.java
+++ /dev/null
@@ -1,656 +0,0 @@
-/*
- * 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.android.c2dm;
-
-import com.google.ipc.invalidation.external.client.SystemResources.Logger;
-import com.google.ipc.invalidation.external.client.android.service.AndroidLogger;
-import com.google.ipc.invalidation.ticl.android.AndroidC2DMConstants;
-
-import android.app.AlarmManager;
-import android.app.IntentService;
-import android.app.PendingIntent;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ServiceInfo;
-import android.os.AsyncTask;
-
-import java.util.HashSet;
-import java.util.Set;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * Class for managing C2DM registration and dispatching of messages to observers.
- *
- * Requires setting the {@link #SENDER_ID_METADATA_FIELD} metadata field with the correct e-mail to
- * be used for the C2DM registration.
- *
- * This is based on the open source chrometophone project.
- */
-public class C2DMManager extends IntentService {
-
-  private static final Logger logger = AndroidLogger.forTag("C2DM");
-
-  /** Maximum amount of time to wait for manager initialization to complete */
-  private static final long MAX_INIT_SECONDS = 30;
-
-  /** Timeout after which wakelocks will be automatically released. */
-  private static final int WAKELOCK_TIMEOUT_MS = 30 * 1000;
-
-  /**
-   * The action of intents sent from the android c2dm framework regarding registration
-   */
-  
-  public static final String REGISTRATION_CALLBACK_INTENT =
-      "com.google.android.c2dm.intent.REGISTRATION";
-
-  /**
-   * The action of intents sent from the Android C2DM framework when we are supposed to retry
-   * registration.
-   */
-  private static final String C2DM_RETRY = "com.google.android.c2dm.intent.RETRY";
-
-  /**
-   * The key in the bundle to use for the sender ID when registering for C2DM.
-   *
-   * The value of the field itself must be the account that the server-side pushing messages
-   * towards the client is using when talking to C2DM.
-   */
-  private static final String EXTRA_SENDER = "sender";
-
-  /**
-   * The key in the bundle to use for boilerplate code identifying the client application towards
-   * the Android C2DM framework
-   */
-  private static final String EXTRA_APPLICATION_PENDING_INTENT = "app";
-
-  /**
-   * The action of intents sent to the Android C2DM framework when we want to register
-   */
-  private static final String REQUEST_UNREGISTRATION_INTENT =
-      "com.google.android.c2dm.intent.UNREGISTER";
-
-  /**
-   * The action of intents sent to the Android C2DM framework when we want to unregister
-   */
-  private static final String REQUEST_REGISTRATION_INTENT =
-      "com.google.android.c2dm.intent.REGISTER";
-
-  /**
-   * The package for the Google Services Framework
-   */
-  private static final String GSF_PACKAGE = "com.google.android.gsf";
-
-  /**
-   * The action of intents sent from the Android C2DM framework when a message is received.
-   */
-  
-  public static final String C2DM_INTENT = "com.google.android.c2dm.intent.RECEIVE";
-
-  /**
-   * The key in the bundle to use when we want to read the C2DM registration ID after a successful
-   * registration
-   */
-  
-  public static final String EXTRA_REGISTRATION_ID = "registration_id";
-
-  /**
-   * The key in the bundle to use when we want to see if we were unregistered from C2DM
-   */
-  
-  static final String EXTRA_UNREGISTERED = "unregistered";
-
-  /**
-   * The key in the bundle to use when we want to see if there was any errors when we tried to
-   * register.
-   */
-  
-  static final String EXTRA_ERROR = "error";
-
-  /**
-   * The android:name we read from the meta-data for the C2DMManager service in the
-   * AndroidManifest.xml file when we want to know which sender id we should use when registering
-   * towards C2DM
-   */
-  
-  static final String SENDER_ID_METADATA_FIELD = "sender_id";
-
-  /**
-   * If {@code true}, newly-registered observers will be informed of the current registration id
-   * if one is already held. Used in  service lifecycle testing to suppress inconvenient
-   * events.
-   */
-  public static final AtomicBoolean disableRegistrationCallbackOnRegisterForTest =
-      new AtomicBoolean(false);
-
-  /**
-   * C2DMMManager is initialized asynchronously because it requires I/O that should not be done on
-   * the main thread.   This latch will only be changed to zero once this initialization has been
-   * completed successfully.   No intents should be handled or other work done until the latch
-   * reaches the initialized state.
-   */
-  private final CountDownLatch initLatch = new CountDownLatch(1);
-
-  /**
-   * The sender ID we have read from the meta-data in AndroidManifest.xml for this service.
-   */
-  private String senderId;
-
-  /**
-   * Observers to dispatch messages from C2DM to
-   */
-  private Set<C2DMObserver> observers;
-
-  /**
-   * A field which is set to true whenever a C2DM registration is in progress. It is set to false
-   * otherwise.
-   */
-  private boolean registrationInProcess;
-
-  /**
-   * The context read during onCreate() which is used throughout the lifetime of this service.
-   */
-  private Context context;
-
-  /**
-   * A field which is set to true whenever a C2DM unregistration is in progress. It is set to false
-   * otherwise.
-   */
-  private boolean unregistrationInProcess;
-
-  /**
-   * A reference to our helper service for handling WakeLocks.
-   */
-  private WakeLockManager wakeLockManager;
-
-  /**
-   * Called from the broadcast receiver and from any observer wanting to register (observers usually
-   * go through calling C2DMessaging.register(...). Will process the received intent, call
-   * handleMessage(), onRegistered(), etc. in background threads, with a wake lock, while keeping
-   * the service alive.
-   *
-   * @param context application to run service in
-   * @param intent the intent received
-   */
-  
-  static void runIntentInService(Context context, Intent intent) {
-    // This is called from C2DMBroadcastReceiver and C2DMessaging, there is no init.
-    WakeLockManager.getInstance(context).acquire(C2DMManager.class, WAKELOCK_TIMEOUT_MS);
-    intent.setClassName(context, C2DMManager.class.getCanonicalName());
-    context.startService(intent);
-  }
-
-  public C2DMManager() {
-    super("C2DMManager");
-    // Always redeliver intents if evicted while processing
-    setIntentRedelivery(true);
-  }
-
-  @Override
-  public void onCreate() {
-    super.onCreate();
-    // Use the mock context when testing, otherwise the service application context.
-    context = getApplicationContext();
-    wakeLockManager = WakeLockManager.getInstance(context);
-
-    // Spawn an AsyncTask performing the blocking IO operations.
-    new AsyncTask<Void, Void, Void>() {
-      @Override
-      protected Void doInBackground(Void... unused) {
-        // C2DMSettings relies on SharedPreferencesImpl which performs disk access.
-        C2DMManager manager = C2DMManager.this;
-        manager.observers = C2DMSettings.getObservers(context);
-        manager.registrationInProcess = C2DMSettings.isRegistering(context);
-        manager.unregistrationInProcess = C2DMSettings.isUnregistering(context);
-        return null;
-      }
-
-      @Override
-      protected void onPostExecute(Void unused) {
-        logger.fine("Initialized");
-        initLatch.countDown();
-      }
-    }.execute();
-
-    senderId = readSenderIdFromMetaData(this);
-    if (senderId == null) {
-      stopSelf();
-    }
-  }
-
-  @Override
-  public final void onHandleIntent(Intent intent) {
-    if (intent == null) {
-      return;
-    }
-    try {
-      // OK to block here (if needed) because IntentService guarantees that onHandleIntent will
-      // only be called on a background thread.
-      logger.fine("Handle intent = %s", intent);
-      waitForInitialization();
-      if (intent.getAction().equals(REGISTRATION_CALLBACK_INTENT)) {
-        handleRegistration(intent);
-      } else if (intent.getAction().equals(C2DM_INTENT)) {
-        onMessage(intent);
-      } else if (intent.getAction().equals(C2DM_RETRY)) {
-        register();
-      } else if (intent.getAction().equals(C2DMessaging.ACTION_REGISTER)) {
-        registerObserver(intent);
-      } else if (intent.getAction().equals(C2DMessaging.ACTION_UNREGISTER)) {
-        unregisterObserver(intent);
-      } else {
-        logger.warning("Received unknown action: %s", intent.getAction());
-      }
-    } finally {
-      // Release the power lock, so device can get back to sleep.
-      // The lock is reference counted by default, so multiple
-      // messages are ok, but because sometimes Android reschedules
-      // services we need to handle the case that the wakelock should
-      // never be underlocked.
-      if (wakeLockManager.isHeld(C2DMManager.class)) {
-        wakeLockManager.release(C2DMManager.class);
-      }
-    }
-  }
-
-  /** Returns true of the C2DMManager is fully initially */
-  
-  boolean isInitialized() {
-    return initLatch.getCount() == 0;
-  }
-
-  /**
-   * Blocks until asynchronous initialization work has been completed.
-   */
-  private void waitForInitialization() {
-    boolean interrupted = false;
-    try {
-      if (initLatch.await(MAX_INIT_SECONDS, TimeUnit.SECONDS)) {
-        return;
-      }
-      logger.warning("Initialization timeout");
-
-    } catch (InterruptedException e) {
-      // Unexpected, so to ensure a consistent state wait for initialization to complete and
-      // then interrupt so higher level code can handle the interrupt.
-      logger.fine("Latch wait interrupted");
-      interrupted = true;
-    } finally {
-      if (interrupted) {
-        logger.warning("Initialization interrupted");
-        Thread.currentThread().interrupt();
-      }
-    }
-
-    // Either an unexpected interrupt or a timeout occurred during initialization.  Set to a default
-    // clean state (no registration work in progress, no observers) and proceed.
-    observers = new HashSet<C2DMObserver>();
-  }
-
-  /**
-   * Called when a cloud message has been received.
-   *
-   * @param intent the received intent
-   */
-  private void onMessage(Intent intent) {
-    boolean matched = false;
-    for (C2DMObserver observer : observers) {
-      if (observer.matches(intent)) {
-        Intent outgoingIntent = createOnMessageIntent(
-            observer.getObserverClass(), context, intent);
-        deliverObserverIntent(observer, outgoingIntent);
-        matched = true;
-      }
-    }
-    if (!matched) {
-      logger.info("No receivers matched intent: %s", intent);
-    }
-  }
-
-  /**
-   * Returns an intent to deliver a C2DM message to {@code observerClass}.
-   * @param context Android context to use to create the intent
-   * @param intent the C2DM message intent to deliver
-   */
-  
-  public static Intent createOnMessageIntent(Class<?> observerClass,
-      Context context, Intent intent) {
-    Intent outgoingIntent = new Intent(intent);
-    outgoingIntent.setAction(C2DMessaging.ACTION_MESSAGE);
-    outgoingIntent.setClass(context, observerClass);
-    return outgoingIntent;
-  }
-
-  /**
-   * Called on registration error. Override to provide better error messages.
-   *
-   * This is called in the context of a Service - no dialog or UI.
-   *
-   * @param errorId the errorId String
-   */
-  private void onRegistrationError(String errorId) {
-    setRegistrationInProcess(false);
-    for (C2DMObserver observer : observers) {
-      deliverObserverIntent(observer,
-          createOnRegistrationErrorIntent(observer.getObserverClass(),
-              context, errorId));
-    }
-  }
-
-  /**
-   * Returns an intent to deliver the C2DM error {@code errorId} to {@code observerClass}.
-   * @param context Android context to use to create the intent
-   */
-  
-  public static Intent createOnRegistrationErrorIntent(Class<?> observerClass,
-      Context context, String errorId) {
-    Intent errorIntent = new Intent(context, observerClass);
-    errorIntent.setAction(C2DMessaging.ACTION_REGISTRATION_ERROR);
-    errorIntent.putExtra(C2DMessaging.EXTRA_REGISTRATION_ERROR, errorId);
-    return errorIntent;
-  }
-
-  /**
-   * Called when a registration token has been received.
-   *
-   * @param registrationId the registration ID received from C2DM
-   */
-  private void onRegistered(String registrationId) {
-    setRegistrationInProcess(false);
-    C2DMSettings.setC2DMRegistrationId(context, registrationId);
-    try {
-      C2DMSettings.setApplicationVersion(context, getCurrentApplicationVersion(this));
-    } catch (NameNotFoundException e) {
-      logger.severe("Unable to find our own package name when storing application version: %s",
-          e.getMessage());
-    }
-    for (C2DMObserver observer : observers) {
-      onRegisteredSingleObserver(registrationId, observer);
-    }
-  }
-
-  /**
-   * Informs the given observer about the registration ID
-   */
-  private void onRegisteredSingleObserver(String registrationId, C2DMObserver observer) {
-    if (!disableRegistrationCallbackOnRegisterForTest.get()) {
-      deliverObserverIntent(observer,
-          createOnRegisteredIntent(observer.getObserverClass(), context, registrationId));
-    }
-  }
-
-  /**
-   * Returns an intent to deliver a new C2DM {@code registrationId} to {@code observerClass}.
-   * @param context Android context to use to create the intent
-   */
-  
-  public static Intent createOnRegisteredIntent(Class<?> observerClass, Context context,
-      String registrationId) {
-    Intent outgoingIntent = new Intent(context, observerClass);
-    outgoingIntent.setAction(C2DMessaging.ACTION_REGISTERED);
-    outgoingIntent.putExtra(C2DMessaging.EXTRA_REGISTRATION_ID, registrationId);
-    return outgoingIntent;
-  }
-
-  /**
-   * Called when the device has been unregistered.
-   */
-  private void onUnregistered() {
-    setUnregisteringInProcess(false);
-    C2DMSettings.clearC2DMRegistrationId(context);
-    for (C2DMObserver observer : observers) {
-      onUnregisteredSingleObserver(observer);
-    }
-  }
-
-  /**
-   * Informs the given observer that the application is no longer registered to C2DM
-   */
-  private void onUnregisteredSingleObserver(C2DMObserver observer) {
-    Intent outgoingIntent = new Intent(context, observer.getObserverClass());
-    outgoingIntent.setAction(C2DMessaging.ACTION_UNREGISTERED);
-    deliverObserverIntent(observer, outgoingIntent);
-  }
-
-  /**
-   * Starts the observer service by delivering it the provided intent. If the observer has asked us
-   * to get a WakeLock for it, we do that and inform the observer that the WakeLock has been
-   * acquired through the flag C2DMessaging.EXTRA_RELEASE_WAKELOCK.
-   */
-  private void deliverObserverIntent(C2DMObserver observer, Intent intent) {
-    if (observer.isHandleWakeLock()) {
-      // Set the extra so the observer knows that it needs to release the wake lock
-      intent.putExtra(C2DMessaging.EXTRA_RELEASE_WAKELOCK, true);
-      wakeLockManager.acquire(observer.getObserverClass(), WAKELOCK_TIMEOUT_MS);
-    }
-    context.startService(intent);
-  }
-
-  /**
-   * Registers an observer.
-   *
-   *  If this was the first observer we also start registering towards C2DM. If we were already
-   * registered, we do a callback to inform about the current C2DM registration ID.
-   *
-   * <p>We also start a registration if the application version stored does not match the
-   * current version number. This leads to any observer registering after an upgrade will trigger
-   * a new C2DM registration.
-   */
-  private void registerObserver(Intent intent) {
-    C2DMObserver observer = C2DMObserver.createFromIntent(intent);
-    observers.add(observer);
-    C2DMSettings.setObservers(context, observers);
-    if (C2DMSettings.hasC2DMRegistrationId(context)) {
-      onRegisteredSingleObserver(C2DMSettings.getC2DMRegistrationId(context), observer);
-      if (!isApplicationVersionCurrent() && !isRegistrationInProcess()) {
-        logger.fine("Registering to C2DM since application version is not current.");
-        register();
-      }
-    } else {
-      if (!isRegistrationInProcess()) {
-        logger.fine("Registering to C2DM since we have no C2DM registration.");
-        register();
-      }
-    }
-  }
-
-  /**
-   * Unregisters an observer.
-   *
-   *  The observer is moved to unregisteringObservers which only gets messages from C2DMManager if
-   * we unregister from C2DM completely. If this was the last observer, we also start the process of
-   * unregistering from C2DM.
-   */
-  private void unregisterObserver(Intent intent) {
-    C2DMObserver observer = C2DMObserver.createFromIntent(intent);
-    if (observers.remove(observer)) {
-      C2DMSettings.setObservers(context, observers);
-      onUnregisteredSingleObserver(observer);
-    }
-    if (observers.isEmpty()) {
-      // No more observers, need to unregister
-      if (!isUnregisteringInProcess()) {
-        unregister();
-      }
-    }
-  }
-
-  /**
-   * Called when the Android C2DM framework sends us a message regarding registration.
-   *
-   *  This method parses the intent from the Android C2DM framework and calls the appropriate
-   * methods for when we are registered, unregistered or if there was an error when trying to
-   * register.
-   */
-  private void handleRegistration(Intent intent) {
-    String registrationId = intent.getStringExtra(EXTRA_REGISTRATION_ID);
-    String error = intent.getStringExtra(EXTRA_ERROR);
-    String removed = intent.getStringExtra(EXTRA_UNREGISTERED);
-    logger.fine("Got registration message: registrationId = %s, error = %s, removed = %s",
-                registrationId, error, removed);
-    if (removed != null) {
-      onUnregistered();
-    } else if (error != null) {
-      handleRegistrationBackoffOnError(error);
-    } else {
-      handleRegistration(registrationId);
-    }
-  }
-
-  /**
-   * Informs observers about a registration error, and schedules a registration retry if the error
-   * was transient.
-   */
-  private void handleRegistrationBackoffOnError(String error) {
-    logger.severe("Registration error %s", error);
-    onRegistrationError(error);
-    if (C2DMessaging.ERR_SERVICE_NOT_AVAILABLE.equals(error)) {
-      long backoffTimeMs = C2DMSettings.getBackoff(context);
-      createAlarm(backoffTimeMs);
-      increaseBackoff(backoffTimeMs);
-    }
-  }
-
-  /**
-   * When C2DM registration fails, we call this method to schedule a retry in the future.
-   */
-  private void createAlarm(long backoffTimeMs) {
-    logger.fine("Scheduling registration retry, backoff = %d", backoffTimeMs);
-    Intent retryIntent = new Intent(C2DM_RETRY);
-    PendingIntent retryPIntent = PendingIntent.getBroadcast(context, 0, retryIntent, 0);
-    AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
-    am.set(AlarmManager.ELAPSED_REALTIME, backoffTimeMs, retryPIntent);
-  }
-
-  /**
-   * Increases the backoff time for retrying C2DM registration
-   */
-  private void increaseBackoff(long backoffTimeMs) {
-    backoffTimeMs *= 2;
-    C2DMSettings.setBackoff(context, backoffTimeMs);
-  }
-
-  /**
-   * When C2DM registration is complete, this method resets the backoff and makes sure all observers
-   * are informed
-   */
-  private void handleRegistration(String registrationId) {
-    C2DMSettings.resetBackoff(context);
-    onRegistered(registrationId);
-  }
-
-  private void setRegistrationInProcess(boolean registrationInProcess) {
-    C2DMSettings.setRegistering(context, registrationInProcess);
-    this.registrationInProcess = registrationInProcess;
-  }
-
-  private boolean isRegistrationInProcess() {
-    return registrationInProcess;
-  }
-
-  private void setUnregisteringInProcess(boolean unregisteringInProcess) {
-    C2DMSettings.setUnregistering(context, unregisteringInProcess);
-    this.unregistrationInProcess = unregisteringInProcess;
-  }
-
-  private boolean isUnregisteringInProcess() {
-    return unregistrationInProcess;
-  }
-
-  /**
-   * Initiate c2d messaging registration for the current application
-   */
-  private void register() {
-    Intent registrationIntent = new Intent(REQUEST_REGISTRATION_INTENT);
-    registrationIntent.setPackage(GSF_PACKAGE);
-    registrationIntent.putExtra(
-        EXTRA_APPLICATION_PENDING_INTENT, PendingIntent.getBroadcast(context, 0, new Intent(), 0));
-    registrationIntent.putExtra(EXTRA_SENDER, senderId);
-    setRegistrationInProcess(true);
-    context.startService(registrationIntent);
-  }
-
-  /**
-   * Unregister the application. New messages will be blocked by server.
-   */
-  private void unregister() {
-    Intent regIntent = new Intent(REQUEST_UNREGISTRATION_INTENT);
-    regIntent.setPackage(GSF_PACKAGE);
-    regIntent.putExtra(
-        EXTRA_APPLICATION_PENDING_INTENT, PendingIntent.getBroadcast(context, 0, new Intent(), 0));
-    setUnregisteringInProcess(true);
-    context.startService(regIntent);
-  }
-
-  /**
-   * Checks if the stored application version is the same as the current application version.
-   */
-  private boolean isApplicationVersionCurrent() {
-    try {
-      String currentApplicationVersion = getCurrentApplicationVersion(this);
-      if (currentApplicationVersion == null) {
-        return false;
-      }
-      return currentApplicationVersion.equals(C2DMSettings.getApplicationVersion(context));
-    } catch (NameNotFoundException e) {
-      logger.fine("Unable to find our own package name when reading application version: %s",
-                     e.getMessage());
-      return false;
-    }
-  }
-
-  /**
-   * Retrieves the current application version.
-   */
-  
-  public static String getCurrentApplicationVersion(Context context) throws NameNotFoundException {
-    PackageInfo packageInfo =
-        context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
-    return packageInfo.versionName;
-  }
-
-  /**
-   * Reads the meta-data to find the field specified in SENDER_ID_METADATA_FIELD. The value of that
-   * field is used when registering towards C2DM. If no value is found,
-   * {@link AndroidC2DMConstants#SENDER_ID} is returned.
-   */
-  static String readSenderIdFromMetaData(Context context) {
-    String senderId = AndroidC2DMConstants.SENDER_ID;
-    try {
-      ServiceInfo serviceInfo = context.getPackageManager().getServiceInfo(
-          new ComponentName(context, C2DMManager.class), PackageManager.GET_META_DATA);
-      if (serviceInfo.metaData != null) {
-        String manifestSenderId = serviceInfo.metaData.getString(SENDER_ID_METADATA_FIELD);
-        if (manifestSenderId != null) {
-          logger.fine("Using manifest-specified sender-id: %s", manifestSenderId);
-          senderId = manifestSenderId;
-        } else {
-          logger.severe("No meta-data element with the name %s found on the service declaration",
-                        SENDER_ID_METADATA_FIELD);
-        }
-      }
-    } catch (NameNotFoundException exception) {
-      logger.info("Could not find C2DMManager service info in manifest");
-    }
-    return senderId;
-  }
-}
diff --git a/java/com/google/ipc/invalidation/ticl/android/c2dm/C2DMObserver.java b/java/com/google/ipc/invalidation/ticl/android/c2dm/C2DMObserver.java
deleted file mode 100644
index 51c8403..0000000
--- a/java/com/google/ipc/invalidation/ticl/android/c2dm/C2DMObserver.java
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * 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.android.c2dm;
-
-
-import com.google.common.base.Preconditions;
-import com.google.ipc.invalidation.external.client.SystemResources.Logger;
-import com.google.ipc.invalidation.external.client.android.service.AndroidLogger;
-
-import android.app.Service;
-import android.content.Intent;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-/**
- * Represents a C2DM observer that gets notifications whenever the
- * application receives a C2DM message or something changes regarding C2DM registration status.
- *
- * An observer may have its own unique filter so that not all messages are dispatched to all
- * observers.
- */
-public class C2DMObserver {
-
-  /** Logger */
-  private static final Logger logger = AndroidLogger.forTag("C2DMObserver");
-
-  /** JSON key name for the observer class name string value */
-  private static final String KEY_CLASS = "class";
-
-  /** JSON key name for the filter field name string value */
-  private static final String KEY_FILTER_KEY = "filterKey";
-
-  /** JSON key name for the value field string value */
-  private static final String KEY_FILTER_VALUE = "filterValue";
-
-  /** JSON kye name for the handle wake lock boolean field */
-  private static final String KEY_HANDLE_WAKE_LOCK = "handleWakeLock";
-
-  /** Service class that handles messages for this observer */
-  private final Class<? extends Service> messageService;
-
-  /** Select field name (or {@code null} if none) */
-  private final String selectKey;
-
-  /** Select field value (or {@code null} if none) */
-  private final String selectValue;
-
-  /** {@code true} if the observer handles the wake lock */
-  private final boolean handleWakeLock;
-
-  /**
-   * Creates a new observer using the state stored within the provided JSON object (normally
-   * created by {@link #toJSON()}.
-   */
-  static C2DMObserver createFromJSON(JSONObject json) {
-    try {
-      // Extract instance state value from the appropriate JSON fields.
-      String canonicalClassString = json.getString(KEY_CLASS);
-      Class<? extends Service> clazz =
-          Class.forName(canonicalClassString).asSubclass(Service.class);
-      String filterKey = json.has(KEY_FILTER_KEY) ? json.getString(KEY_FILTER_KEY) : null;
-      String filterValue = json.has(KEY_FILTER_VALUE) ? json.getString(KEY_FILTER_VALUE) : null;
-      Boolean handleWakeLock =
-          json.has(KEY_HANDLE_WAKE_LOCK) && json.getBoolean(KEY_HANDLE_WAKE_LOCK);
-      return new C2DMObserver(clazz, filterKey, filterValue, handleWakeLock);
-    } catch (JSONException e) {
-      logger.severe("Unable to parse observer. Source: %s", json);
-    } catch (ClassNotFoundException e) {
-      logger.severe("Unable to parse observer. Class not found. Source: %s", json);
-    }
-    return null;
-  }
-
-  /**
-   * Creates a new observer from the extra values contained in the provided intent.
-   */
-  static C2DMObserver createFromIntent(Intent intent) {
-    String canonicalClassString = intent.getStringExtra(C2DMessaging.EXTRA_CANONICAL_CLASS);
-    try {
-      // Extract observer state from the intent built by the C2DM manager.
-      Class<? extends Service> clazz =
-          Class.forName(canonicalClassString).asSubclass(Service.class);
-      String filterKey = intent.getStringExtra(C2DMessaging.EXTRA_FILTER_KEY);
-      String filterValue = intent.getStringExtra(C2DMessaging.EXTRA_FILTER_VALUE);
-      boolean handleWakeLock = intent.getBooleanExtra(C2DMessaging.EXTRA_HANDLE_WAKELOCK, false);
-      return new C2DMObserver(clazz, filterKey, filterValue, handleWakeLock);
-    } catch (ClassNotFoundException e) {
-      logger.severe("Unable to register observer class %s", canonicalClassString);
-      return null;
-    }
-  }
-
-  /**
-   * Creates a new observer for the provided service, selection criteria, and wake lock behavior.
-   */
-  
-  C2DMObserver(Class<? extends Service> messageService, String selectKey, String selectValue,
-      boolean handleWakeLock) {
-    Preconditions.checkNotNull(messageService);
-    this.messageService = messageService;
-    this.selectKey = selectKey;
-    this.selectValue = selectValue;
-    this.handleWakeLock = handleWakeLock;
-  }
-
-  /**
-   * Returns the JSON object representation of the observer state.
-   */
-  JSONObject toJSON() {
-    try {
-      JSONObject json = new JSONObject();
-      json.put(KEY_CLASS, messageService.getCanonicalName());
-      json.put(KEY_FILTER_KEY, selectKey);
-      json.put(KEY_FILTER_VALUE, selectValue);
-      json.put(KEY_HANDLE_WAKE_LOCK, handleWakeLock);
-      return json;
-    } catch (JSONException e) {
-      logger.severe("Unable to create JSON object from observer %s", toString());
-      return null;
-    }
-  }
-
-  /**
-   * Returns {@code true} if the provided intent matches the selection criteria for this
-   * observer.
-   */
-  boolean matches(Intent intent) {
-    if (selectKey == null) {
-      return true;
-    }
-    if (intent.hasExtra(selectKey)) {
-      return selectValue == null || selectValue.equals(intent.getStringExtra(selectKey));
-    }
-    return false;
-  }
-
-  Class<?> getObserverClass() {
-    return messageService;
-  }
-
-  
-  String getFilterKey() {
-    return selectKey;
-  }
-
-  
-  String getFilterValue() {
-    return selectValue;
-  }
-
-  
-  boolean isHandleWakeLock() {
-    return handleWakeLock;
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (this == o) {
-      return true;
-    }
-    if (o == null || getClass() != o.getClass()) {
-      return false;
-    }
-    C2DMObserver that = (C2DMObserver) o;
-    if (!messageService.equals(that.messageService)) {
-      return false;
-    }
-    if (selectKey != null ? !selectKey.equals(that.selectKey) : that.selectKey != null) {
-      return false;
-    }
-    if (selectValue != null ? !selectValue.equals(that.selectValue) : that.selectValue
-        != null) {
-      return false;
-    }
-    return handleWakeLock == that.handleWakeLock;
-  }
-
-  @Override
-  public int hashCode() {
-    int result = messageService.hashCode();
-    result = 31 * result + (selectKey != null ? selectKey.hashCode() : 0);
-    result = 31 * result + (selectValue != null ? selectValue.hashCode() : 0);
-    result = 31 * result + (handleWakeLock ? 1 : 0);
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "C2DMObserver{" + "mClass=" + messageService + ", mFilterKey='" + selectKey + '\''
-        + ", mFilterValue='" + selectValue + '\'' + ", mHandleWakeLock=" + handleWakeLock + '}';
-  }
-}
diff --git a/java/com/google/ipc/invalidation/ticl/android/c2dm/C2DMSettings.java b/java/com/google/ipc/invalidation/ticl/android/c2dm/C2DMSettings.java
deleted file mode 100644
index 481ecaf..0000000
--- a/java/com/google/ipc/invalidation/ticl/android/c2dm/C2DMSettings.java
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * 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.android.c2dm;
-
-
-import com.google.ipc.invalidation.external.client.SystemResources.Logger;
-import com.google.ipc.invalidation.external.client.android.service.AndroidLogger;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * Stores and provides access to private settings used by the C2DM manager.
- */
-public class C2DMSettings {
-
-  private static final Logger logger = AndroidLogger.forTag("C2DMSettings");
-
-  
-  static final String PREFERENCE_PACKAGE = "com.google.android.c2dm.manager";
-
-  
-  static final String REGISTRATION_ID = "registrationId";
-
-  private static final String APPLICATION_VERSION = "applicationVersion";
-
-  private static final String BACKOFF = "c2dm_backoff";
-
-  private static final long BACKOFF_DEFAULT = 30000;
-
-  private static final String OBSERVERS = "observers";
-
-  private static final String REGISTERING = "registering";
-
-  private static final String UNREGISTERING = "unregistering";
-
-  /**
-   * Sets the C2DM registration ID.
-   */
-  static void setC2DMRegistrationId(Context context, String registrationId) {
-    storeField(context, REGISTRATION_ID, registrationId);
-  }
-
-  /**
-   * Clears the C2DM registration ID.
-   */
-  static void clearC2DMRegistrationId(Context context) {
-    storeField(context, REGISTRATION_ID, null);
-  }
-
-  /**
-   * Retrieves the C2DM registration ID (or {@code null} if not stored).
-   */
-  static String getC2DMRegistrationId(Context context) {
-    return retrieveField(context, REGISTRATION_ID, null);
-  }
-
-  /**
-   * Returns {@code true} if there is a C2DM registration ID stored.
-   */
-  static boolean hasC2DMRegistrationId(Context context) {
-    return getC2DMRegistrationId(context) != null;
-  }
-
-  /**
-   * Sets the application version.
-   */
-  static void setApplicationVersion(Context context, String applicationVersion) {
-    storeField(context, APPLICATION_VERSION, applicationVersion);
-  }
-
-  /**
-   * Retrieves the application version (or {@code null} if not stored).
-   */
-  static String getApplicationVersion(Context context) {
-    return retrieveField(context, APPLICATION_VERSION, null);
-  }
-
-  /**
-   * Returns the backoff setting.
-   */
-  static long getBackoff(Context context) {
-    return retrieveField(context, BACKOFF, BACKOFF_DEFAULT);
-  }
-
-  /**
-   * Sets the backoff setting.
-   * @param context
-   * @param backoff
-   */
-  static void setBackoff(Context context, long backoff) {
-    storeField(context, BACKOFF, backoff);
-  }
-
-  /**
-   * Resets the backoff setting to the default value.
-   */
-  static void resetBackoff(Context context) {
-    setBackoff(context, BACKOFF_DEFAULT);
-  }
-
-  /**
-   * Sets the boolean flag indicating C2DM registration is in process.
-   */
-  static void setRegistering(Context context, boolean registering) {
-    storeField(context, REGISTERING, registering);
-  }
-
-  /**
-   * Returns {@code true} if C2DM registration is in process.
-   */
-  static boolean isRegistering(Context context) {
-    return retrieveField(context, REGISTERING, false);
-  }
-
-  /**
-   * Sets the boolean flag indicating C2DM unregistration is in process.
-   */
-  static void setUnregistering(Context context, boolean registering) {
-    storeField(context, UNREGISTERING, registering);
-  }
-
-  /**
-   * Returns the boolean flag indicating C2DM unregistration is in process.
-   */
-  static boolean isUnregistering(Context context) {
-    return retrieveField(context, UNREGISTERING, false);
-  }
-
-  /**
-   * Returns the set of stored observers.
-   */
-  static Set<C2DMObserver> getObservers(Context context) {
-    return createC2DMObserversFromJSON(retrieveField(context, OBSERVERS, null));
-  }
-
-  /**
-   * Sets the set of stored observers.
-   */
-  static void setObservers(Context context, Set<C2DMObserver> observers) {
-    storeField(context, OBSERVERS, createJsonObserversFromC2DMObservers(observers));
-  }
-
-  private static Set<C2DMObserver> createC2DMObserversFromJSON(String jsonString) {
-    // The observer set is stored in a json array of objects that contain the
-    // observer json representation produced by C2DMObserver.toJSON.   Iterate over
-    // this array and recreate observers from the objects.
-    Set<C2DMObserver> observers = new HashSet<C2DMObserver>();
-    if (jsonString == null) {
-      return observers;
-    }
-    try {
-      JSONArray array = new JSONArray(jsonString);
-      for (int i = 0; i < array.length(); i++) {
-        JSONObject jsonObserver = array.getJSONObject(i);
-        C2DMObserver observer = C2DMObserver.createFromJSON(jsonObserver);
-        if (observer != null) {
-          observers.add(observer);
-        }
-      }
-    } catch (JSONException e) {
-      logger.severe("Unable to parse observers. Source: %s", jsonString);
-      observers.clear(); // No partial result
-    }
-    return observers;
-  }
-
-  private static String createJsonObserversFromC2DMObservers(Set<C2DMObserver> observers) {
-    // Stores the observers as an array of json objects in the format produced by
-    // C2DMObserver.toJSON
-    JSONArray array = new JSONArray();
-    for (C2DMObserver observer : observers) {
-      JSONObject json = observer.toJSON();
-      if (json != null) {
-        array.put(json);
-      }
-    }
-    return array.toString();
-  }
-
-  private static boolean retrieveField(Context context, String field, boolean defaultValue) {
-    SharedPreferences preferences = getPreferences(context);
-    return preferences.getBoolean(field, defaultValue);
-  }
-
-  private static void storeField(Context context, String field, boolean value) {
-    SharedPreferences preferences = getPreferences(context);
-    SharedPreferences.Editor editor = preferences.edit();
-    editor.putBoolean(field, value);
-    editor.commit();
-  }
-
-  private static long retrieveField(Context context, String field, long defaultValue) {
-    SharedPreferences preferences = getPreferences(context);
-    return preferences.getLong(field, defaultValue);
-  }
-
-  private static void storeField(Context context, String field, long value) {
-    SharedPreferences preferences = getPreferences(context);
-    SharedPreferences.Editor editor = preferences.edit();
-    editor.putLong(field, value);
-    editor.commit();
-  }
-
-  private static String retrieveField(Context context, String field, String defaultValue) {
-    SharedPreferences preferences = getPreferences(context);
-    return preferences.getString(field, defaultValue);
-  }
-
-  private static void storeField(Context context, String field, String value) {
-    SharedPreferences preferences = getPreferences(context);
-    SharedPreferences.Editor editor = preferences.edit();
-    editor.putString(field, value);
-    editor.commit();
-    if (value == null) {
-      logger.fine("Cleared field %s", field);
-    }
-  }
-
-  private static SharedPreferences getPreferences(Context context) {
-    return context.getSharedPreferences(PREFERENCE_PACKAGE, Context.MODE_PRIVATE);
-  }
-
-  /** Sets the C2DM registration id to {@code registrationId}. */
-  public static void setC2DMRegistrationIdForTest(Context context, String registrationId) {
-    setC2DMRegistrationId(context, registrationId);
-  }
-
-  /** Sets the C2DM application version to {@code version}. */
-  public static void setApplicationVersionForTest(Context context, String version) {
-    setApplicationVersion(context, version);
-  }
-}
diff --git a/java/com/google/ipc/invalidation/ticl/android/c2dm/C2DMTestUtil.java b/java/com/google/ipc/invalidation/ticl/android/c2dm/C2DMTestUtil.java
deleted file mode 100644
index 8ae9428..0000000
--- a/java/com/google/ipc/invalidation/ticl/android/c2dm/C2DMTestUtil.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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.android.c2dm;
-
-
-import android.content.Context;
-
-/**
- * Provides utility methods that allow manipulation of underlying C2DM state for testing.
- *
- */
-
-public class C2DMTestUtil {
-
-  // Not instantiable
-  private C2DMTestUtil() {}
-
-  /**
-   * Clears the C2DM registration ID for the application from within settings.
-   */
-  public static void clearRegistrationId(Context context) {
-    C2DMSettings.clearC2DMRegistrationId(context);
-  }
-
-  /**
-   * Sets the C2DM registration ID for the application stored within settings.
-   */
-  public static void setRegistrationId(Context context, String registrationId) {
-    C2DMSettings.setC2DMRegistrationId(context, registrationId);
-  }
-}
diff --git a/java/com/google/ipc/invalidation/ticl/android/c2dm/C2DMessaging.java b/java/com/google/ipc/invalidation/ticl/android/c2dm/C2DMessaging.java
deleted file mode 100644
index 8fb2eba..0000000
--- a/java/com/google/ipc/invalidation/ticl/android/c2dm/C2DMessaging.java
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * 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.android.c2dm;
-
-import android.app.Service;
-import android.content.Context;
-import android.content.Intent;
-
-
-/**
- * Utilities for device registration.
- *
- *  Will keep track of the registration token in a private preference.
- *
- * This is based on the open source chrometophone project.
- */
-public class C2DMessaging {
-  static final String ACTION_MESSAGE = "com.google.android.c2dm.manager.intent.MESSAGE";
-
-  static final String ACTION_REGISTER = "com.google.android.c2dm.manager.intent.REGISTER";
-
-  static final String ACTION_UNREGISTER = "com.google.android.c2dm.manager.intent.UNREGISTER";
-
-  static final String ACTION_REGISTERED = "com.google.android.c2dm.manager.intent.REGISTERED";
-
-  static final String ACTION_UNREGISTERED = "com.google.android.c2dm.manager.intent.UNREGISTERED";
-
-  static final String ACTION_REGISTRATION_ERROR =
-      "com.google.android.c2dm.manager.intent.REGISTRATION_ERROR";
-
-  static final String EXTRA_REGISTRATION_ID =
-      "com.google.android.c2dm.manager.extra.REGISTRATION_ID";
-
-  static final String EXTRA_REGISTRATION_ERROR = "com.google.android.c2dm.manager.extra.ERROR";
-
-  static final String EXTRA_CANONICAL_CLASS =
-      "com.google.android.c2dm.manager.extra.CANONICAL_CLASS";
-
-  static final String EXTRA_FILTER_KEY = "com.google.android.c2dm.manager.extra.FILTER_KEY";
-
-  static final String EXTRA_FILTER_VALUE = "com.google.android.c2dm.manager.extra.FILTER_VALUE";
-
-  static final String EXTRA_HANDLE_WAKELOCK =
-      "com.google.android.c2dm.manager.extra.HANDLE_WAKELOCK";
-
-  static final String EXTRA_RELEASE_WAKELOCK =
-      "com.google.android.c2dm.manager.extra.RELEASE_WAKELOCK";
-
-  /**
-   * The device can't read the response, or there was a 500/503 from the server that can be retried
-   * later. The C2DMManager will automatically use exponential back off and retry.
-   */
-  public static final String ERR_SERVICE_NOT_AVAILABLE = "SERVICE_NOT_AVAILABLE";
-
-  /**
-   * There is no Google account on the phone. The application should ask the user to open the
-   * account manager and add a Google account. Fix on the device side.
-   */
-  public static final String ERR_ACCOUNT_MISSING = "ACCOUNT_MISSING";
-
-  /**
-   * Bad password. The application should ask the user to enter his/her password, and let user retry
-   * manually later. Fix on the device side.
-   */
-  public static final String ERR_AUTHENTICATION_FAILED = "AUTHENTICATION_FAILED";
-
-  /**
-   * The user has too many applications registered. The application should tell the user to
-   * uninstall some other applications, let user retry manually. Fix on the device side.
-   */
-  public static final String ERR_TOO_MANY_REGISTRATIONS = "TOO_MANY_REGISTRATIONS";
-
-  /**
-   * Invalid parameters found in C2DM registration or message.
-   */
-  public static final String ERR_INVALID_PARAMETERS = "INVALID_PARAMETERS";
-
-  /**
-   * The sender account is not recognized.
-   */
-  public static final String ERR_INVALID_SENDER = "INVALID_SENDER";
-
-  /** Incorrect phone registration with Google. This phone doesn't currently support C2DM. */
-  public static final String ERR_PHONE_REGISTRATION_ERROR = "PHONE_REGISTRATION_ERROR";
-
-  public static String getSenderId(Context context) {
-    return C2DMManager.readSenderIdFromMetaData(context);
-  }
-
-  /**
-   * Returns the current C2DM registration ID for the application or {@code null} if not yet full
-   * registered.
-   */
-  public static String getRegistrationId(Context context) {
-    return C2DMSettings.getC2DMRegistrationId(context);
-  }
-
-  /**
-   * Registers a new C2DM observer service that will receive registration notifications and
-   * delivered messages. Receipt of messages can be made conditional based upon the presence of a
-   * particular extra in the c2dm message and optionally the value of that extra.
-   *
-   * @param context the current application context
-   * @param clazz the service that will receive c2dm activity intents
-   * @param selectKey the name of an extra that will be present in messages selected for this
-   *        observer. If {@code null}, all messages are delivered.
-   * @param selectValue defines a specific value that must match for the messages selected for this
-   *        observer. If {@code null}, any value will match.
-   * @param handleWakeLock if {@code true} indicates that a wake lock should be acquired from the
-   *        {@link WakeLockManager} before messages are delivered to the observer and that the
-   *        observer will be responsible for releasing the lock.
-   */
-  public static void register(Context context, Class<? extends Service> clazz,
-      String selectKey, String selectValue, boolean handleWakeLock) {
-
-    Intent intent = new Intent();
-    intent.setAction(ACTION_REGISTER);
-    intent.putExtra(EXTRA_CANONICAL_CLASS, clazz.getCanonicalName());
-    intent.putExtra(EXTRA_FILTER_KEY, selectKey);
-    intent.putExtra(EXTRA_FILTER_VALUE, selectValue);
-    intent.putExtra(EXTRA_HANDLE_WAKELOCK, handleWakeLock);
-    C2DMManager.runIntentInService(context, intent);
-  }
-
-  /**
-   * Unregisters an existing C2DM observer service so it will no longer receive notifications or
-   * messages (or than a final unregister notification indicating that the observer has been
-   * unregistered.
-   *
-   * @param context the current application context
-   * @param clazz the service that will receive c2dm activity intents
-   * @param selectKey the name of an extra that will be present in messages selected for this
-   *        observer. If {@code null}, all messages are delivered.
-   * @param selectValue defines a specific value that must match for the messages selected for this
-   *        observer. If {@code null}, any value will match.
-   * @param handleWakeLock if {@code true} indicates that a wake lock should be acquired from the
-   *        {@link WakeLockManager} before messages are delivered to the observer and that the
-   *        observer will be responsible for releasing the lock.
-   */
-  public static void unregister(Context context, Class<?> clazz, String selectKey,
-      String selectValue, boolean handleWakeLock) {
-    Intent intent = new Intent();
-    intent.setAction(ACTION_UNREGISTER);
-    intent.putExtra(EXTRA_CANONICAL_CLASS, clazz.getCanonicalName());
-    intent.putExtra(EXTRA_FILTER_KEY, selectKey);
-    intent.putExtra(EXTRA_FILTER_VALUE, selectValue);
-    intent.putExtra(EXTRA_HANDLE_WAKELOCK, handleWakeLock);
-    C2DMManager.runIntentInService(context, intent);
-  }
-}
diff --git a/java/com/google/ipc/invalidation/ticl/android2/AndroidIntentProtocolValidator.java b/java/com/google/ipc/invalidation/ticl/android2/AndroidIntentProtocolValidator.java
deleted file mode 100644
index b12f406..0000000
--- a/java/com/google/ipc/invalidation/ticl/android2/AndroidIntentProtocolValidator.java
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * 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.common.ClientProtocolAccessor;
-import com.google.ipc.invalidation.common.ClientProtocolAccessor.VersionAccessor;
-import com.google.ipc.invalidation.common.ProtoValidator;
-import com.google.ipc.invalidation.external.client.SystemResources.Logger;
-import com.google.ipc.invalidation.ticl.android2.AndroidServiceAccessor.AndroidNetworkSendRequestAccessor;
-import com.google.ipc.invalidation.ticl.android2.AndroidServiceAccessor.AndroidTiclStateAccessor;
-import com.google.ipc.invalidation.ticl.android2.AndroidServiceAccessor.AndroidTiclStateAccessor.MetadataAccessor;
-import com.google.ipc.invalidation.ticl.android2.AndroidServiceAccessor.AndroidTiclStateWithDigestAccessor;
-import com.google.ipc.invalidation.ticl.android2.AndroidServiceAccessor.ClientDowncallAccessor;
-import com.google.ipc.invalidation.ticl.android2.AndroidServiceAccessor.InternalDowncallAccessor;
-import com.google.ipc.invalidation.ticl.android2.AndroidServiceAccessor.ListenerUpcallAccessor;
-import com.google.protobuf.MessageLite;
-import com.google.protos.ipc.invalidation.AndroidService.AndroidNetworkSendRequest;
-import com.google.protos.ipc.invalidation.AndroidService.AndroidSchedulerEvent;
-import com.google.protos.ipc.invalidation.AndroidService.AndroidTiclStateWithDigest;
-import com.google.protos.ipc.invalidation.AndroidService.ClientDowncall;
-import com.google.protos.ipc.invalidation.AndroidService.InternalDowncall;
-import com.google.protos.ipc.invalidation.AndroidService.ListenerUpcall;
-import com.google.protos.ipc.invalidation.ClientProtocol.Version;
-
-/**
- * Validator for Android internal protocol intents and messages.
- * <p>
- * This class works by defining instances of {@code MessageInfo} for each protocol buffer
- * that requires validation. A {@code MessageInfo} takes two parameters: an <i>accessor</i>
- * that allows it to read the fields of an instance of the message to be validated, and a list
- * of {@code FieldInfo} objects that, for each field in the message, specify whether the field
- * is required or optional. Additionally, a {@code FieldInfo} may have a reference to a
- * {@code MessageInfo} object that specifies how to recursively validate the field.
- * <p>
- * For example, the validation for the {@code ACK} downcall protocol buffer is specified as follows:
- * <code>
- * static final MessageInfo ACK = new MessageInfo(
- *       ClientDowncallAccessor.ACK_DOWNCALL_ACCESSOR,
- *       FieldInfo.newRequired(ClientDowncallAccessor.AckDowncallAccessor.ACK_HANDLE));
- * </code>
- * This specifies that the {@code ACK_DOWNCALL_ACCESSOR} is to be used to read the fields of
- * protocol buffers to be validated, and that instances of those protocol buffers should have
- * exactly one field (ack handle) set.
- * <p>
- * For a more complicated example, the {{@link DowncallMessageInfos#REGISTRATIONS} validator
- * requires one or the other (but not both) of two fields to be set, and those fields are
- * recursively validated.
- *
- */
-public final class AndroidIntentProtocolValidator extends ProtoValidator {
-  /** Validation for composite (major/minor) versions. */
-  static final MessageInfo VERSION = new MessageInfo(ClientProtocolAccessor.VERSION_ACCESSOR,
-    FieldInfo.newRequired(VersionAccessor.MAJOR_VERSION),
-    FieldInfo.newRequired(VersionAccessor.MINOR_VERSION)) {
-    @Override
-    public boolean postValidate(MessageLite message) {
-      // Versions must be non-negative.
-      Version version = (Version) message;
-      if ((version.getMajorVersion() < 0) || (version.getMinorVersion() < 0)) {
-        return false;
-      }
-      return true;
-    }
-  };
-
-  /** Validation for public client downcalls. */
-  static class DowncallMessageInfos {
-    static final MessageInfo ACK = new MessageInfo(
-        ClientDowncallAccessor.ACK_DOWNCALL_ACCESSOR,
-        FieldInfo.newRequired(ClientDowncallAccessor.AckDowncallAccessor.ACK_HANDLE));
-
-    static final MessageInfo REGISTRATIONS = new MessageInfo(
-        ClientDowncallAccessor.REGISTRATION_DOWNCALL_ACCESSOR,
-        FieldInfo.newOptional(ClientDowncallAccessor.RegistrationDowncallAccessor.REGISTRATIONS),
-        FieldInfo.newOptional(
-            ClientDowncallAccessor.RegistrationDowncallAccessor.UNREGISTRATIONS)) {
-      @Override
-      public boolean postValidate(MessageLite message) {
-        int numSetFields = 0;
-        for (FieldInfo fieldInfo : getAllFields()) {
-          if (ClientDowncallAccessor.REGISTRATION_DOWNCALL_ACCESSOR.hasField(
-              message, fieldInfo.getFieldDescriptor())) {
-           ++numSetFields;
-          }
-        }
-        return numSetFields == 1; // Registrations or unregistrations, but not both.
-      }
-    };
-
-    static final MessageInfo DOWNCALL_MSG = new MessageInfo(
-        AndroidServiceAccessor.CLIENT_DOWNCALL_ACCESSOR,
-        FieldInfo.newRequired(AndroidServiceAccessor.ClientDowncallAccessor.VERSION, VERSION),
-        FieldInfo.newOptional(AndroidServiceAccessor.ClientDowncallAccessor.SERIAL),
-        FieldInfo.newOptional(AndroidServiceAccessor.ClientDowncallAccessor.ACK, ACK),
-        FieldInfo.newOptional(
-            AndroidServiceAccessor.ClientDowncallAccessor.REGISTRATIONS, REGISTRATIONS),
-        FieldInfo.newOptional(AndroidServiceAccessor.ClientDowncallAccessor.START),
-        FieldInfo.newOptional(AndroidServiceAccessor.ClientDowncallAccessor.STOP)) {
-      @Override
-      public boolean postValidate(MessageLite message) {
-        int numSetFields = 0;
-        for (FieldInfo fieldInfo : getAllFields()) {
-          if (AndroidServiceAccessor.CLIENT_DOWNCALL_ACCESSOR.hasField(
-              message, fieldInfo.getFieldDescriptor())) {
-           ++numSetFields;
-          }
-        }
-        return numSetFields == 2; // Version plus exactly one operation. Serial not currently used.
-      }
-    };
-  }
-
-  /** Validation for client internal downcalls. */
-  static class InternalDowncallInfos {
-    private static MessageInfo NETWORK_STATUS = new MessageInfo(
-        InternalDowncallAccessor.NETWORK_STATUS_ACCESSOR,
-        FieldInfo.newRequired(InternalDowncallAccessor.NetworkStatusAccessor.IS_ONLINE));
-
-    private static MessageInfo SERVER_MESSAGE = new MessageInfo(
-        InternalDowncallAccessor.SERVER_MESSAGE_ACCESSOR,
-        FieldInfo.newRequired(InternalDowncallAccessor.ServerMessageAccessor.DATA));
-
-    // We do not post-validate the config in this message, since the Ticl should be doing it, and
-    // it's not clear that we should be peering into Ticl protocol buffers anyway.
-    private static MessageInfo CREATE_CLIENT_MESSAGE = new MessageInfo(
-        InternalDowncallAccessor.CREATE_CLIENT_ACCESSOR,
-        FieldInfo.newRequired(InternalDowncallAccessor.CreateClientAccessor.CLIENT_CONFIG),
-        FieldInfo.newRequired(InternalDowncallAccessor.CreateClientAccessor.CLIENT_NAME),
-        FieldInfo.newRequired(InternalDowncallAccessor.CreateClientAccessor.CLIENT_TYPE),
-        FieldInfo.newRequired(InternalDowncallAccessor.CreateClientAccessor.SKIP_START_FOR_TEST));
-
-    static final MessageInfo INTERNAL_DOWNCALL_MSG = new MessageInfo(
-        AndroidServiceAccessor.INTERNAL_DOWNCALL_ACCESSOR,
-        FieldInfo.newRequired(InternalDowncallAccessor.VERSION, VERSION),
-        FieldInfo.newOptional(InternalDowncallAccessor.NETWORK_STATUS, NETWORK_STATUS),
-        FieldInfo.newOptional(InternalDowncallAccessor.SERVER_MESSAGE, SERVER_MESSAGE),
-        FieldInfo.newOptional(InternalDowncallAccessor.NETWORK_ADDR_CHANGE),
-        FieldInfo.newOptional(InternalDowncallAccessor.CREATE_CLIENT, CREATE_CLIENT_MESSAGE)) {
-      @Override
-      public boolean postValidate(MessageLite message) {
-        int numSetFields = 0;
-        for (FieldInfo fieldInfo : getAllFields()) {
-          if (AndroidServiceAccessor.INTERNAL_DOWNCALL_ACCESSOR.hasField(
-              message, fieldInfo.getFieldDescriptor())) {
-           ++numSetFields;
-          }
-        }
-        return numSetFields == 2; // Version plus exactly one operation. Serial not currently used.
-      }
-    };
-  }
-
-  /** Validation for listener upcalls. */
-  static class ListenerUpcallInfos {
-    static final MessageInfo ERROR = new MessageInfo(ListenerUpcallAccessor.ERROR_UPCALL_ACCESSOR,
-        FieldInfo.newRequired(ListenerUpcallAccessor.ErrorUpcallAccessor.ERROR_CODE),
-        FieldInfo.newRequired(ListenerUpcallAccessor.ErrorUpcallAccessor.ERROR_MESSAGE),
-        FieldInfo.newRequired(ListenerUpcallAccessor.ErrorUpcallAccessor.IS_TRANSIENT));
-
-    // TODO: validate INVALIDATE_UNKNOWN and INVALIDATION sub-messages.
-    static final MessageInfo INVALIDATE = new MessageInfo(
-        ListenerUpcallAccessor.INVALIDATE_UPCALL_ACCESSOR,
-        FieldInfo.newRequired(ListenerUpcallAccessor.InvalidateUpcallAccessor.ACK_HANDLE),
-        FieldInfo.newOptional(ListenerUpcallAccessor.InvalidateUpcallAccessor.INVALIDATE_ALL),
-        FieldInfo.newOptional(ListenerUpcallAccessor.InvalidateUpcallAccessor.INVALIDATE_UNKNOWN),
-        FieldInfo.newOptional(ListenerUpcallAccessor.InvalidateUpcallAccessor.INVALIDATION)) {
-      @Override
-      public boolean postValidate(MessageLite message) {
-        int numSetFields = 0;
-        for (FieldInfo fieldInfo : getAllFields()) {
-          if (ListenerUpcallAccessor.INVALIDATE_UPCALL_ACCESSOR.hasField(
-              message, fieldInfo.getFieldDescriptor())) {
-           ++numSetFields;
-          }
-        }
-        return numSetFields == 2; // Handle plus exactly one operation. Serial not currently used.
-      }
-    };
-
-    static final MessageInfo REGISTRATION_FAILURE = new MessageInfo(
-        ListenerUpcallAccessor.REGISTRATION_FAILURE_UPCALL_ACCESSOR,
-        FieldInfo.newRequired(ListenerUpcallAccessor.RegistrationFailureUpcallAccessor.MESSAGE),
-        FieldInfo.newRequired(ListenerUpcallAccessor.RegistrationFailureUpcallAccessor.OBJECT_ID),
-        FieldInfo.newRequired(ListenerUpcallAccessor.RegistrationFailureUpcallAccessor.TRANSIENT));
-
-    static final MessageInfo REGISTRATION_STATUS = new MessageInfo(
-        ListenerUpcallAccessor.REGISTRATION_STATUS_UPCALL_ACCESSOR,
-        FieldInfo.newRequired(
-            ListenerUpcallAccessor.RegistrationStatusUpcallAccessor.IS_REGISTERED),
-        FieldInfo.newRequired(ListenerUpcallAccessor.RegistrationStatusUpcallAccessor.OBJECT_ID));
-
-    static final MessageInfo REISSUE_REGISTRATIONS = new MessageInfo(
-        ListenerUpcallAccessor.REISSUE_REGISTRATIONS_UPCALL_ACCESSOR,
-        FieldInfo.newRequired(ListenerUpcallAccessor.ReissueRegistrationsUpcallAccessor.LENGTH),
-        FieldInfo.newRequired(ListenerUpcallAccessor.ReissueRegistrationsUpcallAccessor.PREFIX));
-
-    static final MessageInfo LISTENER_UPCALL_MESSAGE = new MessageInfo(
-        AndroidServiceAccessor.LISTENER_UPCALL_ACCESSOR,
-        FieldInfo.newRequired(ListenerUpcallAccessor.VERSION, VERSION),
-        FieldInfo.newOptional(ListenerUpcallAccessor.SERIAL),
-        FieldInfo.newOptional(ListenerUpcallAccessor.ERROR, ERROR),
-        FieldInfo.newOptional(ListenerUpcallAccessor.INVALIDATE, INVALIDATE),
-        FieldInfo.newOptional(ListenerUpcallAccessor.READY),
-        FieldInfo.newOptional(ListenerUpcallAccessor.REGISTRATION_FAILURE, REGISTRATION_FAILURE),
-        FieldInfo.newOptional(ListenerUpcallAccessor.REGISTRATION_STATUS, REGISTRATION_STATUS),
-        FieldInfo.newOptional(
-            ListenerUpcallAccessor.REISSUE_REGISTRATIONS, REISSUE_REGISTRATIONS)) {
-      @Override
-      public boolean postValidate(MessageLite message) {
-        int numSetFields = 0;
-        for (FieldInfo fieldInfo : getAllFields()) {
-          if (AndroidServiceAccessor.LISTENER_UPCALL_ACCESSOR.hasField(
-              message, fieldInfo.getFieldDescriptor())) {
-           ++numSetFields;
-          }
-        }
-        return numSetFields == 2; // Version plus exactly one operation. Serial not currently used.
-      }
-    };
-  }
-
-  /** Validation for internal protocol buffers. */
-  static class InternalInfos {
-    static final MessageInfo ANDROID_SCHEDULER_EVENT = new MessageInfo(
-        AndroidServiceAccessor.ANDROID_SCHEDULER_EVENT_ACCESSOR,
-        FieldInfo.newRequired(
-            AndroidServiceAccessor.AndroidSchedulerEventAccessor.VERSION, VERSION),
-        FieldInfo.newRequired(AndroidServiceAccessor.AndroidSchedulerEventAccessor.EVENT_NAME),
-        FieldInfo.newRequired(AndroidServiceAccessor.AndroidSchedulerEventAccessor.TICL_ID));
-
-    static final MessageInfo ANDROID_NETWORK_SEND_REQUEST = new MessageInfo(
-        AndroidServiceAccessor.ANDROID_NETWORK_SEND_REQUEST_ACCESSOR,
-        FieldInfo.newRequired(AndroidNetworkSendRequestAccessor.VERSION, VERSION),
-        FieldInfo.newRequired(AndroidNetworkSendRequestAccessor.MESSAGE));
-
-    // We do not post-validate the config in this message, since the Ticl should be doing it, and
-    // it's not clear that we should be peering into Ticl protocol buffers anyway.
-    static final MessageInfo PERSISTED_STATE_METADATA = new MessageInfo(
-        AndroidTiclStateAccessor.METADATA_ACCESSOR,
-        FieldInfo.newRequired(MetadataAccessor.CLIENT_CONFIG),
-        FieldInfo.newRequired(MetadataAccessor.CLIENT_NAME),
-        FieldInfo.newRequired(MetadataAccessor.CLIENT_TYPE),
-        FieldInfo.newRequired(MetadataAccessor.TICL_ID));
-
-    static final MessageInfo ANDROID_TICL_STATE = new MessageInfo(
-        AndroidServiceAccessor.ANDROID_TICL_STATE_ACCESSOR,
-        FieldInfo.newRequired(AndroidTiclStateAccessor.METADATA, PERSISTED_STATE_METADATA),
-        FieldInfo.newRequired(AndroidTiclStateAccessor.TICL_STATE),
-        FieldInfo.newRequired(AndroidTiclStateAccessor.VERSION));
-
-    static final MessageInfo ANDROID_TICL_STATE_WITH_DIGEST = new MessageInfo(
-        AndroidServiceAccessor.ANDROID_TICL_STATE_WITH_DIGEST_ACCESSOR,
-        FieldInfo.newRequired(AndroidTiclStateWithDigestAccessor.DIGEST),
-        FieldInfo.newRequired(AndroidTiclStateWithDigestAccessor.STATE, ANDROID_TICL_STATE));
-  }
-
-  /** Returns whether {@code downcall} has a valid set of fields with valid values. */
-  boolean isDowncallValid(ClientDowncall downcall) {
-    return checkMessage(downcall, DowncallMessageInfos.DOWNCALL_MSG);
-  }
-
-  /** Returns whether {@code downcall} has a valid set of fields with valid values. */
-  boolean isInternalDowncallValid(InternalDowncall downcall) {
-    return checkMessage(downcall, InternalDowncallInfos.INTERNAL_DOWNCALL_MSG);
-  }
-
-  /** Returns whether {@code upcall} has a valid set of fields with valid values. */
-  boolean isListenerUpcallValid(ListenerUpcall upcall) {
-    return checkMessage(upcall, ListenerUpcallInfos.LISTENER_UPCALL_MESSAGE);
-  }
-
-  /** Returns whether {@code event} has a valid set of fields with valid values. */
-  boolean isSchedulerEventValid(AndroidSchedulerEvent event) {
-    return checkMessage(event, InternalInfos.ANDROID_SCHEDULER_EVENT);
-  }
-
-  /** Returns whether {@code request} has a valid set of fields with valid values. */
-  public boolean isNetworkSendRequestValid(AndroidNetworkSendRequest request) {
-    return checkMessage(request, InternalInfos.ANDROID_NETWORK_SEND_REQUEST);
-  }
-
-  /**
-   * Returns whether {@code state} has a valid set of fields with valid values. Does not
-   * verify the digest.
-   */
-  boolean isTiclStateValid(AndroidTiclStateWithDigest state) {
-    return checkMessage(state, InternalInfos.ANDROID_TICL_STATE_WITH_DIGEST);
-  }
-
-  public AndroidIntentProtocolValidator(Logger logger) {
-    super(logger);
-  }
-}
diff --git a/java/com/google/ipc/invalidation/ticl/android2/AndroidInternalScheduler.java b/java/com/google/ipc/invalidation/ticl/android2/AndroidInternalScheduler.java
index 55a8321..287adc2 100644
--- a/java/com/google/ipc/invalidation/ticl/android2/AndroidInternalScheduler.java
+++ b/java/com/google/ipc/invalidation/ticl/android2/AndroidInternalScheduler.java
@@ -21,9 +21,9 @@
 import com.google.ipc.invalidation.external.client.SystemResources.Logger;
 import com.google.ipc.invalidation.external.client.SystemResources.Scheduler;
 import com.google.ipc.invalidation.ticl.RecurringTask;
+import com.google.ipc.invalidation.ticl.proto.AndroidService.AndroidSchedulerEvent;
 import com.google.ipc.invalidation.util.NamedRunnable;
 import com.google.ipc.invalidation.util.TypedUtil;
-import com.google.protos.ipc.invalidation.AndroidService.AndroidSchedulerEvent;
 
 import android.app.AlarmManager;
 import android.app.PendingIntent;
diff --git a/java/com/google/ipc/invalidation/ticl/android2/AndroidInvalidationClientImpl.java b/java/com/google/ipc/invalidation/ticl/android2/AndroidInvalidationClientImpl.java
index e8b3d4b..fbc0018 100644
--- a/java/com/google/ipc/invalidation/ticl/android2/AndroidInvalidationClientImpl.java
+++ b/java/com/google/ipc/invalidation/ticl/android2/AndroidInvalidationClientImpl.java
@@ -25,13 +25,13 @@
 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.ProtoConverter;
+import com.google.ipc.invalidation.ticl.ProtoWrapperConverter;
 import com.google.ipc.invalidation.ticl.android2.ProtocolIntents.ListenerUpcalls;
-import com.google.protobuf.InvalidProtocolBufferException;
-import com.google.protos.ipc.invalidation.AndroidService.AndroidTiclState;
-import com.google.protos.ipc.invalidation.Client.AckHandleP;
-import com.google.protos.ipc.invalidation.ClientProtocol.ApplicationClientIdP;
-import com.google.protos.ipc.invalidation.ClientProtocol.ClientConfigP;
+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.ProtoWrapper.ValidationException;
 
 import android.app.Service;
 import android.content.Context;
@@ -92,8 +92,8 @@
       try {
         AckHandleP ackHandleP = AckHandleP.parseFrom(ackHandle.getHandleData());
         issueIntent(context, ListenerUpcalls.newInvalidateIntent(
-            ProtoConverter.convertToInvalidationProto(invalidation), ackHandleP));
-      } catch (InvalidProtocolBufferException exception) {
+            ProtoWrapperConverter.convertToInvalidationProto(invalidation), ackHandleP));
+      } catch (ValidationException exception) {
         // Log and drop invalid call.
         logBadAckHandle("invalidate", ackHandle);
       }
@@ -105,8 +105,8 @@
       try {
         AckHandleP ackHandleP = AckHandleP.parseFrom(ackHandle.getHandleData());
         issueIntent(context, ListenerUpcalls.newInvalidateUnknownIntent(
-            ProtoConverter.convertToObjectIdProto(objectId), ackHandleP));
-      } catch (InvalidProtocolBufferException exception) {
+            ProtoWrapperConverter.convertToObjectIdProto(objectId), ackHandleP));
+      } catch (ValidationException exception) {
         // Log and drop invalid call.
         logBadAckHandle("invalidateUnknownVersion", ackHandle);
       }
@@ -117,7 +117,7 @@
       try {
         AckHandleP ackHandleP = AckHandleP.parseFrom(ackHandle.getHandleData());
         issueIntent(context, ListenerUpcalls.newInvalidateAllIntent(ackHandleP));
-      } catch (InvalidProtocolBufferException exception) {
+      } catch (ValidationException exception) {
         // Log and drop invalid call.
         logBadAckHandle("invalidateAll", ackHandle);
       }
@@ -127,7 +127,7 @@
     public void informRegistrationStatus(
         InvalidationClient client, ObjectId objectId, RegistrationState regState) {
       Intent intent = ListenerUpcalls.newRegistrationStatusIntent(
-          ProtoConverter.convertToObjectIdProto(objectId),
+          ProtoWrapperConverter.convertToObjectIdProto(objectId),
           regState == RegistrationState.REGISTERED);
       issueIntent(context, intent);
     }
@@ -136,7 +136,7 @@
     public void informRegistrationFailure(InvalidationClient client, ObjectId objectId,
         boolean isTransient, String errorMessage) {
       issueIntent(context, ListenerUpcalls.newRegistrationFailureIntent(
-          ProtoConverter.convertToObjectIdProto(objectId), isTransient, errorMessage));
+          ProtoWrapperConverter.convertToObjectIdProto(objectId), isTransient, errorMessage));
     }
 
     @Override
@@ -203,7 +203,7 @@
     super(resources,
         random,
         marshalledState.getMetadata().getClientType(),
-        marshalledState.getMetadata().getClientName().toByteArray(),
+        marshalledState.getMetadata().getClientName().getByteArray(),
         marshalledState.getMetadata().getClientConfig(),
         getApplicationName(context),
         marshalledState.getTiclState(),
diff --git a/java/com/google/ipc/invalidation/ticl/android2/AndroidInvalidationClientStub.java b/java/com/google/ipc/invalidation/ticl/android2/AndroidInvalidationClientStub.java
index b4c05af..01abf70 100644
--- a/java/com/google/ipc/invalidation/ticl/android2/AndroidInvalidationClientStub.java
+++ b/java/com/google/ipc/invalidation/ticl/android2/AndroidInvalidationClientStub.java
@@ -21,19 +21,15 @@
 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.ObjectId;
-import com.google.ipc.invalidation.ticl.ProtoConverter;
+import com.google.ipc.invalidation.ticl.ProtoWrapperConverter;
 import com.google.ipc.invalidation.ticl.android2.ProtocolIntents.ClientDowncalls;
-import com.google.protobuf.InvalidProtocolBufferException;
-import com.google.protos.ipc.invalidation.Client.AckHandleP;
-import com.google.protos.ipc.invalidation.ClientProtocol.ObjectIdP;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP;
 
 import android.content.Context;
 import android.content.Intent;
 
-import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
-import java.util.List;
+import java.util.Collections;
 
 /**
  * Implementation of {@link InvalidationClient} that uses intents to send commands to an Android
@@ -73,39 +69,35 @@
 
   @Override
   public void register(ObjectId objectId) {
-    List<ObjectIdP> objects = new ArrayList<ObjectIdP>(1);
-    objects.add(ProtoConverter.convertToObjectIdProto(objectId));
+    Collection<ObjectIdP> objects =
+        Collections.singletonList(ProtoWrapperConverter.convertToObjectIdProto(objectId));
     issueIntent(ClientDowncalls.newRegistrationIntent(objects));
   }
 
   @Override
   public void register(Collection<ObjectId> objectIds) {
-    List<ObjectIdP> objectIdPs = ProtoConverter.convertToObjectIdProtoList(objectIds);
+    Collection<ObjectIdP> objectIdPs =
+        ProtoWrapperConverter.convertToObjectIdProtoCollection(objectIds);
     issueIntent(ClientDowncalls.newRegistrationIntent(objectIdPs));
   }
 
   @Override
   public void unregister(ObjectId objectId) {
-    List<ObjectIdP> objects = new ArrayList<ObjectIdP>(1);
-    objects.add(ProtoConverter.convertToObjectIdProto(objectId));
+    Collection<ObjectIdP> objects =
+        Collections.singletonList(ProtoWrapperConverter.convertToObjectIdProto(objectId));
     issueIntent(ClientDowncalls.newUnregistrationIntent(objects));
   }
 
   @Override
   public void unregister(Collection<ObjectId> objectIds) {
-    List<ObjectIdP> objectIdPs = ProtoConverter.convertToObjectIdProtoList(objectIds);
+    Collection<ObjectIdP> objectIdPs =
+        ProtoWrapperConverter.convertToObjectIdProtoCollection(objectIds);
     issueIntent(ClientDowncalls.newUnregistrationIntent(objectIdPs));
   }
 
   @Override
   public void acknowledge(AckHandle ackHandle) {
-    try {
-      AckHandleP ackHandleP = AckHandleP.parseFrom(ackHandle.getHandleData());
-      issueIntent(ClientDowncalls.newAcknowledgeIntent(ackHandleP));
-    } catch (InvalidProtocolBufferException exception) {
-      logger.warning("Dropping acknowledge(); could not parse ack handle data %s",
-          Arrays.toString(ackHandle.getHandleData()));
-    }
+    issueIntent(ClientDowncalls.newAcknowledgeIntent(ackHandle.getHandleData()));
   }
 
   /** Sends {@code intent} to the service implemented by {@link #serviceClass}. */
diff --git a/java/com/google/ipc/invalidation/ticl/android2/AndroidInvalidationListenerIntentMapper.java b/java/com/google/ipc/invalidation/ticl/android2/AndroidInvalidationListenerIntentMapper.java
index 7931845..ed1ec51 100644
--- a/java/com/google/ipc/invalidation/ticl/android2/AndroidInvalidationListenerIntentMapper.java
+++ b/java/com/google/ipc/invalidation/ticl/android2/AndroidInvalidationListenerIntentMapper.java
@@ -21,14 +21,14 @@
 import com.google.ipc.invalidation.external.client.android.service.AndroidLogger;
 import com.google.ipc.invalidation.external.client.types.AckHandle;
 import com.google.ipc.invalidation.external.client.types.ErrorInfo;
-import com.google.ipc.invalidation.ticl.ProtoConverter;
-import com.google.protobuf.InvalidProtocolBufferException;
-import com.google.protos.ipc.invalidation.AndroidService.ListenerUpcall;
-import com.google.protos.ipc.invalidation.AndroidService.ListenerUpcall.ErrorUpcall;
-import com.google.protos.ipc.invalidation.AndroidService.ListenerUpcall.InvalidateUpcall;
-import com.google.protos.ipc.invalidation.AndroidService.ListenerUpcall.RegistrationFailureUpcall;
-import com.google.protos.ipc.invalidation.AndroidService.ListenerUpcall.RegistrationStatusUpcall;
-import com.google.protos.ipc.invalidation.AndroidService.ListenerUpcall.ReissueRegistrationsUpcall;
+import com.google.ipc.invalidation.ticl.ProtoWrapperConverter;
+import com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall;
+import com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.ErrorUpcall;
+import com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.InvalidateUpcall;
+import com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.RegistrationFailureUpcall;
+import com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.RegistrationStatusUpcall;
+import com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.ReissueRegistrationsUpcall;
+import com.google.ipc.invalidation.util.ProtoWrapper.ValidationException;
 
 import android.content.Context;
 import android.content.Intent;
@@ -47,9 +47,6 @@
   /** The logger. */
   private final AndroidLogger logger = AndroidLogger.forPrefix("");
 
-  private final AndroidIntentProtocolValidator validator =
-      new AndroidIntentProtocolValidator(logger);
-
   /** Client passed to the listener (supports downcalls). */
   public final InvalidationClient client;
 
@@ -82,28 +79,28 @@
 
     if (upcall.hasReady()) {
       listener.ready(client);
-    } else if (upcall.hasInvalidate()) {
+    } else if (upcall.getNullableInvalidate() != null) {
       // Handle all invalidation-related upcalls on a common path, since they require creating
       // an AckHandleP.
-      onInvalidateUpcall(upcall, listener);
-    } else if (upcall.hasRegistrationStatus()) {
-      RegistrationStatusUpcall regStatus = upcall.getRegistrationStatus();
+      onInvalidateUpcall(upcall.getNullableInvalidate(), listener);
+    } else if (upcall.getNullableRegistrationStatus() != null) {
+      RegistrationStatusUpcall regStatus = upcall.getNullableRegistrationStatus();
       listener.informRegistrationStatus(client,
-          ProtoConverter.convertFromObjectIdProto(regStatus.getObjectId()),
+          ProtoWrapperConverter.convertFromObjectIdProto(regStatus.getObjectId()),
           regStatus.getIsRegistered() ?
               RegistrationState.REGISTERED : RegistrationState.UNREGISTERED);
-    } else if (upcall.hasRegistrationFailure()) {
-      RegistrationFailureUpcall failure = upcall.getRegistrationFailure();
+    } else if (upcall.getNullableRegistrationFailure() != null) {
+      RegistrationFailureUpcall failure = upcall.getNullableRegistrationFailure();
       listener.informRegistrationFailure(client,
-          ProtoConverter.convertFromObjectIdProto(failure.getObjectId()),
+          ProtoWrapperConverter.convertFromObjectIdProto(failure.getObjectId()),
           failure.getTransient(),
           failure.getMessage());
-    } else if (upcall.hasReissueRegistrations()) {
-      ReissueRegistrationsUpcall reissueRegs = upcall.getReissueRegistrations();
-      listener.reissueRegistrations(client, reissueRegs.getPrefix().toByteArray(),
+    } else if (upcall.getNullableReissueRegistrations() != null) {
+      ReissueRegistrationsUpcall reissueRegs = upcall.getNullableReissueRegistrations();
+      listener.reissueRegistrations(client, reissueRegs.getPrefix().getByteArray(),
           reissueRegs.getLength());
-    } else if (upcall.hasError()) {
-      ErrorUpcall error = upcall.getError();
+    } else if (upcall.getNullableError() != null) {
+      ErrorUpcall error = upcall.getNullableError();
       ErrorInfo errorInfo = ErrorInfo.newInstance(error.getErrorCode(), error.getIsTransient(),
           error.getErrorMessage(), null);
       listener.informError(client, errorInfo);
@@ -116,18 +113,18 @@
    * Handles an invalidation-related listener {@code upcall} by dispatching to the appropriate
    * method on an instance of {@link InvalidationListener}.
    */
-  private void onInvalidateUpcall(ListenerUpcall upcall, InvalidationListener listener) {
-    InvalidateUpcall invalidate = upcall.getInvalidate();
-    AckHandle ackHandle = AckHandle.newInstance(invalidate.getAckHandle().toByteArray());
-    if (invalidate.hasInvalidation()) {
+  private void onInvalidateUpcall(InvalidateUpcall invalidate, InvalidationListener listener) {
+    AckHandle ackHandle = AckHandle.newInstance(invalidate.getAckHandle().getByteArray());
+    if (invalidate.getNullableInvalidation() != null) {
       listener.invalidate(client,
-          ProtoConverter.convertFromInvalidationProto(invalidate.getInvalidation()),
+          ProtoWrapperConverter.convertFromInvalidationProto(invalidate.getNullableInvalidation()),
           ackHandle);
     } else if (invalidate.hasInvalidateAll()) {
       listener.invalidateAll(client, ackHandle);
-    } else if (invalidate.hasInvalidateUnknown()) {
+    } else if (invalidate.getNullableInvalidateUnknown() != null) {
       listener.invalidateUnknownVersion(client,
-          ProtoConverter.convertFromObjectIdProto(invalidate.getInvalidateUnknown()), ackHandle);
+          ProtoWrapperConverter.convertFromObjectIdProto(invalidate.getNullableInvalidateUnknown()),
+          ackHandle);
     } else {
       throw new RuntimeException("Invalid invalidate upcall: " + invalidate);
     }
@@ -147,12 +144,8 @@
     }
     try {
       ListenerUpcall upcall = ListenerUpcall.parseFrom(upcallBytes);
-      if (!validator.isListenerUpcallValid(upcall)) {
-        logger.warning("Ignoring invalid listener upcall: %s", upcall);
-        return null;
-      }
       return upcall;
-    } catch (InvalidProtocolBufferException exception) {
+    } catch (ValidationException exception) {
       logger.severe("Could not parse listener upcall from %s", Arrays.toString(upcallBytes));
       return null;
     }
diff --git a/java/com/google/ipc/invalidation/ticl/android2/AndroidInvalidationListenerStub.java b/java/com/google/ipc/invalidation/ticl/android2/AndroidInvalidationListenerStub.java
index 87efbd5..527157d 100644
--- a/java/com/google/ipc/invalidation/ticl/android2/AndroidInvalidationListenerStub.java
+++ b/java/com/google/ipc/invalidation/ticl/android2/AndroidInvalidationListenerStub.java
@@ -67,7 +67,7 @@
    */
   @Override
   public void onHandleIntent(Intent intent) {
-    logger.fine("onHandleIntent({0})", AndroidStrings.toLazyCompactString(intent));
+    logger.fine("onHandleIntent({0})", intent);
     intentMapper.handleIntent(intent);
   }
 
diff --git a/java/com/google/ipc/invalidation/ticl/android2/AndroidServiceAccessor.java b/java/com/google/ipc/invalidation/ticl/android2/AndroidServiceAccessor.java
deleted file mode 100644
index 3211139..0000000
--- a/java/com/google/ipc/invalidation/ticl/android2/AndroidServiceAccessor.java
+++ /dev/null
@@ -1,1217 +0,0 @@
-/*
- * 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.
- */
-// GENERATED CODE. DO NOT EDIT. (But isn't it pretty?)
-package com.google.ipc.invalidation.ticl.android2;
-
-import com.google.common.base.Preconditions;
-import com.google.ipc.invalidation.common.ProtoValidator.Accessor;
-
-import com.google.ipc.invalidation.common.ProtoValidator.Descriptor;
-
-import com.google.protobuf.MessageLite;
-
-import com.google.protos.ipc.invalidation.AndroidService.AndroidNetworkSendRequest;
-import com.google.protos.ipc.invalidation.AndroidService.AndroidSchedulerEvent;
-import com.google.protos.ipc.invalidation.AndroidService.AndroidTiclState;
-import com.google.protos.ipc.invalidation.AndroidService.AndroidTiclState.Metadata;
-import com.google.protos.ipc.invalidation.AndroidService.AndroidTiclStateWithDigest;
-import com.google.protos.ipc.invalidation.AndroidService.ClientDowncall;
-import com.google.protos.ipc.invalidation.AndroidService.ClientDowncall.RegistrationDowncall;
-import com.google.protos.ipc.invalidation.AndroidService.ClientDowncall.AckDowncall;
-import com.google.protos.ipc.invalidation.AndroidService.ClientDowncall.StopDowncall;
-import com.google.protos.ipc.invalidation.AndroidService.ClientDowncall.StartDowncall;
-import com.google.protos.ipc.invalidation.AndroidService.InternalDowncall;
-import com.google.protos.ipc.invalidation.AndroidService.InternalDowncall.CreateClient;
-import com.google.protos.ipc.invalidation.AndroidService.InternalDowncall.NetworkStatus;
-import com.google.protos.ipc.invalidation.AndroidService.InternalDowncall.ServerMessage;
-import com.google.protos.ipc.invalidation.AndroidService.ListenerUpcall;
-import com.google.protos.ipc.invalidation.AndroidService.ListenerUpcall.ErrorUpcall;
-import com.google.protos.ipc.invalidation.AndroidService.ListenerUpcall.ReissueRegistrationsUpcall;
-import com.google.protos.ipc.invalidation.AndroidService.ListenerUpcall.RegistrationFailureUpcall;
-import com.google.protos.ipc.invalidation.AndroidService.ListenerUpcall.RegistrationStatusUpcall;
-import com.google.protos.ipc.invalidation.AndroidService.ListenerUpcall.InvalidateUpcall;
-import com.google.protos.ipc.invalidation.AndroidService.ListenerUpcall.ReadyUpcall;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Set;
-
-/** Class providing access to fields of protocol buffers in a generic way without using Java reflection. */
-public class AndroidServiceAccessor {
-  /** Class to access fields in {@link AndroidNetworkSendRequest} protos. */
-  public static class AndroidNetworkSendRequestAccessor implements Accessor {
-    private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-      Arrays.<String>asList(
-        "version",
-        "message"
-      ));
-    
-    public static final Descriptor VERSION = new Descriptor("version");
-    public static final Descriptor MESSAGE = new Descriptor("message");
-    
-    /** Returns whether {@code field} is present in {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public boolean hasField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      AndroidNetworkSendRequest message = (AndroidNetworkSendRequest) rawMessage;
-      if (field == VERSION) {
-        return message.hasVersion();
-      }
-      if (field == MESSAGE) {
-        return message.hasMessage();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    /** Returns the {@code field} from {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public Object getField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      AndroidNetworkSendRequest message = (AndroidNetworkSendRequest) rawMessage;
-      if (field == VERSION) {
-        return message.getVersion();
-      }
-      if (field == MESSAGE) {
-        return message.getMessage();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    @Override
-    public Set<String> getAllFieldNames() {
-      return ALL_FIELD_NAMES;
-    }
-  }
-  public static final AndroidNetworkSendRequestAccessor ANDROID_NETWORK_SEND_REQUEST_ACCESSOR = new AndroidNetworkSendRequestAccessor();
-  
-  /** Class to access fields in {@link AndroidSchedulerEvent} protos. */
-  public static class AndroidSchedulerEventAccessor implements Accessor {
-    private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-      Arrays.<String>asList(
-        "version",
-        "event_name",
-        "ticl_id"
-      ));
-    
-    public static final Descriptor VERSION = new Descriptor("version");
-    public static final Descriptor EVENT_NAME = new Descriptor("event_name");
-    public static final Descriptor TICL_ID = new Descriptor("ticl_id");
-    
-    /** Returns whether {@code field} is present in {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public boolean hasField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      AndroidSchedulerEvent message = (AndroidSchedulerEvent) rawMessage;
-      if (field == VERSION) {
-        return message.hasVersion();
-      }
-      if (field == EVENT_NAME) {
-        return message.hasEventName();
-      }
-      if (field == TICL_ID) {
-        return message.hasTiclId();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    /** Returns the {@code field} from {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public Object getField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      AndroidSchedulerEvent message = (AndroidSchedulerEvent) rawMessage;
-      if (field == VERSION) {
-        return message.getVersion();
-      }
-      if (field == EVENT_NAME) {
-        return message.getEventName();
-      }
-      if (field == TICL_ID) {
-        return message.getTiclId();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    @Override
-    public Set<String> getAllFieldNames() {
-      return ALL_FIELD_NAMES;
-    }
-  }
-  public static final AndroidSchedulerEventAccessor ANDROID_SCHEDULER_EVENT_ACCESSOR = new AndroidSchedulerEventAccessor();
-  
-  /** Class to access fields in {@link AndroidTiclState} protos. */
-  public static class AndroidTiclStateAccessor implements Accessor {
-    /** Class to access fields in {@link Metadata} protos. */
-    public static class MetadataAccessor implements Accessor {
-      private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-        Arrays.<String>asList(
-          "client_type",
-          "client_name",
-          "ticl_id",
-          "client_config"
-        ));
-      
-      public static final Descriptor CLIENT_TYPE = new Descriptor("client_type");
-      public static final Descriptor CLIENT_NAME = new Descriptor("client_name");
-      public static final Descriptor TICL_ID = new Descriptor("ticl_id");
-      public static final Descriptor CLIENT_CONFIG = new Descriptor("client_config");
-      
-      /** Returns whether {@code field} is present in {@code message}. */
-      @Override
-      @SuppressWarnings("unchecked")
-      public boolean hasField(MessageLite rawMessage, Descriptor field) {
-        Preconditions.checkNotNull(rawMessage);
-        Preconditions.checkNotNull(field);
-        Metadata message = (Metadata) rawMessage;
-        if (field == CLIENT_TYPE) {
-          return message.hasClientType();
-        }
-        if (field == CLIENT_NAME) {
-          return message.hasClientName();
-        }
-        if (field == TICL_ID) {
-          return message.hasTiclId();
-        }
-        if (field == CLIENT_CONFIG) {
-          return message.hasClientConfig();
-        }
-        throw new IllegalArgumentException("Bad descriptor: " + field);
-      }
-      
-      /** Returns the {@code field} from {@code message}. */
-      @Override
-      @SuppressWarnings("unchecked")
-      public Object getField(MessageLite rawMessage, Descriptor field) {
-        Preconditions.checkNotNull(rawMessage);
-        Preconditions.checkNotNull(field);
-        Metadata message = (Metadata) rawMessage;
-        if (field == CLIENT_TYPE) {
-          return message.getClientType();
-        }
-        if (field == CLIENT_NAME) {
-          return message.getClientName();
-        }
-        if (field == TICL_ID) {
-          return message.getTiclId();
-        }
-        if (field == CLIENT_CONFIG) {
-          return message.getClientConfig();
-        }
-        throw new IllegalArgumentException("Bad descriptor: " + field);
-      }
-      
-      @Override
-      public Set<String> getAllFieldNames() {
-        return ALL_FIELD_NAMES;
-      }
-    }
-    public static final MetadataAccessor METADATA_ACCESSOR = new MetadataAccessor();
-    
-    private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-      Arrays.<String>asList(
-        "version",
-        "ticl_state",
-        "metadata"
-      ));
-    
-    public static final Descriptor VERSION = new Descriptor("version");
-    public static final Descriptor TICL_STATE = new Descriptor("ticl_state");
-    public static final Descriptor METADATA = new Descriptor("metadata");
-    
-    /** Returns whether {@code field} is present in {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public boolean hasField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      AndroidTiclState message = (AndroidTiclState) rawMessage;
-      if (field == VERSION) {
-        return message.hasVersion();
-      }
-      if (field == TICL_STATE) {
-        return message.hasTiclState();
-      }
-      if (field == METADATA) {
-        return message.hasMetadata();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    /** Returns the {@code field} from {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public Object getField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      AndroidTiclState message = (AndroidTiclState) rawMessage;
-      if (field == VERSION) {
-        return message.getVersion();
-      }
-      if (field == TICL_STATE) {
-        return message.getTiclState();
-      }
-      if (field == METADATA) {
-        return message.getMetadata();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    @Override
-    public Set<String> getAllFieldNames() {
-      return ALL_FIELD_NAMES;
-    }
-  }
-  public static final AndroidTiclStateAccessor ANDROID_TICL_STATE_ACCESSOR = new AndroidTiclStateAccessor();
-  
-  /** Class to access fields in {@link AndroidTiclStateWithDigest} protos. */
-  public static class AndroidTiclStateWithDigestAccessor implements Accessor {
-    private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-      Arrays.<String>asList(
-        "state",
-        "digest"
-      ));
-    
-    public static final Descriptor STATE = new Descriptor("state");
-    public static final Descriptor DIGEST = new Descriptor("digest");
-    
-    /** Returns whether {@code field} is present in {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public boolean hasField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      AndroidTiclStateWithDigest message = (AndroidTiclStateWithDigest) rawMessage;
-      if (field == STATE) {
-        return message.hasState();
-      }
-      if (field == DIGEST) {
-        return message.hasDigest();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    /** Returns the {@code field} from {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public Object getField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      AndroidTiclStateWithDigest message = (AndroidTiclStateWithDigest) rawMessage;
-      if (field == STATE) {
-        return message.getState();
-      }
-      if (field == DIGEST) {
-        return message.getDigest();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    @Override
-    public Set<String> getAllFieldNames() {
-      return ALL_FIELD_NAMES;
-    }
-  }
-  public static final AndroidTiclStateWithDigestAccessor ANDROID_TICL_STATE_WITH_DIGEST_ACCESSOR = new AndroidTiclStateWithDigestAccessor();
-  
-  /** Class to access fields in {@link ClientDowncall} protos. */
-  public static class ClientDowncallAccessor implements Accessor {
-    /** Class to access fields in {@link RegistrationDowncall} protos. */
-    public static class RegistrationDowncallAccessor implements Accessor {
-      private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-        Arrays.<String>asList(
-          "registrations",
-          "unregistrations"
-        ));
-      
-      public static final Descriptor REGISTRATIONS = new Descriptor("registrations");
-      public static final Descriptor UNREGISTRATIONS = new Descriptor("unregistrations");
-      
-      /** Returns whether {@code field} is present in {@code message}. */
-      @Override
-      @SuppressWarnings("unchecked")
-      public boolean hasField(MessageLite rawMessage, Descriptor field) {
-        Preconditions.checkNotNull(rawMessage);
-        Preconditions.checkNotNull(field);
-        RegistrationDowncall message = (RegistrationDowncall) rawMessage;
-        if (field == REGISTRATIONS) {
-          return message.getRegistrationsCount() > 0;
-        }
-        if (field == UNREGISTRATIONS) {
-          return message.getUnregistrationsCount() > 0;
-        }
-        throw new IllegalArgumentException("Bad descriptor: " + field);
-      }
-      
-      /** Returns the {@code field} from {@code message}. */
-      @Override
-      @SuppressWarnings("unchecked")
-      public Object getField(MessageLite rawMessage, Descriptor field) {
-        Preconditions.checkNotNull(rawMessage);
-        Preconditions.checkNotNull(field);
-        RegistrationDowncall message = (RegistrationDowncall) rawMessage;
-        if (field == REGISTRATIONS) {
-          return message.getRegistrationsList();
-        }
-        if (field == UNREGISTRATIONS) {
-          return message.getUnregistrationsList();
-        }
-        throw new IllegalArgumentException("Bad descriptor: " + field);
-      }
-      
-      @Override
-      public Set<String> getAllFieldNames() {
-        return ALL_FIELD_NAMES;
-      }
-    }
-    public static final RegistrationDowncallAccessor REGISTRATION_DOWNCALL_ACCESSOR = new RegistrationDowncallAccessor();
-    
-    /** Class to access fields in {@link AckDowncall} protos. */
-    public static class AckDowncallAccessor implements Accessor {
-      private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-        Arrays.<String>asList(
-          "ack_handle"
-        ));
-      
-      public static final Descriptor ACK_HANDLE = new Descriptor("ack_handle");
-      
-      /** Returns whether {@code field} is present in {@code message}. */
-      @Override
-      @SuppressWarnings("unchecked")
-      public boolean hasField(MessageLite rawMessage, Descriptor field) {
-        Preconditions.checkNotNull(rawMessage);
-        Preconditions.checkNotNull(field);
-        AckDowncall message = (AckDowncall) rawMessage;
-        if (field == ACK_HANDLE) {
-          return message.hasAckHandle();
-        }
-        throw new IllegalArgumentException("Bad descriptor: " + field);
-      }
-      
-      /** Returns the {@code field} from {@code message}. */
-      @Override
-      @SuppressWarnings("unchecked")
-      public Object getField(MessageLite rawMessage, Descriptor field) {
-        Preconditions.checkNotNull(rawMessage);
-        Preconditions.checkNotNull(field);
-        AckDowncall message = (AckDowncall) rawMessage;
-        if (field == ACK_HANDLE) {
-          return message.getAckHandle();
-        }
-        throw new IllegalArgumentException("Bad descriptor: " + field);
-      }
-      
-      @Override
-      public Set<String> getAllFieldNames() {
-        return ALL_FIELD_NAMES;
-      }
-    }
-    public static final AckDowncallAccessor ACK_DOWNCALL_ACCESSOR = new AckDowncallAccessor();
-    
-    /** Class to access fields in {@link StopDowncall} protos. */
-    public static class StopDowncallAccessor implements Accessor {
-      private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-        Arrays.<String>asList(
-        ));
-      
-      
-      /** Returns whether {@code field} is present in {@code message}. */
-      @Override
-      @SuppressWarnings("unchecked")
-      public boolean hasField(MessageLite rawMessage, Descriptor field) {
-        Preconditions.checkNotNull(rawMessage);
-        Preconditions.checkNotNull(field);
-        StopDowncall message = (StopDowncall) rawMessage;
-        throw new IllegalArgumentException("Bad descriptor: " + field);
-      }
-      
-      /** Returns the {@code field} from {@code message}. */
-      @Override
-      @SuppressWarnings("unchecked")
-      public Object getField(MessageLite rawMessage, Descriptor field) {
-        Preconditions.checkNotNull(rawMessage);
-        Preconditions.checkNotNull(field);
-        StopDowncall message = (StopDowncall) rawMessage;
-        throw new IllegalArgumentException("Bad descriptor: " + field);
-      }
-      
-      @Override
-      public Set<String> getAllFieldNames() {
-        return ALL_FIELD_NAMES;
-      }
-    }
-    public static final StopDowncallAccessor STOP_DOWNCALL_ACCESSOR = new StopDowncallAccessor();
-    
-    /** Class to access fields in {@link StartDowncall} protos. */
-    public static class StartDowncallAccessor implements Accessor {
-      private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-        Arrays.<String>asList(
-        ));
-      
-      
-      /** Returns whether {@code field} is present in {@code message}. */
-      @Override
-      @SuppressWarnings("unchecked")
-      public boolean hasField(MessageLite rawMessage, Descriptor field) {
-        Preconditions.checkNotNull(rawMessage);
-        Preconditions.checkNotNull(field);
-        StartDowncall message = (StartDowncall) rawMessage;
-        throw new IllegalArgumentException("Bad descriptor: " + field);
-      }
-      
-      /** Returns the {@code field} from {@code message}. */
-      @Override
-      @SuppressWarnings("unchecked")
-      public Object getField(MessageLite rawMessage, Descriptor field) {
-        Preconditions.checkNotNull(rawMessage);
-        Preconditions.checkNotNull(field);
-        StartDowncall message = (StartDowncall) rawMessage;
-        throw new IllegalArgumentException("Bad descriptor: " + field);
-      }
-      
-      @Override
-      public Set<String> getAllFieldNames() {
-        return ALL_FIELD_NAMES;
-      }
-    }
-    public static final StartDowncallAccessor START_DOWNCALL_ACCESSOR = new StartDowncallAccessor();
-    
-    private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-      Arrays.<String>asList(
-        "serial",
-        "version",
-        "start",
-        "stop",
-        "ack",
-        "registrations"
-      ));
-    
-    public static final Descriptor SERIAL = new Descriptor("serial");
-    public static final Descriptor VERSION = new Descriptor("version");
-    public static final Descriptor START = new Descriptor("start");
-    public static final Descriptor STOP = new Descriptor("stop");
-    public static final Descriptor ACK = new Descriptor("ack");
-    public static final Descriptor REGISTRATIONS = new Descriptor("registrations");
-    
-    /** Returns whether {@code field} is present in {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public boolean hasField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      ClientDowncall message = (ClientDowncall) rawMessage;
-      if (field == SERIAL) {
-        return message.hasSerial();
-      }
-      if (field == VERSION) {
-        return message.hasVersion();
-      }
-      if (field == START) {
-        return message.hasStart();
-      }
-      if (field == STOP) {
-        return message.hasStop();
-      }
-      if (field == ACK) {
-        return message.hasAck();
-      }
-      if (field == REGISTRATIONS) {
-        return message.hasRegistrations();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    /** Returns the {@code field} from {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public Object getField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      ClientDowncall message = (ClientDowncall) rawMessage;
-      if (field == SERIAL) {
-        return message.getSerial();
-      }
-      if (field == VERSION) {
-        return message.getVersion();
-      }
-      if (field == START) {
-        return message.getStart();
-      }
-      if (field == STOP) {
-        return message.getStop();
-      }
-      if (field == ACK) {
-        return message.getAck();
-      }
-      if (field == REGISTRATIONS) {
-        return message.getRegistrations();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    @Override
-    public Set<String> getAllFieldNames() {
-      return ALL_FIELD_NAMES;
-    }
-  }
-  public static final ClientDowncallAccessor CLIENT_DOWNCALL_ACCESSOR = new ClientDowncallAccessor();
-  
-  /** Class to access fields in {@link InternalDowncall} protos. */
-  public static class InternalDowncallAccessor implements Accessor {
-    /** Class to access fields in {@link CreateClient} protos. */
-    public static class CreateClientAccessor implements Accessor {
-      private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-        Arrays.<String>asList(
-          "client_type",
-          "client_name",
-          "client_config",
-          "skip_start_for_test"
-        ));
-      
-      public static final Descriptor CLIENT_TYPE = new Descriptor("client_type");
-      public static final Descriptor CLIENT_NAME = new Descriptor("client_name");
-      public static final Descriptor CLIENT_CONFIG = new Descriptor("client_config");
-      public static final Descriptor SKIP_START_FOR_TEST = new Descriptor("skip_start_for_test");
-      
-      /** Returns whether {@code field} is present in {@code message}. */
-      @Override
-      @SuppressWarnings("unchecked")
-      public boolean hasField(MessageLite rawMessage, Descriptor field) {
-        Preconditions.checkNotNull(rawMessage);
-        Preconditions.checkNotNull(field);
-        CreateClient message = (CreateClient) rawMessage;
-        if (field == CLIENT_TYPE) {
-          return message.hasClientType();
-        }
-        if (field == CLIENT_NAME) {
-          return message.hasClientName();
-        }
-        if (field == CLIENT_CONFIG) {
-          return message.hasClientConfig();
-        }
-        if (field == SKIP_START_FOR_TEST) {
-          return message.hasSkipStartForTest();
-        }
-        throw new IllegalArgumentException("Bad descriptor: " + field);
-      }
-      
-      /** Returns the {@code field} from {@code message}. */
-      @Override
-      @SuppressWarnings("unchecked")
-      public Object getField(MessageLite rawMessage, Descriptor field) {
-        Preconditions.checkNotNull(rawMessage);
-        Preconditions.checkNotNull(field);
-        CreateClient message = (CreateClient) rawMessage;
-        if (field == CLIENT_TYPE) {
-          return message.getClientType();
-        }
-        if (field == CLIENT_NAME) {
-          return message.getClientName();
-        }
-        if (field == CLIENT_CONFIG) {
-          return message.getClientConfig();
-        }
-        if (field == SKIP_START_FOR_TEST) {
-          return message.getSkipStartForTest();
-        }
-        throw new IllegalArgumentException("Bad descriptor: " + field);
-      }
-      
-      @Override
-      public Set<String> getAllFieldNames() {
-        return ALL_FIELD_NAMES;
-      }
-    }
-    public static final CreateClientAccessor CREATE_CLIENT_ACCESSOR = new CreateClientAccessor();
-    
-    /** Class to access fields in {@link NetworkStatus} protos. */
-    public static class NetworkStatusAccessor implements Accessor {
-      private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-        Arrays.<String>asList(
-          "is_online"
-        ));
-      
-      public static final Descriptor IS_ONLINE = new Descriptor("is_online");
-      
-      /** Returns whether {@code field} is present in {@code message}. */
-      @Override
-      @SuppressWarnings("unchecked")
-      public boolean hasField(MessageLite rawMessage, Descriptor field) {
-        Preconditions.checkNotNull(rawMessage);
-        Preconditions.checkNotNull(field);
-        NetworkStatus message = (NetworkStatus) rawMessage;
-        if (field == IS_ONLINE) {
-          return message.hasIsOnline();
-        }
-        throw new IllegalArgumentException("Bad descriptor: " + field);
-      }
-      
-      /** Returns the {@code field} from {@code message}. */
-      @Override
-      @SuppressWarnings("unchecked")
-      public Object getField(MessageLite rawMessage, Descriptor field) {
-        Preconditions.checkNotNull(rawMessage);
-        Preconditions.checkNotNull(field);
-        NetworkStatus message = (NetworkStatus) rawMessage;
-        if (field == IS_ONLINE) {
-          return message.getIsOnline();
-        }
-        throw new IllegalArgumentException("Bad descriptor: " + field);
-      }
-      
-      @Override
-      public Set<String> getAllFieldNames() {
-        return ALL_FIELD_NAMES;
-      }
-    }
-    public static final NetworkStatusAccessor NETWORK_STATUS_ACCESSOR = new NetworkStatusAccessor();
-    
-    /** Class to access fields in {@link ServerMessage} protos. */
-    public static class ServerMessageAccessor implements Accessor {
-      private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-        Arrays.<String>asList(
-          "data"
-        ));
-      
-      public static final Descriptor DATA = new Descriptor("data");
-      
-      /** Returns whether {@code field} is present in {@code message}. */
-      @Override
-      @SuppressWarnings("unchecked")
-      public boolean hasField(MessageLite rawMessage, Descriptor field) {
-        Preconditions.checkNotNull(rawMessage);
-        Preconditions.checkNotNull(field);
-        ServerMessage message = (ServerMessage) rawMessage;
-        if (field == DATA) {
-          return message.hasData();
-        }
-        throw new IllegalArgumentException("Bad descriptor: " + field);
-      }
-      
-      /** Returns the {@code field} from {@code message}. */
-      @Override
-      @SuppressWarnings("unchecked")
-      public Object getField(MessageLite rawMessage, Descriptor field) {
-        Preconditions.checkNotNull(rawMessage);
-        Preconditions.checkNotNull(field);
-        ServerMessage message = (ServerMessage) rawMessage;
-        if (field == DATA) {
-          return message.getData();
-        }
-        throw new IllegalArgumentException("Bad descriptor: " + field);
-      }
-      
-      @Override
-      public Set<String> getAllFieldNames() {
-        return ALL_FIELD_NAMES;
-      }
-    }
-    public static final ServerMessageAccessor SERVER_MESSAGE_ACCESSOR = new ServerMessageAccessor();
-    
-    private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-      Arrays.<String>asList(
-        "version",
-        "server_message",
-        "network_status",
-        "network_addr_change",
-        "create_client"
-      ));
-    
-    public static final Descriptor VERSION = new Descriptor("version");
-    public static final Descriptor SERVER_MESSAGE = new Descriptor("server_message");
-    public static final Descriptor NETWORK_STATUS = new Descriptor("network_status");
-    public static final Descriptor NETWORK_ADDR_CHANGE = new Descriptor("network_addr_change");
-    public static final Descriptor CREATE_CLIENT = new Descriptor("create_client");
-    
-    /** Returns whether {@code field} is present in {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public boolean hasField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      InternalDowncall message = (InternalDowncall) rawMessage;
-      if (field == VERSION) {
-        return message.hasVersion();
-      }
-      if (field == SERVER_MESSAGE) {
-        return message.hasServerMessage();
-      }
-      if (field == NETWORK_STATUS) {
-        return message.hasNetworkStatus();
-      }
-      if (field == NETWORK_ADDR_CHANGE) {
-        return message.hasNetworkAddrChange();
-      }
-      if (field == CREATE_CLIENT) {
-        return message.hasCreateClient();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    /** Returns the {@code field} from {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public Object getField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      InternalDowncall message = (InternalDowncall) rawMessage;
-      if (field == VERSION) {
-        return message.getVersion();
-      }
-      if (field == SERVER_MESSAGE) {
-        return message.getServerMessage();
-      }
-      if (field == NETWORK_STATUS) {
-        return message.getNetworkStatus();
-      }
-      if (field == NETWORK_ADDR_CHANGE) {
-        return message.getNetworkAddrChange();
-      }
-      if (field == CREATE_CLIENT) {
-        return message.getCreateClient();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    @Override
-    public Set<String> getAllFieldNames() {
-      return ALL_FIELD_NAMES;
-    }
-  }
-  public static final InternalDowncallAccessor INTERNAL_DOWNCALL_ACCESSOR = new InternalDowncallAccessor();
-  
-  /** Class to access fields in {@link ListenerUpcall} protos. */
-  public static class ListenerUpcallAccessor implements Accessor {
-    /** Class to access fields in {@link ErrorUpcall} protos. */
-    public static class ErrorUpcallAccessor implements Accessor {
-      private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-        Arrays.<String>asList(
-          "error_code",
-          "error_message",
-          "is_transient"
-        ));
-      
-      public static final Descriptor ERROR_CODE = new Descriptor("error_code");
-      public static final Descriptor ERROR_MESSAGE = new Descriptor("error_message");
-      public static final Descriptor IS_TRANSIENT = new Descriptor("is_transient");
-      
-      /** Returns whether {@code field} is present in {@code message}. */
-      @Override
-      @SuppressWarnings("unchecked")
-      public boolean hasField(MessageLite rawMessage, Descriptor field) {
-        Preconditions.checkNotNull(rawMessage);
-        Preconditions.checkNotNull(field);
-        ErrorUpcall message = (ErrorUpcall) rawMessage;
-        if (field == ERROR_CODE) {
-          return message.hasErrorCode();
-        }
-        if (field == ERROR_MESSAGE) {
-          return message.hasErrorMessage();
-        }
-        if (field == IS_TRANSIENT) {
-          return message.hasIsTransient();
-        }
-        throw new IllegalArgumentException("Bad descriptor: " + field);
-      }
-      
-      /** Returns the {@code field} from {@code message}. */
-      @Override
-      @SuppressWarnings("unchecked")
-      public Object getField(MessageLite rawMessage, Descriptor field) {
-        Preconditions.checkNotNull(rawMessage);
-        Preconditions.checkNotNull(field);
-        ErrorUpcall message = (ErrorUpcall) rawMessage;
-        if (field == ERROR_CODE) {
-          return message.getErrorCode();
-        }
-        if (field == ERROR_MESSAGE) {
-          return message.getErrorMessage();
-        }
-        if (field == IS_TRANSIENT) {
-          return message.getIsTransient();
-        }
-        throw new IllegalArgumentException("Bad descriptor: " + field);
-      }
-      
-      @Override
-      public Set<String> getAllFieldNames() {
-        return ALL_FIELD_NAMES;
-      }
-    }
-    public static final ErrorUpcallAccessor ERROR_UPCALL_ACCESSOR = new ErrorUpcallAccessor();
-    
-    /** Class to access fields in {@link ReissueRegistrationsUpcall} protos. */
-    public static class ReissueRegistrationsUpcallAccessor implements Accessor {
-      private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-        Arrays.<String>asList(
-          "prefix",
-          "length"
-        ));
-      
-      public static final Descriptor PREFIX = new Descriptor("prefix");
-      public static final Descriptor LENGTH = new Descriptor("length");
-      
-      /** Returns whether {@code field} is present in {@code message}. */
-      @Override
-      @SuppressWarnings("unchecked")
-      public boolean hasField(MessageLite rawMessage, Descriptor field) {
-        Preconditions.checkNotNull(rawMessage);
-        Preconditions.checkNotNull(field);
-        ReissueRegistrationsUpcall message = (ReissueRegistrationsUpcall) rawMessage;
-        if (field == PREFIX) {
-          return message.hasPrefix();
-        }
-        if (field == LENGTH) {
-          return message.hasLength();
-        }
-        throw new IllegalArgumentException("Bad descriptor: " + field);
-      }
-      
-      /** Returns the {@code field} from {@code message}. */
-      @Override
-      @SuppressWarnings("unchecked")
-      public Object getField(MessageLite rawMessage, Descriptor field) {
-        Preconditions.checkNotNull(rawMessage);
-        Preconditions.checkNotNull(field);
-        ReissueRegistrationsUpcall message = (ReissueRegistrationsUpcall) rawMessage;
-        if (field == PREFIX) {
-          return message.getPrefix();
-        }
-        if (field == LENGTH) {
-          return message.getLength();
-        }
-        throw new IllegalArgumentException("Bad descriptor: " + field);
-      }
-      
-      @Override
-      public Set<String> getAllFieldNames() {
-        return ALL_FIELD_NAMES;
-      }
-    }
-    public static final ReissueRegistrationsUpcallAccessor REISSUE_REGISTRATIONS_UPCALL_ACCESSOR = new ReissueRegistrationsUpcallAccessor();
-    
-    /** Class to access fields in {@link RegistrationFailureUpcall} protos. */
-    public static class RegistrationFailureUpcallAccessor implements Accessor {
-      private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-        Arrays.<String>asList(
-          "object_id",
-          "transient",
-          "message"
-        ));
-      
-      public static final Descriptor OBJECT_ID = new Descriptor("object_id");
-      public static final Descriptor TRANSIENT = new Descriptor("transient");
-      public static final Descriptor MESSAGE = new Descriptor("message");
-      
-      /** Returns whether {@code field} is present in {@code message}. */
-      @Override
-      @SuppressWarnings("unchecked")
-      public boolean hasField(MessageLite rawMessage, Descriptor field) {
-        Preconditions.checkNotNull(rawMessage);
-        Preconditions.checkNotNull(field);
-        RegistrationFailureUpcall message = (RegistrationFailureUpcall) rawMessage;
-        if (field == OBJECT_ID) {
-          return message.hasObjectId();
-        }
-        if (field == TRANSIENT) {
-          return message.hasTransient();
-        }
-        if (field == MESSAGE) {
-          return message.hasMessage();
-        }
-        throw new IllegalArgumentException("Bad descriptor: " + field);
-      }
-      
-      /** Returns the {@code field} from {@code message}. */
-      @Override
-      @SuppressWarnings("unchecked")
-      public Object getField(MessageLite rawMessage, Descriptor field) {
-        Preconditions.checkNotNull(rawMessage);
-        Preconditions.checkNotNull(field);
-        RegistrationFailureUpcall message = (RegistrationFailureUpcall) rawMessage;
-        if (field == OBJECT_ID) {
-          return message.getObjectId();
-        }
-        if (field == TRANSIENT) {
-          return message.getTransient();
-        }
-        if (field == MESSAGE) {
-          return message.getMessage();
-        }
-        throw new IllegalArgumentException("Bad descriptor: " + field);
-      }
-      
-      @Override
-      public Set<String> getAllFieldNames() {
-        return ALL_FIELD_NAMES;
-      }
-    }
-    public static final RegistrationFailureUpcallAccessor REGISTRATION_FAILURE_UPCALL_ACCESSOR = new RegistrationFailureUpcallAccessor();
-    
-    /** Class to access fields in {@link RegistrationStatusUpcall} protos. */
-    public static class RegistrationStatusUpcallAccessor implements Accessor {
-      private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-        Arrays.<String>asList(
-          "object_id",
-          "is_registered"
-        ));
-      
-      public static final Descriptor OBJECT_ID = new Descriptor("object_id");
-      public static final Descriptor IS_REGISTERED = new Descriptor("is_registered");
-      
-      /** Returns whether {@code field} is present in {@code message}. */
-      @Override
-      @SuppressWarnings("unchecked")
-      public boolean hasField(MessageLite rawMessage, Descriptor field) {
-        Preconditions.checkNotNull(rawMessage);
-        Preconditions.checkNotNull(field);
-        RegistrationStatusUpcall message = (RegistrationStatusUpcall) rawMessage;
-        if (field == OBJECT_ID) {
-          return message.hasObjectId();
-        }
-        if (field == IS_REGISTERED) {
-          return message.hasIsRegistered();
-        }
-        throw new IllegalArgumentException("Bad descriptor: " + field);
-      }
-      
-      /** Returns the {@code field} from {@code message}. */
-      @Override
-      @SuppressWarnings("unchecked")
-      public Object getField(MessageLite rawMessage, Descriptor field) {
-        Preconditions.checkNotNull(rawMessage);
-        Preconditions.checkNotNull(field);
-        RegistrationStatusUpcall message = (RegistrationStatusUpcall) rawMessage;
-        if (field == OBJECT_ID) {
-          return message.getObjectId();
-        }
-        if (field == IS_REGISTERED) {
-          return message.getIsRegistered();
-        }
-        throw new IllegalArgumentException("Bad descriptor: " + field);
-      }
-      
-      @Override
-      public Set<String> getAllFieldNames() {
-        return ALL_FIELD_NAMES;
-      }
-    }
-    public static final RegistrationStatusUpcallAccessor REGISTRATION_STATUS_UPCALL_ACCESSOR = new RegistrationStatusUpcallAccessor();
-    
-    /** Class to access fields in {@link InvalidateUpcall} protos. */
-    public static class InvalidateUpcallAccessor implements Accessor {
-      private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-        Arrays.<String>asList(
-          "ack_handle",
-          "invalidation",
-          "invalidate_unknown",
-          "invalidate_all"
-        ));
-      
-      public static final Descriptor ACK_HANDLE = new Descriptor("ack_handle");
-      public static final Descriptor INVALIDATION = new Descriptor("invalidation");
-      public static final Descriptor INVALIDATE_UNKNOWN = new Descriptor("invalidate_unknown");
-      public static final Descriptor INVALIDATE_ALL = new Descriptor("invalidate_all");
-      
-      /** Returns whether {@code field} is present in {@code message}. */
-      @Override
-      @SuppressWarnings("unchecked")
-      public boolean hasField(MessageLite rawMessage, Descriptor field) {
-        Preconditions.checkNotNull(rawMessage);
-        Preconditions.checkNotNull(field);
-        InvalidateUpcall message = (InvalidateUpcall) rawMessage;
-        if (field == ACK_HANDLE) {
-          return message.hasAckHandle();
-        }
-        if (field == INVALIDATION) {
-          return message.hasInvalidation();
-        }
-        if (field == INVALIDATE_UNKNOWN) {
-          return message.hasInvalidateUnknown();
-        }
-        if (field == INVALIDATE_ALL) {
-          return message.hasInvalidateAll();
-        }
-        throw new IllegalArgumentException("Bad descriptor: " + field);
-      }
-      
-      /** Returns the {@code field} from {@code message}. */
-      @Override
-      @SuppressWarnings("unchecked")
-      public Object getField(MessageLite rawMessage, Descriptor field) {
-        Preconditions.checkNotNull(rawMessage);
-        Preconditions.checkNotNull(field);
-        InvalidateUpcall message = (InvalidateUpcall) rawMessage;
-        if (field == ACK_HANDLE) {
-          return message.getAckHandle();
-        }
-        if (field == INVALIDATION) {
-          return message.getInvalidation();
-        }
-        if (field == INVALIDATE_UNKNOWN) {
-          return message.getInvalidateUnknown();
-        }
-        if (field == INVALIDATE_ALL) {
-          return message.getInvalidateAll();
-        }
-        throw new IllegalArgumentException("Bad descriptor: " + field);
-      }
-      
-      @Override
-      public Set<String> getAllFieldNames() {
-        return ALL_FIELD_NAMES;
-      }
-    }
-    public static final InvalidateUpcallAccessor INVALIDATE_UPCALL_ACCESSOR = new InvalidateUpcallAccessor();
-    
-    /** Class to access fields in {@link ReadyUpcall} protos. */
-    public static class ReadyUpcallAccessor implements Accessor {
-      private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-        Arrays.<String>asList(
-        ));
-      
-      
-      /** Returns whether {@code field} is present in {@code message}. */
-      @Override
-      @SuppressWarnings("unchecked")
-      public boolean hasField(MessageLite rawMessage, Descriptor field) {
-        Preconditions.checkNotNull(rawMessage);
-        Preconditions.checkNotNull(field);
-        ReadyUpcall message = (ReadyUpcall) rawMessage;
-        throw new IllegalArgumentException("Bad descriptor: " + field);
-      }
-      
-      /** Returns the {@code field} from {@code message}. */
-      @Override
-      @SuppressWarnings("unchecked")
-      public Object getField(MessageLite rawMessage, Descriptor field) {
-        Preconditions.checkNotNull(rawMessage);
-        Preconditions.checkNotNull(field);
-        ReadyUpcall message = (ReadyUpcall) rawMessage;
-        throw new IllegalArgumentException("Bad descriptor: " + field);
-      }
-      
-      @Override
-      public Set<String> getAllFieldNames() {
-        return ALL_FIELD_NAMES;
-      }
-    }
-    public static final ReadyUpcallAccessor READY_UPCALL_ACCESSOR = new ReadyUpcallAccessor();
-    
-    private static final Set<String> ALL_FIELD_NAMES = new HashSet<String>(
-      Arrays.<String>asList(
-        "serial",
-        "version",
-        "ready",
-        "invalidate",
-        "registration_status",
-        "registration_failure",
-        "reissue_registrations",
-        "error"
-      ));
-    
-    public static final Descriptor SERIAL = new Descriptor("serial");
-    public static final Descriptor VERSION = new Descriptor("version");
-    public static final Descriptor READY = new Descriptor("ready");
-    public static final Descriptor INVALIDATE = new Descriptor("invalidate");
-    public static final Descriptor REGISTRATION_STATUS = new Descriptor("registration_status");
-    public static final Descriptor REGISTRATION_FAILURE = new Descriptor("registration_failure");
-    public static final Descriptor REISSUE_REGISTRATIONS = new Descriptor("reissue_registrations");
-    public static final Descriptor ERROR = new Descriptor("error");
-    
-    /** Returns whether {@code field} is present in {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public boolean hasField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      ListenerUpcall message = (ListenerUpcall) rawMessage;
-      if (field == SERIAL) {
-        return message.hasSerial();
-      }
-      if (field == VERSION) {
-        return message.hasVersion();
-      }
-      if (field == READY) {
-        return message.hasReady();
-      }
-      if (field == INVALIDATE) {
-        return message.hasInvalidate();
-      }
-      if (field == REGISTRATION_STATUS) {
-        return message.hasRegistrationStatus();
-      }
-      if (field == REGISTRATION_FAILURE) {
-        return message.hasRegistrationFailure();
-      }
-      if (field == REISSUE_REGISTRATIONS) {
-        return message.hasReissueRegistrations();
-      }
-      if (field == ERROR) {
-        return message.hasError();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    /** Returns the {@code field} from {@code message}. */
-    @Override
-    @SuppressWarnings("unchecked")
-    public Object getField(MessageLite rawMessage, Descriptor field) {
-      Preconditions.checkNotNull(rawMessage);
-      Preconditions.checkNotNull(field);
-      ListenerUpcall message = (ListenerUpcall) rawMessage;
-      if (field == SERIAL) {
-        return message.getSerial();
-      }
-      if (field == VERSION) {
-        return message.getVersion();
-      }
-      if (field == READY) {
-        return message.getReady();
-      }
-      if (field == INVALIDATE) {
-        return message.getInvalidate();
-      }
-      if (field == REGISTRATION_STATUS) {
-        return message.getRegistrationStatus();
-      }
-      if (field == REGISTRATION_FAILURE) {
-        return message.getRegistrationFailure();
-      }
-      if (field == REISSUE_REGISTRATIONS) {
-        return message.getReissueRegistrations();
-      }
-      if (field == ERROR) {
-        return message.getError();
-      }
-      throw new IllegalArgumentException("Bad descriptor: " + field);
-    }
-    
-    @Override
-    public Set<String> getAllFieldNames() {
-      return ALL_FIELD_NAMES;
-    }
-  }
-  public static final ListenerUpcallAccessor LISTENER_UPCALL_ACCESSOR = new ListenerUpcallAccessor();
-  
-}
diff --git a/java/com/google/ipc/invalidation/ticl/android2/AndroidStrings.java b/java/com/google/ipc/invalidation/ticl/android2/AndroidStrings.java
deleted file mode 100644
index 4bc6c5b..0000000
--- a/java/com/google/ipc/invalidation/ticl/android2/AndroidStrings.java
+++ /dev/null
@@ -1,390 +0,0 @@
-/*
- * 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.common.base.Joiner;
-import com.google.ipc.invalidation.common.CommonProtoStrings2;
-import com.google.ipc.invalidation.util.TextBuilder;
-import com.google.protobuf.ByteString;
-import com.google.protobuf.InvalidProtocolBufferException;
-import com.google.protos.ipc.invalidation.AndroidService.AndroidNetworkSendRequest;
-import com.google.protos.ipc.invalidation.AndroidService.AndroidSchedulerEvent;
-import com.google.protos.ipc.invalidation.AndroidService.ClientDowncall;
-import com.google.protos.ipc.invalidation.AndroidService.ClientDowncall.AckDowncall;
-import com.google.protos.ipc.invalidation.AndroidService.ClientDowncall.RegistrationDowncall;
-import com.google.protos.ipc.invalidation.AndroidService.InternalDowncall;
-import com.google.protos.ipc.invalidation.AndroidService.InternalDowncall.CreateClient;
-import com.google.protos.ipc.invalidation.AndroidService.InternalDowncall.NetworkStatus;
-import com.google.protos.ipc.invalidation.AndroidService.InternalDowncall.ServerMessage;
-import com.google.protos.ipc.invalidation.AndroidService.ListenerUpcall;
-import com.google.protos.ipc.invalidation.AndroidService.ListenerUpcall.ErrorUpcall;
-import com.google.protos.ipc.invalidation.AndroidService.ListenerUpcall.InvalidateUpcall;
-import com.google.protos.ipc.invalidation.AndroidService.ListenerUpcall.RegistrationFailureUpcall;
-import com.google.protos.ipc.invalidation.AndroidService.ListenerUpcall.RegistrationStatusUpcall;
-import com.google.protos.ipc.invalidation.AndroidService.ListenerUpcall.ReissueRegistrationsUpcall;
-import com.google.protos.ipc.invalidation.Client.AckHandleP;
-import com.google.protos.ipc.invalidation.ClientProtocol.ObjectIdP;
-
-import android.content.Intent;
-
-import java.util.List;
-
-
-/**
- * Utilities to format Android protocol buffers and intents as compact strings suitable for logging.
- * By convention, methods take a {@link TextBuilder} and the object to format and return the
- * builder. Null object arguments are permitted.
- *
- * <p>{@link #toCompactString} methods immediately append a description of the object to the given
- * {@link TextBuilder}s. {@link #toLazyCompactString} methods return an object that defers the work
- * of formatting the provided argument until {@link Object#toString} is called.
- *
- */
-public class AndroidStrings {
-
-  /**
-   * String to return when the argument is unknown (suggests a new protocol field or invalid
-   * proto).
-   */
-  static final String UNKNOWN_MESSAGE = "UNKNOWN@AndroidStrings";
-
-  /**
-   * String to return when there is an error formatting an argument.
-   */
-  static final String ERROR_MESSAGE = "ERROR@AndroidStrings";
-
-  /**
-   * Returns an object that lazily evaluates {@link #toCompactString} when {@link Object#toString}
-   * is called.
-   */
-  public static Object toLazyCompactString(final Intent intent) {
-    return new Object() {
-      @Override
-      public String toString() {
-        TextBuilder builder = new TextBuilder();
-        AndroidStrings.toCompactString(builder, intent);
-        return builder.toString();
-      }
-    };
-  }
-
-  /** Appends a description of the given client {@code downcall} to the given {@code builder}. */
-  public static TextBuilder toCompactString(TextBuilder builder,
-      ClientDowncall downcall) {
-    if (downcall == null) {
-      return builder;
-    }
-    builder.append(ProtocolIntents.CLIENT_DOWNCALL_KEY).append("::");
-    if (downcall.hasStart()) {
-      builder.append("start()");
-    } else if (downcall.hasStop()) {
-      builder.append("stop()");
-    } else if (downcall.hasAck()) {
-      toCompactString(builder, downcall.getAck());
-    } else if (downcall.hasRegistrations()) {
-      toCompactString(builder, downcall.getRegistrations());
-    } else {
-      builder.append(UNKNOWN_MESSAGE);
-    }
-    return builder;
-  }
-
-  /** Appends a description of the given {@code ack} downcall to the given {@code builder}. */
-  public static TextBuilder toCompactString(TextBuilder builder, AckDowncall ack) {
-    if (ack == null) {
-      return builder;
-    }
-    builder.append("ack(");
-    serializedAckHandleToCompactString(builder, ack.getAckHandle());
-    return builder.append(")");
-  }
-
-  /**
-   * Appends a description of the given {@code registration} downcall to the given {@code builder}.
-   */
-  public static TextBuilder toCompactString(TextBuilder builder,
-      RegistrationDowncall registration) {
-    if (registration == null) {
-      return builder;
-    }
-    List<ObjectIdP> objects;
-    if (registration.getRegistrationsCount() > 0) {
-      builder.append("register(");
-      objects = registration.getRegistrationsList();
-    } else {
-      builder.append("unregister(");
-      objects = registration.getUnregistrationsList();
-    }
-    return CommonProtoStrings2.toCompactStringForObjectIds(builder, objects).append(")");
-  }
-
-  /** Appends a description of the given internal {@code downcall} to the given {@code builder}. */
-  public static TextBuilder toCompactString(TextBuilder builder,
-      InternalDowncall downcall) {
-    if (downcall == null) {
-      return builder;
-    }
-    builder.append(ProtocolIntents.INTERNAL_DOWNCALL_KEY).append("::");
-    if (downcall.hasServerMessage()) {
-      toCompactString(builder, downcall.getServerMessage());
-    } else if (downcall.hasNetworkStatus()) {
-      toCompactString(builder, downcall.getNetworkStatus());
-    } else if (downcall.hasNetworkAddrChange()) {
-      builder.append("newtworkAddrChange()");
-    } else if (downcall.hasCreateClient()) {
-      toCompactString(builder, downcall.getCreateClient());
-    } else {
-      builder.append(UNKNOWN_MESSAGE);
-    }
-    return builder;
-  }
-
-  /** Appends a description of the given {@code serverMessage} to the given {@code builder}. */
-  public static TextBuilder toCompactString(TextBuilder builder,
-      ServerMessage serverMessage) {
-    if (serverMessage == null) {
-      return builder;
-    }
-    return builder.append("serverMessage(").append(serverMessage.getData()).append(")");
-  }
-
-  /** Appends a description of the given {@code networkStatus} to the given {@code builder}. */
-  public static TextBuilder toCompactString(TextBuilder builder,
-      NetworkStatus networkStatus) {
-    if (networkStatus == null) {
-      return builder;
-    }
-    return builder.append("networkStatus(isOnline = ").append(networkStatus.getIsOnline())
-        .append(")");
-  }
-
-  /**
-   * Appends a description of the given {@code createClient} command to the given {@code builder}.
-   */
-  public static TextBuilder toCompactString(TextBuilder builder,
-      CreateClient createClient) {
-    if (createClient == null) {
-      return builder;
-    }
-    return builder.append("createClient(type = ").append(createClient.getClientType())
-        .append(", name = ").append(createClient.getClientName()).append(", skipStartForTest = ")
-        .append(createClient.getSkipStartForTest()).append(")");
-  }
-
-  /** Appends a description of the given listener {@code upcall} to the given {@code builder}. */
-  public static TextBuilder toCompactString(TextBuilder builder,
-      ListenerUpcall upcall) {
-    if (upcall == null) {
-       return builder;
-    }
-    builder.append(ProtocolIntents.LISTENER_UPCALL_KEY).append("::");
-    if (upcall.hasReady()) {
-      builder.append(".ready()");
-    } else if (upcall.hasInvalidate()) {
-      toCompactString(builder, upcall.getInvalidate());
-    } else if (upcall.hasRegistrationStatus()) {
-      toCompactString(builder, upcall.getRegistrationStatus());
-    } else if (upcall.hasRegistrationFailure()) {
-      toCompactString(builder, upcall.getRegistrationFailure());
-    } else if (upcall.hasReissueRegistrations()) {
-      toCompactString(builder, upcall.getReissueRegistrations());
-    } else if (upcall.hasError()) {
-      toCompactString(builder, upcall.getError());
-    } else {
-      builder.append(UNKNOWN_MESSAGE);
-    }
-    return builder;
-  }
-
-  /** Appends a description of the given {@code invalidate} command to the given {@code builder}. */
-  public static TextBuilder toCompactString(TextBuilder builder,
-      InvalidateUpcall invalidate) {
-    if (invalidate == null) {
-      return builder;
-    }
-    builder.append("invalidate(ackHandle = ");
-    serializedAckHandleToCompactString(builder, invalidate.getAckHandle());
-    builder.append(", ");
-    if (invalidate.hasInvalidation()) {
-      CommonProtoStrings2.toCompactString(builder, invalidate.getInvalidation());
-    } else if (invalidate.getInvalidateAll()) {
-      builder.append("ALL");
-    } else if (invalidate.hasInvalidateUnknown()) {
-      builder.append("UNKNOWN: ");
-      CommonProtoStrings2.toCompactString(builder, invalidate.getInvalidateUnknown());
-    }
-    return builder.append(")");
-  }
-
-  /** Appends a description of the given {@code status} upcall to the given {@code builder}. */
-  public static TextBuilder toCompactString(TextBuilder builder,
-      RegistrationStatusUpcall status) {
-    if (status == null) {
-      return builder;
-    }
-    builder.append("registrationStatus(objectId = ");
-    CommonProtoStrings2.toCompactString(builder, status.getObjectId());
-    return builder.append(", isRegistered = ").append(status.getIsRegistered()).append(")");
-  }
-
-  /** Appends a description of the given {@code failure} upcall to the given {@code builder}. */
-  public static TextBuilder toCompactString(TextBuilder builder,
-      RegistrationFailureUpcall failure) {
-    if (failure == null) {
-      return builder;
-    }
-    builder.append("registrationFailure(objectId = ");
-    CommonProtoStrings2.toCompactString(builder, failure.getObjectId());
-    return builder.append(", isTransient = ").append(failure.getTransient()).append(")");
-  }
-
-  /**
-   * Appends a description of the given {@code reissue} registrations upcall to the given
-   * {@code builder}.
-   */
-  public static TextBuilder toCompactString(TextBuilder builder,
-      ReissueRegistrationsUpcall reissue) {
-    if (reissue == null) {
-      return builder;
-    }
-    builder.append("reissueRegistrations(prefix = ");
-    return builder.append(reissue.getPrefix()).append(", length = ").append(reissue.getLength())
-        .append(")");
-  }
-
-  /** Appends a description of the given {@code error} upcall to the given {@code builder}. */
-  public static TextBuilder toCompactString(TextBuilder builder, ErrorUpcall error) {
-    if (error == null) {
-      return builder;
-    }
-    return builder.append("error(code = ").append(error.getErrorCode()).append(", message = ")
-        .append(error.getErrorMessage()).append(", isTransient = ").append(error.getIsTransient())
-        .append(")");
-  }
-
-  /** Appends a description of the given {@code request} to the given {@code builder}. */
-  public static TextBuilder toCompactString(TextBuilder builder,
-      AndroidNetworkSendRequest request) {
-    if (request == null) {
-      return builder;
-    }
-    return builder.append(ProtocolIntents.OUTBOUND_MESSAGE_KEY).append("(")
-        .append(request.getMessage()).append(")");
-  }
-
-  /** Appends a description of the given (@code event} to the given {@code builder}. */
-  public static TextBuilder toCompactString(TextBuilder builder,
-      AndroidSchedulerEvent event) {
-    if (event == null) {
-      return builder;
-    }
-    return builder.append(ProtocolIntents.SCHEDULER_KEY).append("(eventName = ")
-        .append(event.getEventName()).append(", ticlId = ").append(event.getTiclId()).append(")");
-  }
-
-  /** See spec in implementation notes. */
-  public static TextBuilder toCompactString(TextBuilder builder, AckHandleP ackHandle) {
-    if (ackHandle == null) {
-      return builder;
-    }
-    return CommonProtoStrings2.toCompactString(builder.appendFormat("AckHandle: "),
-        ackHandle.getInvalidation());
-  }
-
-  /**
-   * Appends a description of the given {@code intent} to the given {@code builder}. If the intent
-   * includes some recognized extras, formats the extra context as well.
-   */
-  public static TextBuilder toCompactString(TextBuilder builder, Intent intent) {
-    if (intent == null) {
-      return builder;
-    }
-    builder.append("intent(");
-    try {
-      if (!tryParseExtra(builder, intent)) {
-        builder.append(UNKNOWN_MESSAGE).append(", extras = ")
-            .append(Joiner.on(", ").join(intent.getExtras().keySet()));
-      }
-    } catch (InvalidProtocolBufferException exception) {
-      builder.append(ERROR_MESSAGE).append(" : ").append(exception);
-    }
-    return builder.append(")");
-  }
-
-  /** Appends a description of any known extra or appends 'UNKNOWN' if none are recognized. */
-  private static boolean tryParseExtra(TextBuilder builder, Intent intent)
-      throws InvalidProtocolBufferException {
-    byte[] data;
-
-    data = intent.getByteArrayExtra(ProtocolIntents.SCHEDULER_KEY);
-    if (data != null) {
-      AndroidSchedulerEvent schedulerEvent = AndroidSchedulerEvent.parseFrom(data);
-      toCompactString(builder, schedulerEvent);
-      return true;
-    }
-
-    data = intent.getByteArrayExtra(ProtocolIntents.OUTBOUND_MESSAGE_KEY);
-    if (data != null) {
-      AndroidNetworkSendRequest outboundMessage = AndroidNetworkSendRequest.parseFrom(data);
-      toCompactString(builder, outboundMessage);
-      return true;
-    }
-
-    data = intent.getByteArrayExtra(ProtocolIntents.LISTENER_UPCALL_KEY);
-    if (data != null) {
-      ListenerUpcall upcall = ListenerUpcall.parseFrom(data);
-      toCompactString(builder, upcall);
-      return true;
-    }
-
-    data = intent.getByteArrayExtra(ProtocolIntents.INTERNAL_DOWNCALL_KEY);
-    if (data != null) {
-      InternalDowncall internalDowncall = InternalDowncall.parseFrom(data);
-      toCompactString(builder, internalDowncall);
-      return true;
-    }
-
-    data = intent.getByteArrayExtra(ProtocolIntents.CLIENT_DOWNCALL_KEY);
-    if (data != null) {
-      ClientDowncall clientDowncall = ClientDowncall.parseFrom(data);
-      toCompactString(builder, clientDowncall);
-      return true;
-    }
-
-    // Didn't recognize any intents.
-    return false;
-  }
-
-  /** Given serialized form of an ack handle, appends description to {@code builder}. */
-  private static TextBuilder serializedAckHandleToCompactString(
-      TextBuilder builder, ByteString serialized) {
-    if (serialized == null) {
-      return builder;
-    }
-    // The ack handle is supposed by an AckHandleP!
-    try {
-      AckHandleP ackHandle = AckHandleP.parseFrom(serialized);
-      return toCompactString(builder, ackHandle);
-    } catch (InvalidProtocolBufferException exception) {
-      // But it wasn't... Just log the raw bytes.
-      return builder.append(serialized);
-    }
-  }
-
-  private AndroidStrings() {
-    // Avoid instantiation.
-  }
-}
diff --git a/java/com/google/ipc/invalidation/ticl/android2/ProtocolIntents.java b/java/com/google/ipc/invalidation/ticl/android2/ProtocolIntents.java
index 28605be..c5b19ca 100644
--- a/java/com/google/ipc/invalidation/ticl/android2/ProtocolIntents.java
+++ b/java/com/google/ipc/invalidation/ticl/android2/ProtocolIntents.java
@@ -15,36 +15,37 @@
  */
 package com.google.ipc.invalidation.ticl.android2;
 
-import com.google.ipc.invalidation.common.CommonProtos2;
 import com.google.ipc.invalidation.external.client.types.ErrorInfo;
-import com.google.protobuf.ByteString;
-import com.google.protos.ipc.invalidation.AndroidService.AndroidNetworkSendRequest;
-import com.google.protos.ipc.invalidation.AndroidService.AndroidSchedulerEvent;
-import com.google.protos.ipc.invalidation.AndroidService.ClientDowncall;
-import com.google.protos.ipc.invalidation.AndroidService.ClientDowncall.AckDowncall;
-import com.google.protos.ipc.invalidation.AndroidService.ClientDowncall.RegistrationDowncall;
-import com.google.protos.ipc.invalidation.AndroidService.ClientDowncall.StartDowncall;
-import com.google.protos.ipc.invalidation.AndroidService.ClientDowncall.StopDowncall;
-import com.google.protos.ipc.invalidation.AndroidService.InternalDowncall;
-import com.google.protos.ipc.invalidation.AndroidService.InternalDowncall.CreateClient;
-import com.google.protos.ipc.invalidation.AndroidService.InternalDowncall.NetworkStatus;
-import com.google.protos.ipc.invalidation.AndroidService.InternalDowncall.ServerMessage;
-import com.google.protos.ipc.invalidation.AndroidService.ListenerUpcall;
-import com.google.protos.ipc.invalidation.AndroidService.ListenerUpcall.ErrorUpcall;
-import com.google.protos.ipc.invalidation.AndroidService.ListenerUpcall.InvalidateUpcall;
-import com.google.protos.ipc.invalidation.AndroidService.ListenerUpcall.ReadyUpcall;
-import com.google.protos.ipc.invalidation.AndroidService.ListenerUpcall.RegistrationFailureUpcall;
-import com.google.protos.ipc.invalidation.AndroidService.ListenerUpcall.RegistrationStatusUpcall;
-import com.google.protos.ipc.invalidation.AndroidService.ListenerUpcall.ReissueRegistrationsUpcall;
-import com.google.protos.ipc.invalidation.Client.AckHandleP;
-import com.google.protos.ipc.invalidation.ClientProtocol.ClientConfigP;
-import com.google.protos.ipc.invalidation.ClientProtocol.InvalidationMessage;
-import com.google.protos.ipc.invalidation.ClientProtocol.InvalidationP;
-import com.google.protos.ipc.invalidation.ClientProtocol.ObjectIdP;
-import com.google.protos.ipc.invalidation.ClientProtocol.Version;
+import com.google.ipc.invalidation.ticl.proto.AndroidService.AndroidNetworkSendRequest;
+import com.google.ipc.invalidation.ticl.proto.AndroidService.AndroidSchedulerEvent;
+import com.google.ipc.invalidation.ticl.proto.AndroidService.ClientDowncall;
+import com.google.ipc.invalidation.ticl.proto.AndroidService.ClientDowncall.AckDowncall;
+import com.google.ipc.invalidation.ticl.proto.AndroidService.ClientDowncall.RegistrationDowncall;
+import com.google.ipc.invalidation.ticl.proto.AndroidService.ClientDowncall.StartDowncall;
+import com.google.ipc.invalidation.ticl.proto.AndroidService.ClientDowncall.StopDowncall;
+import com.google.ipc.invalidation.ticl.proto.AndroidService.InternalDowncall;
+import com.google.ipc.invalidation.ticl.proto.AndroidService.InternalDowncall.CreateClient;
+import com.google.ipc.invalidation.ticl.proto.AndroidService.InternalDowncall.NetworkStatus;
+import com.google.ipc.invalidation.ticl.proto.AndroidService.InternalDowncall.ServerMessage;
+import com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall;
+import com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.ErrorUpcall;
+import com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.InvalidateUpcall;
+import com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.ReadyUpcall;
+import com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.RegistrationFailureUpcall;
+import com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.RegistrationStatusUpcall;
+import com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.ReissueRegistrationsUpcall;
+import com.google.ipc.invalidation.ticl.proto.Client.AckHandleP;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.ClientConfigP;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationMessage;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationP;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version;
+import com.google.ipc.invalidation.util.Bytes;
 
 import android.content.Intent;
 
+import java.util.Collection;
+
 /**
  * Factory class for {@link Intent}s used between the application, Ticl, and listener in the
  * Android Ticl.
@@ -52,7 +53,7 @@
  */
 public class ProtocolIntents {
   /** Version of the on-device protocol. */
-  static final Version ANDROID_PROTOCOL_VERSION_VALUE = CommonProtos2.newVersion(1, 0);
+  static final Version ANDROID_PROTOCOL_VERSION_VALUE = Version.create(1, 0);
 
   /** Key of Intent byte[] extra holding a client downcall protocol buffer. */
   public static final String CLIENT_DOWNCALL_KEY = "ipcinv-downcall";
@@ -76,51 +77,44 @@
   public static class ClientDowncalls {
     public static Intent newStartIntent() {
       Intent intent = new Intent();
-      intent.putExtra(CLIENT_DOWNCALL_KEY, newBuilder()
-          .setStart(StartDowncall.getDefaultInstance())
-          .build().toByteArray());
+      intent.putExtra(CLIENT_DOWNCALL_KEY, ClientDowncall.createWithStart(
+          ANDROID_PROTOCOL_VERSION_VALUE, StartDowncall.DEFAULT_INSTANCE).toByteArray());
       return intent;
     }
 
     public static Intent newStopIntent() {
       Intent intent = new Intent();
-      intent.putExtra(CLIENT_DOWNCALL_KEY, newBuilder()
-          .setStop(StopDowncall.getDefaultInstance())
-          .build().toByteArray());
+      intent.putExtra(CLIENT_DOWNCALL_KEY, ClientDowncall.createWithStop(
+          ANDROID_PROTOCOL_VERSION_VALUE, StopDowncall.DEFAULT_INSTANCE).toByteArray());
       return intent;
     }
 
-    public static Intent newAcknowledgeIntent(AckHandleP ackHandle) {
-      AckDowncall ackDowncall = AckDowncall.newBuilder()
-          .setAckHandle(ackHandle.toByteString()).build();
+    public static Intent newAcknowledgeIntent(byte[] ackHandleData) {
+      AckDowncall ackDowncall = AckDowncall.create(new Bytes(ackHandleData));
       Intent intent = new Intent();
-      intent.putExtra(CLIENT_DOWNCALL_KEY,
-          newBuilder().setAck(ackDowncall).build().toByteArray());
+      intent.putExtra(CLIENT_DOWNCALL_KEY, ClientDowncall.createWithAck(
+          ANDROID_PROTOCOL_VERSION_VALUE, ackDowncall).toByteArray());
       return intent;
     }
 
-    public static Intent newRegistrationIntent(Iterable<ObjectIdP> registrations) {
-      RegistrationDowncall regDowncall = RegistrationDowncall.newBuilder()
-          .addAllRegistrations(registrations).build();
+    public static Intent newRegistrationIntent(Collection<ObjectIdP> registrations) {
+      RegistrationDowncall regDowncall =
+          RegistrationDowncall.createWithRegistrations(registrations);
       Intent intent = new Intent();
-      intent.putExtra(CLIENT_DOWNCALL_KEY,
-          newBuilder().setRegistrations(regDowncall).build().toByteArray());
+      intent.putExtra(CLIENT_DOWNCALL_KEY, ClientDowncall.createWithRegistrations(
+          ANDROID_PROTOCOL_VERSION_VALUE, regDowncall).toByteArray());
       return intent;
     }
 
-    public static Intent newUnregistrationIntent(Iterable<ObjectIdP> unregistrations) {
-      RegistrationDowncall unregDowncall = RegistrationDowncall.newBuilder()
-          .addAllUnregistrations(unregistrations).build();
+    public static Intent newUnregistrationIntent(Collection<ObjectIdP> unregistrations) {
+      RegistrationDowncall regDowncall =
+          RegistrationDowncall.createWithUnregistrations(unregistrations);
       Intent intent = new Intent();
-      intent.putExtra(CLIENT_DOWNCALL_KEY,
-          newBuilder().setRegistrations(unregDowncall).build().toByteArray());
+      intent.putExtra(CLIENT_DOWNCALL_KEY, ClientDowncall.createWithRegistrations(
+          ANDROID_PROTOCOL_VERSION_VALUE, regDowncall).toByteArray());
       return intent;
     }
 
-    private static ClientDowncall.Builder newBuilder() {
-      return ClientDowncall.newBuilder().setVersion(ANDROID_PROTOCOL_VERSION_VALUE);
-    }
-
     private ClientDowncalls() {
       // Disallow instantiation.
     }
@@ -128,49 +122,38 @@
 
   /** Intents for non-public calls on the Ticl (currently, network-related calls. */
   public static class InternalDowncalls {
-    public static Intent newServerMessageIntent(ByteString serverMessage) {
+    public static Intent newServerMessageIntent(Bytes serverMessage) {
       Intent intent = new Intent();
-      intent.putExtra(INTERNAL_DOWNCALL_KEY,
-          newBuilder()
-            .setServerMessage(ServerMessage.newBuilder().setData(serverMessage))
-            .build().toByteArray());
+      intent.putExtra(INTERNAL_DOWNCALL_KEY, InternalDowncall.createWithServerMessage(
+          ANDROID_PROTOCOL_VERSION_VALUE, ServerMessage.create(serverMessage))
+          .toByteArray());
       return intent;
     }
 
     public static Intent newNetworkStatusIntent(Boolean status) {
       Intent intent = new Intent();
-      intent.putExtra(INTERNAL_DOWNCALL_KEY,
-          newBuilder()
-          .setNetworkStatus(NetworkStatus.newBuilder().setIsOnline(status))
-          .build().toByteArray());
+      intent.putExtra(INTERNAL_DOWNCALL_KEY, InternalDowncall.createWithNetworkStatus(
+          ANDROID_PROTOCOL_VERSION_VALUE, NetworkStatus.create(status)).toByteArray());
       return intent;
     }
 
     public static Intent newNetworkAddrChangeIntent() {
       Intent intent = new Intent();
-      intent.putExtra(INTERNAL_DOWNCALL_KEY,
-          newBuilder().setNetworkAddrChange(true).build().toByteArray());
+      intent.putExtra(INTERNAL_DOWNCALL_KEY, InternalDowncall.createWithNetworkAddrChange(
+          ANDROID_PROTOCOL_VERSION_VALUE, true).toByteArray());
       return intent;
     }
 
-    public static Intent newCreateClientIntent(int clientType, byte[] clientName,
+    public static Intent newCreateClientIntent(int clientType, Bytes clientName,
         ClientConfigP config, boolean skipStartForTest) {
-      CreateClient createClient = CreateClient.newBuilder()
-          .setClientType(clientType)
-          .setClientName(ByteString.copyFrom(clientName))
-          .setClientConfig(config)
-          .setSkipStartForTest(skipStartForTest)
-          .build();
+      CreateClient createClient =
+          CreateClient.create(clientType, clientName, config, skipStartForTest);
       Intent intent = new Intent();
-      intent.putExtra(INTERNAL_DOWNCALL_KEY,
-          newBuilder().setCreateClient(createClient).build().toByteArray());
+      intent.putExtra(INTERNAL_DOWNCALL_KEY, InternalDowncall.createWithCreateClient(
+          ANDROID_PROTOCOL_VERSION_VALUE, createClient).toByteArray());
       return intent;
     }
 
-    private static InternalDowncall.Builder newBuilder() {
-      return InternalDowncall.newBuilder().setVersion(ANDROID_PROTOCOL_VERSION_VALUE);
-    }
-
     private InternalDowncalls() {
       // Disallow instantiation.
     }
@@ -180,89 +163,74 @@
   public static class ListenerUpcalls {
     public static Intent newReadyIntent() {
       Intent intent = new Intent();
-      intent.putExtra(LISTENER_UPCALL_KEY,
-          newBuilder().setReady(ReadyUpcall.getDefaultInstance()).build().toByteArray());
+      intent.putExtra(LISTENER_UPCALL_KEY, ListenerUpcall.createWithReady(
+          ANDROID_PROTOCOL_VERSION_VALUE, ReadyUpcall.DEFAULT_INSTANCE).toByteArray());
       return intent;
     }
 
     public static Intent newInvalidateIntent(InvalidationP invalidation, AckHandleP ackHandle) {
       Intent intent = new Intent();
-      InvalidateUpcall invUpcall = InvalidateUpcall.newBuilder()
-          .setAckHandle(ackHandle.toByteString())
-          .setInvalidation(invalidation).build();
-      intent.putExtra(LISTENER_UPCALL_KEY,
-          newBuilder().setInvalidate(invUpcall).build().toByteArray());
+      InvalidateUpcall invUpcall =
+          InvalidateUpcall.createWithInvalidation(new Bytes(ackHandle.toByteArray()), invalidation);
+      intent.putExtra(LISTENER_UPCALL_KEY, ListenerUpcall.createWithInvalidate(
+          ANDROID_PROTOCOL_VERSION_VALUE, invUpcall).toByteArray());
       return intent;
     }
 
     public static Intent newInvalidateUnknownIntent(ObjectIdP object, AckHandleP ackHandle) {
       Intent intent = new Intent();
-      InvalidateUpcall invUpcall = InvalidateUpcall.newBuilder()
-          .setAckHandle(ackHandle.toByteString())
-          .setInvalidateUnknown(object).build();
-      intent.putExtra(LISTENER_UPCALL_KEY,
-          newBuilder().setInvalidate(invUpcall).build().toByteArray());
+      InvalidateUpcall invUpcall =
+          InvalidateUpcall.createWithInvalidateUnknown(new Bytes(ackHandle.toByteArray()), object);
+      intent.putExtra(LISTENER_UPCALL_KEY, ListenerUpcall.createWithInvalidate(
+          ANDROID_PROTOCOL_VERSION_VALUE, invUpcall).toByteArray());
       return intent;
     }
 
     public static Intent newInvalidateAllIntent(AckHandleP ackHandle) {
       Intent intent = new Intent();
-      InvalidateUpcall invUpcall = InvalidateUpcall.newBuilder()
-          .setAckHandle(ackHandle.toByteString())
-          .setInvalidateAll(true).build();
-      intent.putExtra(LISTENER_UPCALL_KEY,
-          newBuilder().setInvalidate(invUpcall).build().toByteArray());
+      InvalidateUpcall invUpcall = InvalidateUpcall.createWithInvalidateAll(
+          new Bytes(ackHandle.toByteArray()), true);
+      intent.putExtra(LISTENER_UPCALL_KEY, ListenerUpcall.createWithInvalidate(
+          ANDROID_PROTOCOL_VERSION_VALUE, invUpcall).toByteArray());
       return intent;
     }
 
     public static Intent newRegistrationStatusIntent(ObjectIdP object, boolean isRegistered) {
       Intent intent = new Intent();
-      RegistrationStatusUpcall regUpcall = RegistrationStatusUpcall.newBuilder()
-            .setObjectId(object)
-            .setIsRegistered(isRegistered).build();
-      intent.putExtra(LISTENER_UPCALL_KEY,
-          newBuilder().setRegistrationStatus(regUpcall).build().toByteArray());
+      RegistrationStatusUpcall regUpcall = RegistrationStatusUpcall.create(object, isRegistered);
+      intent.putExtra(LISTENER_UPCALL_KEY, ListenerUpcall.createWithRegistrationStatus(
+          ANDROID_PROTOCOL_VERSION_VALUE, regUpcall).toByteArray());
       return intent;
     }
 
     public static Intent newRegistrationFailureIntent(ObjectIdP object, boolean isTransient,
         String message) {
       Intent intent = new Intent();
-      RegistrationFailureUpcall regUpcall = RegistrationFailureUpcall.newBuilder()
-            .setObjectId(object)
-            .setTransient(isTransient)
-            .setMessage(message).build();
-      intent.putExtra(LISTENER_UPCALL_KEY,
-          newBuilder().setRegistrationFailure(regUpcall).build().toByteArray());
+      RegistrationFailureUpcall regUpcall =
+          RegistrationFailureUpcall.create(object, isTransient, message);
+      intent.putExtra(LISTENER_UPCALL_KEY, ListenerUpcall.createWithRegistrationFailure(
+          ANDROID_PROTOCOL_VERSION_VALUE, regUpcall).toByteArray());
       return intent;
     }
 
     public static Intent newReissueRegistrationsIntent(byte[] prefix, int length) {
       Intent intent = new Intent();
-      ReissueRegistrationsUpcall reissueRegistrations = ReissueRegistrationsUpcall.newBuilder()
-          .setPrefix(ByteString.copyFrom(prefix))
-          .setLength(length).build();
-      intent.putExtra(LISTENER_UPCALL_KEY,
-          newBuilder().setReissueRegistrations(reissueRegistrations).build().toByteArray());
+      ReissueRegistrationsUpcall reissueRegistrations =
+          ReissueRegistrationsUpcall.create(new Bytes(prefix), length);
+      intent.putExtra(LISTENER_UPCALL_KEY, ListenerUpcall.createWithReissueRegistrations(
+          ANDROID_PROTOCOL_VERSION_VALUE, reissueRegistrations).toByteArray());
       return intent;
     }
 
     public static Intent newErrorIntent(ErrorInfo errorInfo) {
       Intent intent = new Intent();
-      ErrorUpcall errorUpcall = ErrorUpcall.newBuilder()
-          .setErrorCode(errorInfo.getErrorReason())
-          .setErrorMessage(errorInfo.getErrorMessage())
-          .setIsTransient(errorInfo.isTransient())
-          .build();
-      intent.putExtra(LISTENER_UPCALL_KEY,
-          newBuilder().setError(errorUpcall).build().toByteArray());
+      ErrorUpcall errorUpcall = ErrorUpcall.create(errorInfo.getErrorReason(),
+          errorInfo.getErrorMessage(), errorInfo.isTransient());
+      intent.putExtra(LISTENER_UPCALL_KEY, ListenerUpcall.createWithError(
+          ANDROID_PROTOCOL_VERSION_VALUE, errorUpcall).toByteArray());
       return intent;
     }
 
-    private static ListenerUpcall.Builder newBuilder() {
-      return ListenerUpcall.newBuilder().setVersion(ANDROID_PROTOCOL_VERSION_VALUE);
-    }
-
     private ListenerUpcalls() {
       // Disallow instantiation.
     }
@@ -270,19 +238,15 @@
 
   /** Returns a new intent encoding a request to execute the scheduled action {@code eventName}. */
   public static Intent newSchedulerIntent(String eventName, long ticlId) {
-    byte[] eventBytes =
-        AndroidSchedulerEvent.newBuilder()
-          .setVersion(ANDROID_PROTOCOL_VERSION_VALUE)
-          .setEventName(eventName)
-          .setTiclId(ticlId).build().toByteArray();
+    byte[] eventBytes = AndroidSchedulerEvent.create(ANDROID_PROTOCOL_VERSION_VALUE, eventName,
+        ticlId).toByteArray();
     return new Intent().putExtra(SCHEDULER_KEY, eventBytes);
   }
 
   /** Returns a new intent encoding a message to send to the data center. */
   public static Intent newOutboundMessageIntent(byte[] message) {
-    byte[] payloadBytes = AndroidNetworkSendRequest.newBuilder()
-        .setVersion(ANDROID_PROTOCOL_VERSION_VALUE)
-        .setMessage(ByteString.copyFrom(message)).build().toByteArray();
+    byte[] payloadBytes = AndroidNetworkSendRequest.create(ANDROID_PROTOCOL_VERSION_VALUE,
+        new Bytes(message)).toByteArray();
     return new Intent().putExtra(OUTBOUND_MESSAGE_KEY, payloadBytes);
   }
 
diff --git a/java/com/google/ipc/invalidation/ticl/android2/ResourcesFactory.java b/java/com/google/ipc/invalidation/ticl/android2/ResourcesFactory.java
index 45e9232..d53e7df 100644
--- a/java/com/google/ipc/invalidation/ticl/android2/ResourcesFactory.java
+++ b/java/com/google/ipc/invalidation/ticl/android2/ResourcesFactory.java
@@ -18,9 +18,7 @@
 
 import com.google.common.base.Preconditions;
 import com.google.ipc.invalidation.external.client.SystemResources;
-import com.google.ipc.invalidation.external.client.SystemResources.NetworkChannel;
 import com.google.ipc.invalidation.external.client.SystemResources.Scheduler;
-import com.google.ipc.invalidation.external.client.SystemResources.Storage;
 import com.google.ipc.invalidation.external.client.android.service.AndroidLogger;
 import com.google.ipc.invalidation.ticl.BasicSystemResources;
 import com.google.ipc.invalidation.ticl.android2.channel.AndroidNetworkChannel;
diff --git a/java/com/google/ipc/invalidation/ticl/android2/TiclService.java b/java/com/google/ipc/invalidation/ticl/android2/TiclService.java
index 6263b89..ff979f1 100644
--- a/java/com/google/ipc/invalidation/ticl/android2/TiclService.java
+++ b/java/com/google/ipc/invalidation/ticl/android2/TiclService.java
@@ -26,22 +26,23 @@
 import com.google.ipc.invalidation.external.client.types.Status;
 import com.google.ipc.invalidation.ticl.InvalidationClientCore;
 import com.google.ipc.invalidation.ticl.PersistenceUtils;
-import com.google.ipc.invalidation.ticl.ProtoConverter;
+import com.google.ipc.invalidation.ticl.ProtoWrapperConverter;
 import com.google.ipc.invalidation.ticl.android2.AndroidInvalidationClientImpl.IntentForwardingListener;
 import com.google.ipc.invalidation.ticl.android2.ResourcesFactory.AndroidResources;
-import com.google.protobuf.InvalidProtocolBufferException;
-import com.google.protos.ipc.invalidation.AndroidService.AndroidSchedulerEvent;
-import com.google.protos.ipc.invalidation.AndroidService.ClientDowncall;
-import com.google.protos.ipc.invalidation.AndroidService.ClientDowncall.RegistrationDowncall;
-import com.google.protos.ipc.invalidation.AndroidService.InternalDowncall;
-import com.google.protos.ipc.invalidation.AndroidService.InternalDowncall.CreateClient;
-import com.google.protos.ipc.invalidation.Client.PersistentTiclState;
-import com.google.protos.ipc.invalidation.ClientProtocol.ServerToClientMessage;
+import com.google.ipc.invalidation.ticl.proto.AndroidService.AndroidSchedulerEvent;
+import com.google.ipc.invalidation.ticl.proto.AndroidService.ClientDowncall;
+import com.google.ipc.invalidation.ticl.proto.AndroidService.ClientDowncall.RegistrationDowncall;
+import com.google.ipc.invalidation.ticl.proto.AndroidService.InternalDowncall;
+import com.google.ipc.invalidation.ticl.proto.AndroidService.InternalDowncall.CreateClient;
+import com.google.ipc.invalidation.ticl.proto.Client.PersistentTiclState;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.ServerToClientMessage;
+import com.google.ipc.invalidation.util.Bytes;
+import com.google.ipc.invalidation.util.ProtoWrapper.ValidationException;
 
 import android.app.IntentService;
 import android.content.Intent;
 
-import java.util.List;
+import java.util.Collection;
 
 
 /**
@@ -60,9 +61,6 @@
   /** Resources for the created Ticls. */
   private AndroidResources resources;
 
-  /** Validator for received messages. */
-  private AndroidIntentProtocolValidator validator;
-
   /** The function for computing persistence state digests when rewriting them. */
   private final DigestFunction digestFn = new ObjectIdDigestUtils.Sha1DigestFunction();
 
@@ -95,8 +93,7 @@
     // We create resources anew each time.
     resources = createResources();
     resources.start();
-    resources.getLogger().fine("onHandleIntent(%s)", AndroidStrings.toLazyCompactString(intent));
-    validator = new AndroidIntentProtocolValidator(resources.getLogger());
+    resources.getLogger().fine("onHandleIntent(%s)", intent);
 
     try {
       // Dispatch the appropriate handler function based on which extra key is set.
@@ -110,30 +107,25 @@
         resources.getLogger().warning("Received Intent without any recognized extras: %s", intent);
       }
     } finally {
-      // Null out resources and validator to prevent accidentally using them in the future before
-      // they have been properly re-created.
+      // Null out resources to prevent accidentally using them in the future before they have been
+      // properly re-created.
       resources.stop();
       resources = null;
-      validator = null;
     }
   }
 
   /** Handles a request to call a function on the ticl. */
   private void handleClientDowncall(byte[] clientDowncallBytes) {
-    // Parse the request.
+    // Parse and validate the request.
     final ClientDowncall downcall;
     try {
       downcall = ClientDowncall.parseFrom(clientDowncallBytes);
-    } catch (InvalidProtocolBufferException exception) {
+    } catch (ValidationException exception) {
       resources.getLogger().warning("Failed parsing ClientDowncall from %s: %s",
-          clientDowncallBytes, exception.getMessage());
+          Bytes.toLazyCompactString(clientDowncallBytes), exception.getMessage());
       return;
     }
-    // Validate the request.
-    if (!validator.isDowncallValid(downcall)) {
-      resources.getLogger().warning("Ignoring invalid downcall message: %s", downcall);
-      return;
-    }
+
     resources.getLogger().fine("Handle client downcall: %s", downcall);
 
     // Restore the appropriate Ticl.
@@ -145,22 +137,23 @@
     }
 
     // Call the appropriate method.
-    if (downcall.hasAck()) {
-      ticl.acknowledge(AckHandle.newInstance(downcall.getAck().getAckHandle().toByteArray()));
+    if (downcall.getNullableAck() != null) {
+      ticl.acknowledge(
+          AckHandle.newInstance(downcall.getNullableAck().getAckHandle().getByteArray()));
     } else if (downcall.hasStart()) {
       ticl.start();
     } else if (downcall.hasStop()) {
       ticl.stop();
-    } else if (downcall.hasRegistrations()) {
-      RegistrationDowncall regDowncall = downcall.getRegistrations();
-      if (regDowncall.getRegistrationsCount() > 0) {
-        List<ObjectId> objects = ProtoConverter.convertToObjectIdList(
-            regDowncall.getRegistrationsList());
+    } else if (downcall.getNullableRegistrations() != null) {
+      RegistrationDowncall regDowncall = downcall.getNullableRegistrations();
+      if (!regDowncall.getRegistrations().isEmpty()) {
+        Collection<ObjectId> objects =
+            ProtoWrapperConverter.convertFromObjectIdProtoCollection(regDowncall.getRegistrations());
         ticl.register(objects);
       }
-      if (regDowncall.getUnregistrationsCount() > 0) {
-        List<ObjectId> objects = ProtoConverter.convertToObjectIdList(
-            regDowncall.getUnregistrationsList());
+      if (!regDowncall.getUnregistrations().isEmpty()) {
+        Collection<ObjectId> objects = ProtoWrapperConverter.convertFromObjectIdProtoCollection(
+            regDowncall.getUnregistrations());
         ticl.unregister(objects);
       }
     } else {
@@ -178,29 +171,26 @@
 
   /** Handles an internal downcall on the Ticl. */
   private void handleInternalDowncall(byte[] internalDowncallBytes) {
-    // Parse the request.
+    // Parse and validate the request.
     final InternalDowncall downcall;
     try {
       downcall = InternalDowncall.parseFrom(internalDowncallBytes);
-    } catch (InvalidProtocolBufferException exception) {
+    } catch (ValidationException exception) {
       resources.getLogger().warning("Failed parsing InternalDowncall from %s: %s",
-          internalDowncallBytes, exception.getMessage());
-      return;
-    }
-    // Validate the request.
-    if (!validator.isInternalDowncallValid(downcall)) {
-      resources.getLogger().warning("Ignoring invalid internal downcall message: %s", downcall);
+          Bytes.toLazyCompactString(internalDowncallBytes),
+          exception.getMessage());
       return;
     }
     resources.getLogger().fine("Handle internal downcall: %s", downcall);
 
     // Message from the data center; just forward it to the Ticl.
-    if (downcall.hasServerMessage()) {
+    if (downcall.getNullableServerMessage() != null) {
       // We deliver the message regardless of whether the Ticl existed, since we'll want to
       // rewrite persistent state in the case where it did not.
       // TODO: what if this is the "wrong" Ticl?
       AndroidInvalidationClientImpl ticl = TiclStateManager.restoreTicl(this, resources);
-      handleServerMessage((ticl != null), downcall.getServerMessage().getData().toByteArray());
+      handleServerMessage((ticl != null),
+          downcall.getNullableServerMessage().getData().getByteArray());
       if (ticl != null) {
         TiclStateManager.saveTicl(this, resources.getLogger(), ticl);
       }
@@ -208,13 +198,13 @@
     }
 
     // Network online/offline status change; just forward it to the Ticl.
-    if (downcall.hasNetworkStatus()) {
+    if (downcall.getNullableNetworkStatus() != null) {
       // Network status changes only make sense for Ticls that do exist.
       // TODO: what if this is the "wrong" Ticl?
       AndroidInvalidationClientImpl ticl = TiclStateManager.restoreTicl(this, resources);
       if (ticl != null) {
         resources.getNetworkListener().onOnlineStatusChange(
-            downcall.getNetworkStatus().getIsOnline());
+            downcall.getNullableNetworkStatus().getIsOnline());
         TiclStateManager.saveTicl(this, resources.getLogger(), ticl);
       }
       return;
@@ -231,11 +221,12 @@
     }
 
     // Client creation request (meta operation).
-    if (downcall.hasCreateClient()) {
-      handleCreateClient(downcall.getCreateClient());
+    if (downcall.getNullableCreateClient() != null) {
+      handleCreateClient(downcall.getNullableCreateClient());
       return;
     }
-    throw new RuntimeException("Invalid internal downcall passed validation: " + downcall);
+    throw new RuntimeException(
+        "Invalid internal downcall passed validation: " + downcall);
   }
 
   /** Handles a {@code createClient} request. */
@@ -246,7 +237,7 @@
     // Create the requested Ticl.
     resources.getLogger().fine("Create client: creating");
     TiclStateManager.createTicl(this, resources, createClient.getClientType(),
-        createClient.getClientName().toByteArray(), createClient.getClientConfig(),
+        createClient.getClientName().getByteArray(), createClient.getClientConfig(),
         createClient.getSkipStartForTest());
   }
 
@@ -288,15 +279,16 @@
         PersistentTiclState state = PersistenceUtils.deserializeState(
             resources.getLogger(), stateBytes, digestFn);
         if (state == null) {
-          resources.getLogger().warning("Ignoring invalid Ticl state: %s", stateBytes);
+          resources.getLogger().warning("Ignoring invalid Ticl state: %s",
+              Bytes.toLazyCompactString(stateBytes));
           return;
         }
-        PersistentTiclState newState = PersistentTiclState.newBuilder(state)
-            .setLastMessageSendTimeMs(0)
-            .build();
+        PersistentTiclState.Builder stateBuilder = state.toBuilder();
+        stateBuilder.lastMessageSendTimeMs = 0L;
+        state = stateBuilder.build();
 
         // Serialize the new state and write it to storage.
-        byte[] newClientState = PersistenceUtils.serializeState(newState, digestFn);
+        byte[] newClientState = PersistenceUtils.serializeState(state, digestFn);
         resources.getStorage().writeKey(InvalidationClientCore.CLIENT_TOKEN_KEY, newClientState,
             new Callback<Status>() {
               @Override
@@ -324,13 +316,13 @@
     if (backgroundServiceClass != null) {
       try {
         ServerToClientMessage s2cMessage = ServerToClientMessage.parseFrom(message);
-        if (s2cMessage.hasInvalidationMessage()) {
-          Intent intent =
-              ProtocolIntents.newBackgroundInvalidationIntent(s2cMessage.getInvalidationMessage());
+        if (s2cMessage.getNullableInvalidationMessage() != null) {
+          Intent intent = ProtocolIntents.newBackgroundInvalidationIntent(
+              s2cMessage.getNullableInvalidationMessage());
           intent.setClassName(getApplicationContext(), backgroundServiceClass);
           startService(intent);
         }
-      } catch (InvalidProtocolBufferException exception) {
+      } catch (ValidationException exception) {
         resources.getLogger().info("Failed to parse message: %s", exception.getMessage());
       }
     }
@@ -338,20 +330,16 @@
 
   /** Handles a request to call a particular recurring task on the Ticl. */
   private void handleSchedulerEvent(byte[] schedulerEventBytes) {
-    // Parse the request.
+    // Parse and validate the request.
     final AndroidSchedulerEvent event;
     try {
       event = AndroidSchedulerEvent.parseFrom(schedulerEventBytes);
-    } catch (InvalidProtocolBufferException exception) {
+    } catch (ValidationException exception) {
       resources.getLogger().warning("Failed parsing SchedulerEvent from %s: %s",
-          schedulerEventBytes, exception.getMessage());
+          Bytes.toLazyCompactString(schedulerEventBytes), exception.getMessage());
       return;
     }
-    // Validate the request.
-    if (!validator.isSchedulerEventValid(event)) {
-      resources.getLogger().warning("Ignoring invalid scheduler event: %s", event);
-      return;
-    }
+
     resources.getLogger().fine("Handle scheduler event: %s", event);
 
     // Restore the appropriate Ticl.
diff --git a/java/com/google/ipc/invalidation/ticl/android2/TiclStateManager.java b/java/com/google/ipc/invalidation/ticl/android2/TiclStateManager.java
index d0ef952..f0ec484 100644
--- a/java/com/google/ipc/invalidation/ticl/android2/TiclStateManager.java
+++ b/java/com/google/ipc/invalidation/ticl/android2/TiclStateManager.java
@@ -20,14 +20,14 @@
 import com.google.ipc.invalidation.common.ObjectIdDigestUtils.Sha1DigestFunction;
 import com.google.ipc.invalidation.external.client.SystemResources;
 import com.google.ipc.invalidation.external.client.SystemResources.Logger;
-import com.google.protobuf.ByteString;
-import com.google.protobuf.InvalidProtocolBufferException;
-import com.google.protos.ipc.invalidation.AndroidService.AndroidTiclState;
-import com.google.protos.ipc.invalidation.AndroidService.AndroidTiclState.Metadata;
-import com.google.protos.ipc.invalidation.AndroidService.AndroidTiclStateWithDigest;
-import com.google.protos.ipc.invalidation.ClientProtocol.ApplicationClientIdP;
-import com.google.protos.ipc.invalidation.ClientProtocol.ClientConfigP;
-import com.google.protos.ipc.invalidation.JavaClient.InvalidationClientState;
+import com.google.ipc.invalidation.ticl.proto.AndroidService.AndroidTiclState;
+import com.google.ipc.invalidation.ticl.proto.AndroidService.AndroidTiclState.Metadata;
+import com.google.ipc.invalidation.ticl.proto.AndroidService.AndroidTiclStateWithDigest;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.ApplicationClientIdP;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.ClientConfigP;
+import com.google.ipc.invalidation.util.Bytes;
+import com.google.ipc.invalidation.util.ProtoWrapper.ValidationException;
+import com.google.ipc.invalidation.util.TypedUtil;
 
 import android.content.Context;
 
@@ -115,9 +115,6 @@
 
       // Create a protobuf with the Ticl state and a digest over it.
       AndroidTiclStateWithDigest digestedState = createDigestedState(ticl);
-      AndroidIntentProtocolValidator validator = new AndroidIntentProtocolValidator(logger);
-      Preconditions.checkState(validator.isTiclStateValid(digestedState),
-          "Produced invalid digested state: %s", digestedState);
 
       // Write the protobuf to storage.
       outputStream = openStateFileForWriting(context);
@@ -157,25 +154,18 @@
         byte[] fileData = new byte[(int) fileSizeBytes];
         input.readFully(fileData);
         AndroidTiclStateWithDigest androidState = AndroidTiclStateWithDigest.parseFrom(fileData);
-        AndroidIntentProtocolValidator validator = new AndroidIntentProtocolValidator(logger);
 
-        // Check the structure of the message (required fields set).
-        if (!validator.isTiclStateValid(androidState)) {
-          logger.warning("Read AndroidTiclStateWithDigest with invalid structure: %s",
-              androidState);
-          return null;
-        }
         // Validate the digest in the method.
         if (isDigestValid(androidState, logger)) {
-          InvalidationClientState state = androidState.getState().getTiclState();
-          return androidState.getState();
+          return Preconditions.checkNotNull(androidState.getState(),
+              "validator ensures that state is set");
         } else {
           logger.warning("Android Ticl state failed digest check: %s", androidState);
         }
       }
     } catch (FileNotFoundException exception) {
       logger.info("Ticl state file does not exist: %s", TICL_STATE_FILENAME);
-    } catch (InvalidProtocolBufferException exception) {
+    } catch (ValidationException exception) {
       logger.warning("Could not read Ticl state: %s", exception);
     } catch (IOException exception) {
       logger.warning("Could not read Ticl state: %s", exception);
@@ -199,21 +189,13 @@
       AndroidInvalidationClientImpl ticl) {
     Sha1DigestFunction digester = new Sha1DigestFunction();
     ApplicationClientIdP ticlAppId = ticl.getApplicationClientIdP();
-    Metadata metaData = Metadata.newBuilder()
-         .setClientConfig(ticl.getConfig())
-         .setClientName(ticlAppId.getClientName())
-         .setClientType(ticlAppId.getClientType())
-         .setTiclId(ticl.getSchedulingId())
-         .build();
-    AndroidTiclState state = AndroidTiclState.newBuilder()
-        .setMetadata(metaData)
-        .setTiclState(ticl.marshal())
-        .setVersion(ProtocolIntents.ANDROID_PROTOCOL_VERSION_VALUE).build();
+    Metadata metadata = Metadata.create(ticlAppId.getClientType(), ticlAppId.getClientName(),
+        ticl.getSchedulingId(), ticl.getConfig());
+    AndroidTiclState state = AndroidTiclState.create(ProtocolIntents.ANDROID_PROTOCOL_VERSION_VALUE,
+        ticl.marshal(), metadata);
     digester.update(state.toByteArray());
-    AndroidTiclStateWithDigest verifiedState = AndroidTiclStateWithDigest.newBuilder()
-        .setState(state)
-        .setDigest(ByteString.copyFrom(digester.getDigest()))
-        .build();
+    AndroidTiclStateWithDigest verifiedState =
+        AndroidTiclStateWithDigest.create(state, new Bytes(digester.getDigest()));
     return verifiedState;
   }
 
@@ -221,9 +203,9 @@
   private static boolean isDigestValid(AndroidTiclStateWithDigest state, Logger logger) {
     Sha1DigestFunction digester = new Sha1DigestFunction();
     digester.update(state.getState().toByteArray());
-    ByteString computedDigest = ByteString.copyFrom(digester.getDigest());
-    if (!computedDigest.equals(state.getDigest())) {
-      logger.warning("Android Ticl state digest mismatch; computed %s for %s",
+    byte[] computedDigest = digester.getDigest();
+    if (!TypedUtil.<Bytes>equals(new Bytes(computedDigest), state.getDigest())) {
+      logger.warning("Android TICL state digest mismatch; computed %s for %s",
           computedDigest, state);
       return false;
     }
diff --git a/java/com/google/ipc/invalidation/ticl/android/c2dm/WakeLockManager.java b/java/com/google/ipc/invalidation/ticl/android2/WakeLockManager.java
similarity index 99%
rename from java/com/google/ipc/invalidation/ticl/android/c2dm/WakeLockManager.java
rename to java/com/google/ipc/invalidation/ticl/android2/WakeLockManager.java
index afa51ca..2748e84 100644
--- a/java/com/google/ipc/invalidation/ticl/android/c2dm/WakeLockManager.java
+++ b/java/com/google/ipc/invalidation/ticl/android2/WakeLockManager.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.google.ipc.invalidation.ticl.android.c2dm;
+package com.google.ipc.invalidation.ticl.android2;
 
 import com.google.common.base.Preconditions;
 import com.google.ipc.invalidation.external.client.SystemResources.Logger;
diff --git a/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidChannelConstants.java b/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidChannelConstants.java
index f5fe9ff..146a311 100644
--- a/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidChannelConstants.java
+++ b/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidChannelConstants.java
@@ -15,9 +15,8 @@
  */
 package com.google.ipc.invalidation.ticl.android2.channel;
 
-import com.google.ipc.invalidation.common.CommonProtos2;
-import com.google.protos.ipc.invalidation.AndroidChannel.MajorVersion;
-import com.google.protos.ipc.invalidation.ClientProtocol.Version;
+import com.google.ipc.invalidation.ticl.proto.AndroidChannel.MajorVersion;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version;
 
 /**
  * Constants used by the network channel.
@@ -120,8 +119,7 @@
   }
 
   /** The channel version expected by this channel implementation. */
-  public static final Version CHANNEL_VERSION =
-      CommonProtos2.newVersion(MajorVersion.INITIAL.getNumber(), 0);
+  public static final Version CHANNEL_VERSION = Version.create(MajorVersion.INITIAL, 0);
 
   /**
    * An extra set on an intent to the AndroidMessageSenderService to inform it that a GCM
diff --git a/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidMessageReceiverService.java b/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidMessageReceiverService.java
index e750cc2..54d0fb9 100644
--- a/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidMessageReceiverService.java
+++ b/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidMessageReceiverService.java
@@ -22,8 +22,8 @@
 import com.google.ipc.invalidation.ticl.android2.AndroidTiclManifest;
 import com.google.ipc.invalidation.ticl.android2.ProtocolIntents;
 import com.google.ipc.invalidation.ticl.android2.channel.AndroidChannelConstants.C2dmConstants;
-import com.google.protobuf.InvalidProtocolBufferException;
-import com.google.protos.ipc.invalidation.AndroidChannel.AddressedAndroidMessage;
+import com.google.ipc.invalidation.ticl.proto.AndroidChannel.AddressedAndroidMessage;
+import com.google.ipc.invalidation.util.ProtoWrapper.ValidationException;
 
 import android.content.Context;
 import android.content.Intent;
@@ -73,7 +73,7 @@
             ProtocolIntents.InternalDowncalls.newServerMessageIntent(addrMessage.getMessage());
         msgIntent.setClassName(this, serviceClass);
         startService(msgIntent);
-      } catch (InvalidProtocolBufferException exception) {
+      } catch (ValidationException exception) {
         logger.warning("Failed parsing inbound message: %s", exception);
       }
     } else {
@@ -125,7 +125,7 @@
     GCMRegistrar.checkDevice(context);
     GCMRegistrar.checkManifest(context);
     String regId = GCMRegistrar.getRegistrationId(context);
-    if (regId.equals("")) {
+    if (regId.isEmpty()) {
       logger.info("Not registered with GCM; registering");
       GCMRegistrar.register(context, senderId);
     } else {
diff --git a/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidMessageSenderService.java b/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidMessageSenderService.java
index ad3c81c..ddffb08 100644
--- a/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidMessageSenderService.java
+++ b/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidMessageSenderService.java
@@ -18,16 +18,15 @@
 import com.google.android.gcm.GCMRegistrar;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Strings;
-import com.google.ipc.invalidation.common.CommonProtos2;
 import com.google.ipc.invalidation.external.client.SystemResources.Logger;
 import com.google.ipc.invalidation.external.client.android.service.AndroidLogger;
-import com.google.ipc.invalidation.ticl.android2.AndroidIntentProtocolValidator;
 import com.google.ipc.invalidation.ticl.android2.ProtocolIntents;
 import com.google.ipc.invalidation.ticl.android2.channel.AndroidChannelConstants.AuthTokenConstants;
 import com.google.ipc.invalidation.ticl.android2.channel.AndroidChannelConstants.HttpConstants;
-import com.google.protobuf.InvalidProtocolBufferException;
-import com.google.protos.ipc.invalidation.AndroidService.AndroidNetworkSendRequest;
-import com.google.protos.ipc.invalidation.ChannelCommon.NetworkEndpointId;
+import com.google.ipc.invalidation.ticl.proto.AndroidService.AndroidNetworkSendRequest;
+import com.google.ipc.invalidation.ticl.proto.ChannelCommon.NetworkEndpointId;
+import com.google.ipc.invalidation.ticl.proto.CommonProtos;
+import com.google.ipc.invalidation.util.ProtoWrapper.ValidationException;
 
 import android.app.IntentService;
 import android.app.PendingIntent;
@@ -75,9 +74,6 @@
 
   private final Logger logger = AndroidLogger.forTag("MsgSenderSvc");
 
-  private final AndroidIntentProtocolValidator validator =
-      new AndroidIntentProtocolValidator(logger);
-
   /** The last message sent, for tests. */
   public static byte[] lastTiclMessageForTest = null;
 
@@ -125,18 +121,14 @@
     final AndroidNetworkSendRequest sendRequest;
     try {
        sendRequest = AndroidNetworkSendRequest.parseFrom(sendRequestBytes);
-    } catch (InvalidProtocolBufferException exception) {
-      logger.warning("Failed parsing AndroidNetworkSendRequest from %s: %s",
+    } catch (ValidationException exception) {
+      logger.warning("Invalid AndroidNetworkSendRequest from %s: %s",
           sendRequestBytes, exception);
       return;
     }
-    if (!validator.isNetworkSendRequestValid(sendRequest)) {
-      logger.warning("Ignoring invalid send request: %s", sendRequest);
-      return;
-    }
 
     // Request an auth token from the application to use when sending the message.
-    byte[] message = sendRequest.getMessage().toByteArray();
+    byte[] message = sendRequest.getMessage().getByteArray();
     requestAuthTokenForMessage(message, null);
   }
 
@@ -393,8 +385,8 @@
           registrationId);
       return null;
     }
-    return CommonProtos2.newAndroidEndpointId(registrationId,
-        NO_CLIENT_KEY, context.getPackageName(), AndroidChannelConstants.CHANNEL_VERSION);
+    return CommonProtos.newAndroidEndpointId(registrationId, NO_CLIENT_KEY,
+        context.getPackageName(), AndroidChannelConstants.CHANNEL_VERSION);
   }
 
   /** Sets the channel url to {@code url}, for tests. */
diff --git a/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidNetworkChannel.java b/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidNetworkChannel.java
index 7a7d527..f1f9138 100644
--- a/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidNetworkChannel.java
+++ b/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidNetworkChannel.java
@@ -20,7 +20,7 @@
 import com.google.ipc.invalidation.ticl.TestableNetworkChannel;
 import com.google.ipc.invalidation.ticl.android2.ProtocolIntents;
 import com.google.ipc.invalidation.ticl.android2.ResourcesFactory.AndroidResources;
-import com.google.protos.ipc.invalidation.ChannelCommon.NetworkEndpointId;
+import com.google.ipc.invalidation.ticl.proto.ChannelCommon.NetworkEndpointId;
 
 import android.content.Context;
 import android.content.Intent;
diff --git a/java/com/google/ipc/invalidation/ticl/proto/AndroidChannel.java b/java/com/google/ipc/invalidation/ticl/proto/AndroidChannel.java
new file mode 100644
index 0000000..a922f0d
--- /dev/null
+++ b/java/com/google/ipc/invalidation/ticl/proto/AndroidChannel.java
@@ -0,0 +1,354 @@
+/*
+ * 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.
+ */
+// Generated by j/c/g/ipc/invalidation/common/proto_wrapper_generator
+package com.google.ipc.invalidation.ticl.proto;
+
+import com.google.ipc.invalidation.util.Bytes;
+import com.google.ipc.invalidation.util.ProtoWrapper;
+import com.google.ipc.invalidation.util.ProtoWrapper.ValidationException;
+import com.google.ipc.invalidation.util.TextBuilder;
+import com.google.protobuf.nano.MessageNano;
+import com.google.protobuf.nano.InvalidProtocolBufferNanoException;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+
+public interface AndroidChannel {
+
+  public static final class AndroidEndpointId extends ProtoWrapper {
+    public static AndroidEndpointId create(String c2DmRegistrationId,
+        String clientKey,
+        String senderId,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version channelVersion,
+        String packageName) {
+      return new AndroidEndpointId(c2DmRegistrationId, clientKey, senderId, channelVersion, packageName);
+    }
+
+    public static final AndroidEndpointId DEFAULT_INSTANCE = new AndroidEndpointId(null, null, null, null, null);
+
+    private final long __hazzerBits;
+    private final String c2DmRegistrationId;
+    private final String clientKey;
+    private final String senderId;
+    private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version channelVersion;
+    private final String packageName;
+
+    private AndroidEndpointId(String c2DmRegistrationId,
+        String clientKey,
+        String senderId,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version channelVersion,
+        String packageName) {
+      int hazzerBits = 0;
+      if (c2DmRegistrationId != null) {
+        hazzerBits |= 0x1;
+        this.c2DmRegistrationId = c2DmRegistrationId;
+      } else {
+        this.c2DmRegistrationId = "";
+      }
+      if (clientKey != null) {
+        hazzerBits |= 0x2;
+        this.clientKey = clientKey;
+      } else {
+        this.clientKey = "";
+      }
+      if (senderId != null) {
+        hazzerBits |= 0x4;
+        this.senderId = senderId;
+      } else {
+        this.senderId = "";
+      }
+      this.channelVersion = channelVersion;
+      if (packageName != null) {
+        hazzerBits |= 0x8;
+        this.packageName = packageName;
+      } else {
+        this.packageName = "";
+      }
+      this.__hazzerBits = hazzerBits;
+    }
+
+    public String getC2DmRegistrationId() { return c2DmRegistrationId; }
+    public boolean hasC2DmRegistrationId() { return (0x1 & __hazzerBits) != 0; }
+
+    public String getClientKey() { return clientKey; }
+    public boolean hasClientKey() { return (0x2 & __hazzerBits) != 0; }
+
+    public String getSenderId() { return senderId; }
+    public boolean hasSenderId() { return (0x4 & __hazzerBits) != 0; }
+
+    public com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version getNullableChannelVersion() { return channelVersion; }
+
+    public String getPackageName() { return packageName; }
+    public boolean hasPackageName() { return (0x8 & __hazzerBits) != 0; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof AndroidEndpointId)) { return false; }
+      AndroidEndpointId other = (AndroidEndpointId) obj;
+      return __hazzerBits == other.__hazzerBits
+          && (!hasC2DmRegistrationId() || equals(c2DmRegistrationId, other.c2DmRegistrationId))
+          && (!hasClientKey() || equals(clientKey, other.clientKey))
+          && (!hasSenderId() || equals(senderId, other.senderId))
+          && equals(channelVersion, other.channelVersion)
+          && (!hasPackageName() || equals(packageName, other.packageName));
+    }
+
+    @Override protected int computeHashCode() {
+      int result = hash(__hazzerBits);
+      if (hasC2DmRegistrationId()) {
+        result = result * 31 + c2DmRegistrationId.hashCode();
+      }
+      if (hasClientKey()) {
+        result = result * 31 + clientKey.hashCode();
+      }
+      if (hasSenderId()) {
+        result = result * 31 + senderId.hashCode();
+      }
+      if (channelVersion != null) {
+        result = result * 31 + channelVersion.hashCode();
+      }
+      if (hasPackageName()) {
+        result = result * 31 + packageName.hashCode();
+      }
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<AndroidEndpointId:");
+      if (hasC2DmRegistrationId()) {
+        builder.append(" c2dm_registration_id=").append(c2DmRegistrationId);
+      }
+      if (hasClientKey()) {
+        builder.append(" client_key=").append(clientKey);
+      }
+      if (hasSenderId()) {
+        builder.append(" sender_id=").append(senderId);
+      }
+      if (channelVersion != null) {
+        builder.append(" channel_version=").append(channelVersion);
+      }
+      if (hasPackageName()) {
+        builder.append(" package_name=").append(packageName);
+      }
+      builder.append('>');
+    }
+
+    public static AndroidEndpointId parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoAndroidChannel.AndroidEndpointId(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static AndroidEndpointId fromMessageNano(com.google.protos.ipc.invalidation.NanoAndroidChannel.AndroidEndpointId message) {
+      if (message == null) { return null; }
+      return new AndroidEndpointId(message.c2DmRegistrationId,
+          message.clientKey,
+          message.senderId,
+          com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version.fromMessageNano(message.channelVersion),
+          message.packageName);
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoAndroidChannel.AndroidEndpointId toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoAndroidChannel.AndroidEndpointId msg = new com.google.protos.ipc.invalidation.NanoAndroidChannel.AndroidEndpointId();
+      msg.c2DmRegistrationId = hasC2DmRegistrationId() ? c2DmRegistrationId : null;
+      msg.clientKey = hasClientKey() ? clientKey : null;
+      msg.senderId = hasSenderId() ? senderId : null;
+      msg.channelVersion = this.channelVersion != null ? channelVersion.toMessageNano() : null;
+      msg.packageName = hasPackageName() ? packageName : null;
+      return msg;
+    }
+  }
+
+  public static final class AddressedAndroidMessage extends ProtoWrapper {
+    public static AddressedAndroidMessage create(String clientKey,
+        Bytes message) {
+      return new AddressedAndroidMessage(clientKey, message);
+    }
+
+    public static final AddressedAndroidMessage DEFAULT_INSTANCE = new AddressedAndroidMessage(null, null);
+
+    private final long __hazzerBits;
+    private final String clientKey;
+    private final Bytes message;
+
+    private AddressedAndroidMessage(String clientKey,
+        Bytes message) {
+      int hazzerBits = 0;
+      if (clientKey != null) {
+        hazzerBits |= 0x1;
+        this.clientKey = clientKey;
+      } else {
+        this.clientKey = "";
+      }
+      if (message != null) {
+        hazzerBits |= 0x2;
+        this.message = message;
+      } else {
+        this.message = Bytes.EMPTY_BYTES;
+      }
+      this.__hazzerBits = hazzerBits;
+    }
+
+    public String getClientKey() { return clientKey; }
+    public boolean hasClientKey() { return (0x1 & __hazzerBits) != 0; }
+
+    public Bytes getMessage() { return message; }
+    public boolean hasMessage() { return (0x2 & __hazzerBits) != 0; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof AddressedAndroidMessage)) { return false; }
+      AddressedAndroidMessage other = (AddressedAndroidMessage) obj;
+      return __hazzerBits == other.__hazzerBits
+          && (!hasClientKey() || equals(clientKey, other.clientKey))
+          && (!hasMessage() || equals(message, other.message));
+    }
+
+    @Override protected int computeHashCode() {
+      int result = hash(__hazzerBits);
+      if (hasClientKey()) {
+        result = result * 31 + clientKey.hashCode();
+      }
+      if (hasMessage()) {
+        result = result * 31 + message.hashCode();
+      }
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<AddressedAndroidMessage:");
+      if (hasClientKey()) {
+        builder.append(" client_key=").append(clientKey);
+      }
+      if (hasMessage()) {
+        builder.append(" message=").append(message);
+      }
+      builder.append('>');
+    }
+
+    public static AddressedAndroidMessage parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoAndroidChannel.AddressedAndroidMessage(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static AddressedAndroidMessage fromMessageNano(com.google.protos.ipc.invalidation.NanoAndroidChannel.AddressedAndroidMessage message) {
+      if (message == null) { return null; }
+      return new AddressedAndroidMessage(message.clientKey,
+          Bytes.fromByteArray(message.message));
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoAndroidChannel.AddressedAndroidMessage toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoAndroidChannel.AddressedAndroidMessage msg = new com.google.protos.ipc.invalidation.NanoAndroidChannel.AddressedAndroidMessage();
+      msg.clientKey = hasClientKey() ? clientKey : null;
+      msg.message = hasMessage() ? message.getByteArray() : null;
+      return msg;
+    }
+  }
+
+  public static final class AddressedAndroidMessageBatch extends ProtoWrapper {
+    public static AddressedAndroidMessageBatch create(Collection<com.google.ipc.invalidation.ticl.proto.AndroidChannel.AddressedAndroidMessage> addressedMessage) {
+      return new AddressedAndroidMessageBatch(addressedMessage);
+    }
+
+    public static final AddressedAndroidMessageBatch DEFAULT_INSTANCE = new AddressedAndroidMessageBatch(null);
+
+    private final List<com.google.ipc.invalidation.ticl.proto.AndroidChannel.AddressedAndroidMessage> addressedMessage;
+
+    private AddressedAndroidMessageBatch(Collection<com.google.ipc.invalidation.ticl.proto.AndroidChannel.AddressedAndroidMessage> addressedMessage) {
+      this.addressedMessage = optional("addressed_message", addressedMessage);
+    }
+
+    public List<com.google.ipc.invalidation.ticl.proto.AndroidChannel.AddressedAndroidMessage> getAddressedMessage() { return addressedMessage; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof AddressedAndroidMessageBatch)) { return false; }
+      AddressedAndroidMessageBatch other = (AddressedAndroidMessageBatch) obj;
+      return equals(addressedMessage, other.addressedMessage);
+    }
+
+    @Override protected int computeHashCode() {
+      int result = 1;
+      result = result * 31 + addressedMessage.hashCode();
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<AddressedAndroidMessageBatch:");
+      builder.append(" addressed_message=[").append(addressedMessage).append(']');
+      builder.append('>');
+    }
+
+    public static AddressedAndroidMessageBatch parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoAndroidChannel.AddressedAndroidMessageBatch(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static AddressedAndroidMessageBatch fromMessageNano(com.google.protos.ipc.invalidation.NanoAndroidChannel.AddressedAndroidMessageBatch message) {
+      if (message == null) { return null; }
+      List<com.google.ipc.invalidation.ticl.proto.AndroidChannel.AddressedAndroidMessage> addressedMessage = new ArrayList<com.google.ipc.invalidation.ticl.proto.AndroidChannel.AddressedAndroidMessage>(message.addressedMessage.length);
+      for (int i = 0; i < message.addressedMessage.length; i++) {
+        addressedMessage.add(com.google.ipc.invalidation.ticl.proto.AndroidChannel.AddressedAndroidMessage.fromMessageNano(message.addressedMessage[i]));
+      }
+      return new AddressedAndroidMessageBatch(addressedMessage);
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoAndroidChannel.AddressedAndroidMessageBatch toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoAndroidChannel.AddressedAndroidMessageBatch msg = new com.google.protos.ipc.invalidation.NanoAndroidChannel.AddressedAndroidMessageBatch();
+      msg.addressedMessage = new com.google.protos.ipc.invalidation.NanoAndroidChannel.AddressedAndroidMessage[addressedMessage.size()];
+      for (int i = 0; i < msg.addressedMessage.length; i++) {
+        msg.addressedMessage[i] = addressedMessage.get(i).toMessageNano();
+      }
+      return msg;
+    }
+  }
+  public interface MajorVersion {
+    public static final int INITIAL = 0;
+    public static final int BATCH = 1;
+    public static final int DEFAULT = 0;
+    public static final int MIN_SUPPORTED = 0;
+    public static final int MAX_SUPPORTED = 1;
+  }
+
+}
diff --git a/java/com/google/ipc/invalidation/ticl/proto/AndroidListenerProtocol.java b/java/com/google/ipc/invalidation/ticl/proto/AndroidListenerProtocol.java
new file mode 100644
index 0000000..18443a1
--- /dev/null
+++ b/java/com/google/ipc/invalidation/ticl/proto/AndroidListenerProtocol.java
@@ -0,0 +1,501 @@
+/*
+ * 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.
+ */
+// Generated by j/c/g/ipc/invalidation/common/proto_wrapper_generator
+package com.google.ipc.invalidation.ticl.proto;
+
+import com.google.ipc.invalidation.util.Bytes;
+import com.google.ipc.invalidation.util.ProtoWrapper;
+import com.google.ipc.invalidation.util.ProtoWrapper.ValidationException;
+import com.google.ipc.invalidation.util.TextBuilder;
+import com.google.protobuf.nano.MessageNano;
+import com.google.protobuf.nano.InvalidProtocolBufferNanoException;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+
+public interface AndroidListenerProtocol {
+
+  public static final class AndroidListenerState extends ProtoWrapper {
+    public static final class RetryRegistrationState extends ProtoWrapper {
+      public static RetryRegistrationState create(com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP objectId,
+          com.google.ipc.invalidation.ticl.proto.Client.ExponentialBackoffState exponentialBackoffState) {
+        return new RetryRegistrationState(objectId, exponentialBackoffState);
+      }
+
+      public static final RetryRegistrationState DEFAULT_INSTANCE = new RetryRegistrationState(null, null);
+
+      private final long __hazzerBits;
+      private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP objectId;
+      private final com.google.ipc.invalidation.ticl.proto.Client.ExponentialBackoffState exponentialBackoffState;
+
+      private RetryRegistrationState(com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP objectId,
+          com.google.ipc.invalidation.ticl.proto.Client.ExponentialBackoffState exponentialBackoffState) {
+        int hazzerBits = 0;
+        this.objectId = objectId;
+        if (exponentialBackoffState != null) {
+          hazzerBits |= 0x1;
+          this.exponentialBackoffState = exponentialBackoffState;
+        } else {
+          this.exponentialBackoffState = com.google.ipc.invalidation.ticl.proto.Client.ExponentialBackoffState.DEFAULT_INSTANCE;
+        }
+        this.__hazzerBits = hazzerBits;
+      }
+
+      public com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP getNullableObjectId() { return objectId; }
+
+      public com.google.ipc.invalidation.ticl.proto.Client.ExponentialBackoffState getExponentialBackoffState() { return exponentialBackoffState; }
+      public boolean hasExponentialBackoffState() { return (0x1 & __hazzerBits) != 0; }
+
+      @Override public final boolean equals(Object obj) {
+        if (this == obj) { return true; }
+        if (!(obj instanceof RetryRegistrationState)) { return false; }
+        RetryRegistrationState other = (RetryRegistrationState) obj;
+        return __hazzerBits == other.__hazzerBits
+            && equals(objectId, other.objectId)
+            && (!hasExponentialBackoffState() || equals(exponentialBackoffState, other.exponentialBackoffState));
+      }
+
+      @Override protected int computeHashCode() {
+        int result = hash(__hazzerBits);
+        if (objectId != null) {
+          result = result * 31 + objectId.hashCode();
+        }
+        if (hasExponentialBackoffState()) {
+          result = result * 31 + exponentialBackoffState.hashCode();
+        }
+        return result;
+      }
+
+      @Override public void toCompactString(TextBuilder builder) {
+        builder.append("<RetryRegistrationState:");
+        if (objectId != null) {
+          builder.append(" object_id=").append(objectId);
+        }
+        if (hasExponentialBackoffState()) {
+          builder.append(" exponential_backoff_state=").append(exponentialBackoffState);
+        }
+        builder.append('>');
+      }
+
+      public static RetryRegistrationState parseFrom(byte[] data) throws ValidationException {
+        try {
+          return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoAndroidListenerProtocol.AndroidListenerState.RetryRegistrationState(), data));
+        } catch (InvalidProtocolBufferNanoException exception) {
+          throw new ValidationException(exception);
+        } catch (ValidationArgumentException exception) {
+          throw new ValidationException(exception.getMessage());
+        }
+      }
+
+      static RetryRegistrationState fromMessageNano(com.google.protos.ipc.invalidation.NanoAndroidListenerProtocol.AndroidListenerState.RetryRegistrationState message) {
+        if (message == null) { return null; }
+        return new RetryRegistrationState(com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP.fromMessageNano(message.objectId),
+            com.google.ipc.invalidation.ticl.proto.Client.ExponentialBackoffState.fromMessageNano(message.exponentialBackoffState));
+      }
+
+      public byte[] toByteArray() {
+        return MessageNano.toByteArray(toMessageNano());
+      }
+
+      com.google.protos.ipc.invalidation.NanoAndroidListenerProtocol.AndroidListenerState.RetryRegistrationState toMessageNano() {
+        com.google.protos.ipc.invalidation.NanoAndroidListenerProtocol.AndroidListenerState.RetryRegistrationState msg = new com.google.protos.ipc.invalidation.NanoAndroidListenerProtocol.AndroidListenerState.RetryRegistrationState();
+        msg.objectId = this.objectId != null ? objectId.toMessageNano() : null;
+        msg.exponentialBackoffState = hasExponentialBackoffState() ? exponentialBackoffState.toMessageNano() : null;
+        return msg;
+      }
+    }
+    public static AndroidListenerState create(Collection<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP> registration,
+        Collection<com.google.ipc.invalidation.ticl.proto.AndroidListenerProtocol.AndroidListenerState.RetryRegistrationState> retryRegistrationState,
+        Bytes clientId,
+        Integer requestCodeSeqNum) {
+      return new AndroidListenerState(registration, retryRegistrationState, clientId, requestCodeSeqNum);
+    }
+
+    public static final AndroidListenerState DEFAULT_INSTANCE = new AndroidListenerState(null, null, null, null);
+
+    private final long __hazzerBits;
+    private final List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP> registration;
+    private final List<com.google.ipc.invalidation.ticl.proto.AndroidListenerProtocol.AndroidListenerState.RetryRegistrationState> retryRegistrationState;
+    private final Bytes clientId;
+    private final int requestCodeSeqNum;
+
+    private AndroidListenerState(Collection<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP> registration,
+        Collection<com.google.ipc.invalidation.ticl.proto.AndroidListenerProtocol.AndroidListenerState.RetryRegistrationState> retryRegistrationState,
+        Bytes clientId,
+        Integer requestCodeSeqNum) {
+      int hazzerBits = 0;
+      this.registration = optional("registration", registration);
+      this.retryRegistrationState = optional("retry_registration_state", retryRegistrationState);
+      if (clientId != null) {
+        hazzerBits |= 0x1;
+        this.clientId = clientId;
+      } else {
+        this.clientId = Bytes.EMPTY_BYTES;
+      }
+      if (requestCodeSeqNum != null) {
+        hazzerBits |= 0x2;
+        this.requestCodeSeqNum = requestCodeSeqNum;
+      } else {
+        this.requestCodeSeqNum = 0;
+      }
+      this.__hazzerBits = hazzerBits;
+    }
+
+    public List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP> getRegistration() { return registration; }
+
+    public List<com.google.ipc.invalidation.ticl.proto.AndroidListenerProtocol.AndroidListenerState.RetryRegistrationState> getRetryRegistrationState() { return retryRegistrationState; }
+
+    public Bytes getClientId() { return clientId; }
+    public boolean hasClientId() { return (0x1 & __hazzerBits) != 0; }
+
+    public int getRequestCodeSeqNum() { return requestCodeSeqNum; }
+    public boolean hasRequestCodeSeqNum() { return (0x2 & __hazzerBits) != 0; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof AndroidListenerState)) { return false; }
+      AndroidListenerState other = (AndroidListenerState) obj;
+      return __hazzerBits == other.__hazzerBits
+          && equals(registration, other.registration)
+          && equals(retryRegistrationState, other.retryRegistrationState)
+          && (!hasClientId() || equals(clientId, other.clientId))
+          && (!hasRequestCodeSeqNum() || requestCodeSeqNum == other.requestCodeSeqNum);
+    }
+
+    @Override protected int computeHashCode() {
+      int result = hash(__hazzerBits);
+      result = result * 31 + registration.hashCode();
+      result = result * 31 + retryRegistrationState.hashCode();
+      if (hasClientId()) {
+        result = result * 31 + clientId.hashCode();
+      }
+      if (hasRequestCodeSeqNum()) {
+        result = result * 31 + hash(requestCodeSeqNum);
+      }
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<AndroidListenerState:");
+      builder.append(" registration=[").append(registration).append(']');
+      builder.append(" retry_registration_state=[").append(retryRegistrationState).append(']');
+      if (hasClientId()) {
+        builder.append(" client_id=").append(clientId);
+      }
+      if (hasRequestCodeSeqNum()) {
+        builder.append(" request_code_seq_num=").append(requestCodeSeqNum);
+      }
+      builder.append('>');
+    }
+
+    public static AndroidListenerState parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoAndroidListenerProtocol.AndroidListenerState(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static AndroidListenerState fromMessageNano(com.google.protos.ipc.invalidation.NanoAndroidListenerProtocol.AndroidListenerState message) {
+      if (message == null) { return null; }
+      List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP> registration = new ArrayList<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP>(message.registration.length);
+      for (int i = 0; i < message.registration.length; i++) {
+        registration.add(com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP.fromMessageNano(message.registration[i]));
+      }
+      List<com.google.ipc.invalidation.ticl.proto.AndroidListenerProtocol.AndroidListenerState.RetryRegistrationState> retryRegistrationState = new ArrayList<com.google.ipc.invalidation.ticl.proto.AndroidListenerProtocol.AndroidListenerState.RetryRegistrationState>(message.retryRegistrationState.length);
+      for (int i = 0; i < message.retryRegistrationState.length; i++) {
+        retryRegistrationState.add(com.google.ipc.invalidation.ticl.proto.AndroidListenerProtocol.AndroidListenerState.RetryRegistrationState.fromMessageNano(message.retryRegistrationState[i]));
+      }
+      return new AndroidListenerState(registration,
+          retryRegistrationState,
+          Bytes.fromByteArray(message.clientId),
+          message.requestCodeSeqNum);
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoAndroidListenerProtocol.AndroidListenerState toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoAndroidListenerProtocol.AndroidListenerState msg = new com.google.protos.ipc.invalidation.NanoAndroidListenerProtocol.AndroidListenerState();
+      msg.registration = new com.google.protos.ipc.invalidation.NanoClientProtocol.ObjectIdP[registration.size()];
+      for (int i = 0; i < msg.registration.length; i++) {
+        msg.registration[i] = registration.get(i).toMessageNano();
+      }
+      msg.retryRegistrationState = new com.google.protos.ipc.invalidation.NanoAndroidListenerProtocol.AndroidListenerState.RetryRegistrationState[retryRegistrationState.size()];
+      for (int i = 0; i < msg.retryRegistrationState.length; i++) {
+        msg.retryRegistrationState[i] = retryRegistrationState.get(i).toMessageNano();
+      }
+      msg.clientId = hasClientId() ? clientId.getByteArray() : null;
+      msg.requestCodeSeqNum = hasRequestCodeSeqNum() ? requestCodeSeqNum : null;
+      return msg;
+    }
+  }
+
+  public static final class RegistrationCommand extends ProtoWrapper {
+    public static RegistrationCommand create(Boolean isRegister,
+        Collection<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP> objectId,
+        Bytes clientId,
+        Boolean isDelayed) {
+      return new RegistrationCommand(isRegister, objectId, clientId, isDelayed);
+    }
+
+    public static final RegistrationCommand DEFAULT_INSTANCE = new RegistrationCommand(null, null, null, null);
+
+    private final long __hazzerBits;
+    private final boolean isRegister;
+    private final List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP> objectId;
+    private final Bytes clientId;
+    private final boolean isDelayed;
+
+    private RegistrationCommand(Boolean isRegister,
+        Collection<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP> objectId,
+        Bytes clientId,
+        Boolean isDelayed) {
+      int hazzerBits = 0;
+      if (isRegister != null) {
+        hazzerBits |= 0x1;
+        this.isRegister = isRegister;
+      } else {
+        this.isRegister = false;
+      }
+      this.objectId = optional("object_id", objectId);
+      if (clientId != null) {
+        hazzerBits |= 0x2;
+        this.clientId = clientId;
+      } else {
+        this.clientId = Bytes.EMPTY_BYTES;
+      }
+      if (isDelayed != null) {
+        hazzerBits |= 0x4;
+        this.isDelayed = isDelayed;
+      } else {
+        this.isDelayed = false;
+      }
+      this.__hazzerBits = hazzerBits;
+    }
+
+    public boolean getIsRegister() { return isRegister; }
+    public boolean hasIsRegister() { return (0x1 & __hazzerBits) != 0; }
+
+    public List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP> getObjectId() { return objectId; }
+
+    public Bytes getClientId() { return clientId; }
+    public boolean hasClientId() { return (0x2 & __hazzerBits) != 0; }
+
+    public boolean getIsDelayed() { return isDelayed; }
+    public boolean hasIsDelayed() { return (0x4 & __hazzerBits) != 0; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof RegistrationCommand)) { return false; }
+      RegistrationCommand other = (RegistrationCommand) obj;
+      return __hazzerBits == other.__hazzerBits
+          && (!hasIsRegister() || isRegister == other.isRegister)
+          && equals(objectId, other.objectId)
+          && (!hasClientId() || equals(clientId, other.clientId))
+          && (!hasIsDelayed() || isDelayed == other.isDelayed);
+    }
+
+    @Override protected int computeHashCode() {
+      int result = hash(__hazzerBits);
+      if (hasIsRegister()) {
+        result = result * 31 + hash(isRegister);
+      }
+      result = result * 31 + objectId.hashCode();
+      if (hasClientId()) {
+        result = result * 31 + clientId.hashCode();
+      }
+      if (hasIsDelayed()) {
+        result = result * 31 + hash(isDelayed);
+      }
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<RegistrationCommand:");
+      if (hasIsRegister()) {
+        builder.append(" is_register=").append(isRegister);
+      }
+      builder.append(" object_id=[").append(objectId).append(']');
+      if (hasClientId()) {
+        builder.append(" client_id=").append(clientId);
+      }
+      if (hasIsDelayed()) {
+        builder.append(" is_delayed=").append(isDelayed);
+      }
+      builder.append('>');
+    }
+
+    public static RegistrationCommand parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoAndroidListenerProtocol.RegistrationCommand(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static RegistrationCommand fromMessageNano(com.google.protos.ipc.invalidation.NanoAndroidListenerProtocol.RegistrationCommand message) {
+      if (message == null) { return null; }
+      List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP> objectId = new ArrayList<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP>(message.objectId.length);
+      for (int i = 0; i < message.objectId.length; i++) {
+        objectId.add(com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP.fromMessageNano(message.objectId[i]));
+      }
+      return new RegistrationCommand(message.isRegister,
+          objectId,
+          Bytes.fromByteArray(message.clientId),
+          message.isDelayed);
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoAndroidListenerProtocol.RegistrationCommand toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoAndroidListenerProtocol.RegistrationCommand msg = new com.google.protos.ipc.invalidation.NanoAndroidListenerProtocol.RegistrationCommand();
+      msg.isRegister = hasIsRegister() ? isRegister : null;
+      msg.objectId = new com.google.protos.ipc.invalidation.NanoClientProtocol.ObjectIdP[objectId.size()];
+      for (int i = 0; i < msg.objectId.length; i++) {
+        msg.objectId[i] = objectId.get(i).toMessageNano();
+      }
+      msg.clientId = hasClientId() ? clientId.getByteArray() : null;
+      msg.isDelayed = hasIsDelayed() ? isDelayed : null;
+      return msg;
+    }
+  }
+
+  public static final class StartCommand extends ProtoWrapper {
+    public static StartCommand create(Integer clientType,
+        Bytes clientName,
+        Boolean allowSuppression) {
+      return new StartCommand(clientType, clientName, allowSuppression);
+    }
+
+    public static final StartCommand DEFAULT_INSTANCE = new StartCommand(null, null, null);
+
+    private final long __hazzerBits;
+    private final int clientType;
+    private final Bytes clientName;
+    private final boolean allowSuppression;
+
+    private StartCommand(Integer clientType,
+        Bytes clientName,
+        Boolean allowSuppression) {
+      int hazzerBits = 0;
+      if (clientType != null) {
+        hazzerBits |= 0x1;
+        this.clientType = clientType;
+      } else {
+        this.clientType = 0;
+      }
+      if (clientName != null) {
+        hazzerBits |= 0x2;
+        this.clientName = clientName;
+      } else {
+        this.clientName = Bytes.EMPTY_BYTES;
+      }
+      if (allowSuppression != null) {
+        hazzerBits |= 0x4;
+        this.allowSuppression = allowSuppression;
+      } else {
+        this.allowSuppression = false;
+      }
+      this.__hazzerBits = hazzerBits;
+    }
+
+    public int getClientType() { return clientType; }
+    public boolean hasClientType() { return (0x1 & __hazzerBits) != 0; }
+
+    public Bytes getClientName() { return clientName; }
+    public boolean hasClientName() { return (0x2 & __hazzerBits) != 0; }
+
+    public boolean getAllowSuppression() { return allowSuppression; }
+    public boolean hasAllowSuppression() { return (0x4 & __hazzerBits) != 0; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof StartCommand)) { return false; }
+      StartCommand other = (StartCommand) obj;
+      return __hazzerBits == other.__hazzerBits
+          && (!hasClientType() || clientType == other.clientType)
+          && (!hasClientName() || equals(clientName, other.clientName))
+          && (!hasAllowSuppression() || allowSuppression == other.allowSuppression);
+    }
+
+    @Override protected int computeHashCode() {
+      int result = hash(__hazzerBits);
+      if (hasClientType()) {
+        result = result * 31 + hash(clientType);
+      }
+      if (hasClientName()) {
+        result = result * 31 + clientName.hashCode();
+      }
+      if (hasAllowSuppression()) {
+        result = result * 31 + hash(allowSuppression);
+      }
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<StartCommand:");
+      if (hasClientType()) {
+        builder.append(" client_type=").append(clientType);
+      }
+      if (hasClientName()) {
+        builder.append(" client_name=").append(clientName);
+      }
+      if (hasAllowSuppression()) {
+        builder.append(" allow_suppression=").append(allowSuppression);
+      }
+      builder.append('>');
+    }
+
+    public static StartCommand parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoAndroidListenerProtocol.StartCommand(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static StartCommand fromMessageNano(com.google.protos.ipc.invalidation.NanoAndroidListenerProtocol.StartCommand message) {
+      if (message == null) { return null; }
+      return new StartCommand(message.clientType,
+          Bytes.fromByteArray(message.clientName),
+          message.allowSuppression);
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoAndroidListenerProtocol.StartCommand toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoAndroidListenerProtocol.StartCommand msg = new com.google.protos.ipc.invalidation.NanoAndroidListenerProtocol.StartCommand();
+      msg.clientType = hasClientType() ? clientType : null;
+      msg.clientName = hasClientName() ? clientName.getByteArray() : null;
+      msg.allowSuppression = hasAllowSuppression() ? allowSuppression : null;
+      return msg;
+    }
+  }
+}
diff --git a/java/com/google/ipc/invalidation/ticl/proto/AndroidService.java b/java/com/google/ipc/invalidation/ticl/proto/AndroidService.java
new file mode 100644
index 0000000..e2d8030
--- /dev/null
+++ b/java/com/google/ipc/invalidation/ticl/proto/AndroidService.java
@@ -0,0 +1,2009 @@
+/*
+ * 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.
+ */
+// Generated by j/c/g/ipc/invalidation/common/proto_wrapper_generator
+package com.google.ipc.invalidation.ticl.proto;
+
+import com.google.ipc.invalidation.util.Bytes;
+import com.google.ipc.invalidation.util.ProtoWrapper;
+import com.google.ipc.invalidation.util.ProtoWrapper.ValidationException;
+import com.google.ipc.invalidation.util.TextBuilder;
+import com.google.protobuf.nano.MessageNano;
+import com.google.protobuf.nano.InvalidProtocolBufferNanoException;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+
+public interface AndroidService {
+
+  public static final class ClientDowncall extends ProtoWrapper {
+    public static final class StartDowncall extends ProtoWrapper {
+      public static StartDowncall create() {
+        return new StartDowncall();
+      }
+
+      public static final StartDowncall DEFAULT_INSTANCE = new StartDowncall();
+
+
+      private StartDowncall() {
+      }
+
+
+      @Override public final boolean equals(Object obj) {
+        if (this == obj) { return true; }
+        if (!(obj instanceof StartDowncall)) { return false; }
+        StartDowncall other = (StartDowncall) obj;
+        return true;
+      }
+
+      @Override protected int computeHashCode() {
+        int result = 1;
+        return result;
+      }
+
+      @Override public void toCompactString(TextBuilder builder) {
+        builder.append("<StartDowncall:");
+        builder.append('>');
+      }
+
+      public static StartDowncall parseFrom(byte[] data) throws ValidationException {
+        try {
+          return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoAndroidService.ClientDowncall.StartDowncall(), data));
+        } catch (InvalidProtocolBufferNanoException exception) {
+          throw new ValidationException(exception);
+        } catch (ValidationArgumentException exception) {
+          throw new ValidationException(exception.getMessage());
+        }
+      }
+
+      static StartDowncall fromMessageNano(com.google.protos.ipc.invalidation.NanoAndroidService.ClientDowncall.StartDowncall message) {
+        if (message == null) { return null; }
+        return new StartDowncall();
+      }
+
+      public byte[] toByteArray() {
+        return MessageNano.toByteArray(toMessageNano());
+      }
+
+      com.google.protos.ipc.invalidation.NanoAndroidService.ClientDowncall.StartDowncall toMessageNano() {
+        com.google.protos.ipc.invalidation.NanoAndroidService.ClientDowncall.StartDowncall msg = new com.google.protos.ipc.invalidation.NanoAndroidService.ClientDowncall.StartDowncall();
+        return msg;
+      }
+    }
+    public static final class StopDowncall extends ProtoWrapper {
+      public static StopDowncall create() {
+        return new StopDowncall();
+      }
+
+      public static final StopDowncall DEFAULT_INSTANCE = new StopDowncall();
+
+
+      private StopDowncall() {
+      }
+
+
+      @Override public final boolean equals(Object obj) {
+        if (this == obj) { return true; }
+        if (!(obj instanceof StopDowncall)) { return false; }
+        StopDowncall other = (StopDowncall) obj;
+        return true;
+      }
+
+      @Override protected int computeHashCode() {
+        int result = 1;
+        return result;
+      }
+
+      @Override public void toCompactString(TextBuilder builder) {
+        builder.append("<StopDowncall:");
+        builder.append('>');
+      }
+
+      public static StopDowncall parseFrom(byte[] data) throws ValidationException {
+        try {
+          return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoAndroidService.ClientDowncall.StopDowncall(), data));
+        } catch (InvalidProtocolBufferNanoException exception) {
+          throw new ValidationException(exception);
+        } catch (ValidationArgumentException exception) {
+          throw new ValidationException(exception.getMessage());
+        }
+      }
+
+      static StopDowncall fromMessageNano(com.google.protos.ipc.invalidation.NanoAndroidService.ClientDowncall.StopDowncall message) {
+        if (message == null) { return null; }
+        return new StopDowncall();
+      }
+
+      public byte[] toByteArray() {
+        return MessageNano.toByteArray(toMessageNano());
+      }
+
+      com.google.protos.ipc.invalidation.NanoAndroidService.ClientDowncall.StopDowncall toMessageNano() {
+        com.google.protos.ipc.invalidation.NanoAndroidService.ClientDowncall.StopDowncall msg = new com.google.protos.ipc.invalidation.NanoAndroidService.ClientDowncall.StopDowncall();
+        return msg;
+      }
+    }
+    public static final class AckDowncall extends ProtoWrapper {
+      public static AckDowncall create(Bytes ackHandle) {
+        return new AckDowncall(ackHandle);
+      }
+
+      private final Bytes ackHandle;
+
+      private AckDowncall(Bytes ackHandle) throws ValidationArgumentException {
+        required("ack_handle", ackHandle);
+        this.ackHandle = ackHandle;
+      }
+
+      public Bytes getAckHandle() { return ackHandle; }
+
+      @Override public final boolean equals(Object obj) {
+        if (this == obj) { return true; }
+        if (!(obj instanceof AckDowncall)) { return false; }
+        AckDowncall other = (AckDowncall) obj;
+        return equals(ackHandle, other.ackHandle);
+      }
+
+      @Override protected int computeHashCode() {
+        int result = 1;
+        result = result * 31 + ackHandle.hashCode();
+        return result;
+      }
+
+      @Override public void toCompactString(TextBuilder builder) {
+        builder.append("<AckDowncall:");
+        builder.append(" ack_handle=").append(ackHandle);
+        builder.append('>');
+      }
+
+      public static AckDowncall parseFrom(byte[] data) throws ValidationException {
+        try {
+          return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoAndroidService.ClientDowncall.AckDowncall(), data));
+        } catch (InvalidProtocolBufferNanoException exception) {
+          throw new ValidationException(exception);
+        } catch (ValidationArgumentException exception) {
+          throw new ValidationException(exception.getMessage());
+        }
+      }
+
+      static AckDowncall fromMessageNano(com.google.protos.ipc.invalidation.NanoAndroidService.ClientDowncall.AckDowncall message) {
+        if (message == null) { return null; }
+        return new AckDowncall(Bytes.fromByteArray(message.ackHandle));
+      }
+
+      public byte[] toByteArray() {
+        return MessageNano.toByteArray(toMessageNano());
+      }
+
+      com.google.protos.ipc.invalidation.NanoAndroidService.ClientDowncall.AckDowncall toMessageNano() {
+        com.google.protos.ipc.invalidation.NanoAndroidService.ClientDowncall.AckDowncall msg = new com.google.protos.ipc.invalidation.NanoAndroidService.ClientDowncall.AckDowncall();
+        msg.ackHandle = ackHandle.getByteArray();
+        return msg;
+      }
+    }
+    public static final class RegistrationDowncall extends ProtoWrapper {
+      public static RegistrationDowncall createWithRegistrations(Collection<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP> registrations) {
+        return new RegistrationDowncall(registrations, null);
+      }
+
+      public static RegistrationDowncall createWithUnregistrations(Collection<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP> unregistrations) {
+        return new RegistrationDowncall(null, unregistrations);
+      }
+
+      private final List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP> registrations;
+      private final List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP> unregistrations;
+
+      private RegistrationDowncall(Collection<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP> registrations,
+          Collection<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP> unregistrations) throws ValidationArgumentException {
+        this.registrations = optional("registrations", registrations);
+        this.unregistrations = optional("unregistrations", unregistrations);
+        String existingOneOfField = null;
+        if (!this.registrations.isEmpty()) {
+          existingOneOfField = "registrations";
+        }
+        if (!this.unregistrations.isEmpty()) {
+          if (existingOneOfField != null) {
+            oneOfViolation(existingOneOfField, "unregistrations");
+          }
+          existingOneOfField = "unregistrations";
+        }
+        if (existingOneOfField == null) { oneOfViolation(); }
+      }
+
+      public List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP> getRegistrations() { return registrations; }
+
+      public List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP> getUnregistrations() { return unregistrations; }
+
+      @Override public final boolean equals(Object obj) {
+        if (this == obj) { return true; }
+        if (!(obj instanceof RegistrationDowncall)) { return false; }
+        RegistrationDowncall other = (RegistrationDowncall) obj;
+        return equals(registrations, other.registrations)
+            && equals(unregistrations, other.unregistrations);
+      }
+
+      @Override protected int computeHashCode() {
+        int result = 1;
+        result = result * 31 + registrations.hashCode();
+        result = result * 31 + unregistrations.hashCode();
+        return result;
+      }
+
+      @Override public void toCompactString(TextBuilder builder) {
+        builder.append("<RegistrationDowncall:");
+        builder.append(" registrations=[").append(registrations).append(']');
+        builder.append(" unregistrations=[").append(unregistrations).append(']');
+        builder.append('>');
+      }
+
+      public static RegistrationDowncall parseFrom(byte[] data) throws ValidationException {
+        try {
+          return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoAndroidService.ClientDowncall.RegistrationDowncall(), data));
+        } catch (InvalidProtocolBufferNanoException exception) {
+          throw new ValidationException(exception);
+        } catch (ValidationArgumentException exception) {
+          throw new ValidationException(exception.getMessage());
+        }
+      }
+
+      static RegistrationDowncall fromMessageNano(com.google.protos.ipc.invalidation.NanoAndroidService.ClientDowncall.RegistrationDowncall message) {
+        if (message == null) { return null; }
+        List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP> registrations = new ArrayList<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP>(message.registrations.length);
+        for (int i = 0; i < message.registrations.length; i++) {
+          registrations.add(com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP.fromMessageNano(message.registrations[i]));
+        }
+        List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP> unregistrations = new ArrayList<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP>(message.unregistrations.length);
+        for (int i = 0; i < message.unregistrations.length; i++) {
+          unregistrations.add(com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP.fromMessageNano(message.unregistrations[i]));
+        }
+        return new RegistrationDowncall(registrations,
+            unregistrations);
+      }
+
+      public byte[] toByteArray() {
+        return MessageNano.toByteArray(toMessageNano());
+      }
+
+      com.google.protos.ipc.invalidation.NanoAndroidService.ClientDowncall.RegistrationDowncall toMessageNano() {
+        com.google.protos.ipc.invalidation.NanoAndroidService.ClientDowncall.RegistrationDowncall msg = new com.google.protos.ipc.invalidation.NanoAndroidService.ClientDowncall.RegistrationDowncall();
+        msg.registrations = new com.google.protos.ipc.invalidation.NanoClientProtocol.ObjectIdP[registrations.size()];
+        for (int i = 0; i < msg.registrations.length; i++) {
+          msg.registrations[i] = registrations.get(i).toMessageNano();
+        }
+        msg.unregistrations = new com.google.protos.ipc.invalidation.NanoClientProtocol.ObjectIdP[unregistrations.size()];
+        for (int i = 0; i < msg.unregistrations.length; i++) {
+          msg.unregistrations[i] = unregistrations.get(i).toMessageNano();
+        }
+        return msg;
+      }
+    }
+    public static ClientDowncall createWithStart(com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version version,
+        com.google.ipc.invalidation.ticl.proto.AndroidService.ClientDowncall.StartDowncall start) {
+      return new ClientDowncall(null, version, start, null, null, null);
+    }
+
+    public static ClientDowncall createWithSerial(long serial,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version version) {
+      return new ClientDowncall(serial, version, null, null, null, null);
+    }
+
+    public static ClientDowncall createWithAck(com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version version,
+        com.google.ipc.invalidation.ticl.proto.AndroidService.ClientDowncall.AckDowncall ack) {
+      return new ClientDowncall(null, version, null, null, ack, null);
+    }
+
+    public static ClientDowncall createWithRegistrations(com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version version,
+        com.google.ipc.invalidation.ticl.proto.AndroidService.ClientDowncall.RegistrationDowncall registrations) {
+      return new ClientDowncall(null, version, null, null, null, registrations);
+    }
+
+    public static ClientDowncall createWithStop(com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version version,
+        com.google.ipc.invalidation.ticl.proto.AndroidService.ClientDowncall.StopDowncall stop) {
+      return new ClientDowncall(null, version, null, stop, null, null);
+    }
+
+    private final long __hazzerBits;
+    private final long serial;
+    private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version version;
+    private final com.google.ipc.invalidation.ticl.proto.AndroidService.ClientDowncall.StartDowncall start;
+    private final com.google.ipc.invalidation.ticl.proto.AndroidService.ClientDowncall.StopDowncall stop;
+    private final com.google.ipc.invalidation.ticl.proto.AndroidService.ClientDowncall.AckDowncall ack;
+    private final com.google.ipc.invalidation.ticl.proto.AndroidService.ClientDowncall.RegistrationDowncall registrations;
+
+    private ClientDowncall(Long serial,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version version,
+        com.google.ipc.invalidation.ticl.proto.AndroidService.ClientDowncall.StartDowncall start,
+        com.google.ipc.invalidation.ticl.proto.AndroidService.ClientDowncall.StopDowncall stop,
+        com.google.ipc.invalidation.ticl.proto.AndroidService.ClientDowncall.AckDowncall ack,
+        com.google.ipc.invalidation.ticl.proto.AndroidService.ClientDowncall.RegistrationDowncall registrations) throws ValidationArgumentException {
+      int hazzerBits = 0;
+      if (serial != null) {
+        hazzerBits |= 0x1;
+        this.serial = serial;
+      } else {
+        this.serial = 0;
+      }
+      required("version", version);
+      this.version = version;
+      if (start != null) {
+        hazzerBits |= 0x2;
+        this.start = start;
+      } else {
+        this.start = com.google.ipc.invalidation.ticl.proto.AndroidService.ClientDowncall.StartDowncall.DEFAULT_INSTANCE;
+      }
+      if (stop != null) {
+        hazzerBits |= 0x4;
+        this.stop = stop;
+      } else {
+        this.stop = com.google.ipc.invalidation.ticl.proto.AndroidService.ClientDowncall.StopDowncall.DEFAULT_INSTANCE;
+      }
+      this.ack = ack;
+      this.registrations = registrations;
+      this.__hazzerBits = hazzerBits;
+      String existingOneOfField = null;
+      if (hasStart()) {
+        existingOneOfField = "start";
+      }
+      if (hasSerial()) {
+        if (existingOneOfField != null) {
+          oneOfViolation(existingOneOfField, "serial");
+        }
+        existingOneOfField = "serial";
+      }
+      if (this.ack != null) {
+        if (existingOneOfField != null) {
+          oneOfViolation(existingOneOfField, "ack");
+        }
+        existingOneOfField = "ack";
+      }
+      if (this.registrations != null) {
+        if (existingOneOfField != null) {
+          oneOfViolation(existingOneOfField, "registrations");
+        }
+        existingOneOfField = "registrations";
+      }
+      if (hasStop()) {
+        if (existingOneOfField != null) {
+          oneOfViolation(existingOneOfField, "stop");
+        }
+        existingOneOfField = "stop";
+      }
+      if (existingOneOfField == null) { oneOfViolation(); }
+    }
+
+    public long getSerial() { return serial; }
+    public boolean hasSerial() { return (0x1 & __hazzerBits) != 0; }
+
+    public com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version getVersion() { return version; }
+
+    public com.google.ipc.invalidation.ticl.proto.AndroidService.ClientDowncall.StartDowncall getStart() { return start; }
+    public boolean hasStart() { return (0x2 & __hazzerBits) != 0; }
+
+    public com.google.ipc.invalidation.ticl.proto.AndroidService.ClientDowncall.StopDowncall getStop() { return stop; }
+    public boolean hasStop() { return (0x4 & __hazzerBits) != 0; }
+
+    public com.google.ipc.invalidation.ticl.proto.AndroidService.ClientDowncall.AckDowncall getNullableAck() { return ack; }
+
+    public com.google.ipc.invalidation.ticl.proto.AndroidService.ClientDowncall.RegistrationDowncall getNullableRegistrations() { return registrations; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof ClientDowncall)) { return false; }
+      ClientDowncall other = (ClientDowncall) obj;
+      return __hazzerBits == other.__hazzerBits
+          && (!hasSerial() || serial == other.serial)
+          && equals(version, other.version)
+          && (!hasStart() || equals(start, other.start))
+          && (!hasStop() || equals(stop, other.stop))
+          && equals(ack, other.ack)
+          && equals(registrations, other.registrations);
+    }
+
+    @Override protected int computeHashCode() {
+      int result = hash(__hazzerBits);
+      if (hasSerial()) {
+        result = result * 31 + hash(serial);
+      }
+      result = result * 31 + version.hashCode();
+      if (hasStart()) {
+        result = result * 31 + start.hashCode();
+      }
+      if (hasStop()) {
+        result = result * 31 + stop.hashCode();
+      }
+      if (ack != null) {
+        result = result * 31 + ack.hashCode();
+      }
+      if (registrations != null) {
+        result = result * 31 + registrations.hashCode();
+      }
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<ClientDowncall:");
+      if (hasSerial()) {
+        builder.append(" serial=").append(serial);
+      }
+      builder.append(" version=").append(version);
+      if (hasStart()) {
+        builder.append(" start=").append(start);
+      }
+      if (hasStop()) {
+        builder.append(" stop=").append(stop);
+      }
+      if (ack != null) {
+        builder.append(" ack=").append(ack);
+      }
+      if (registrations != null) {
+        builder.append(" registrations=").append(registrations);
+      }
+      builder.append('>');
+    }
+
+    public static ClientDowncall parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoAndroidService.ClientDowncall(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static ClientDowncall fromMessageNano(com.google.protos.ipc.invalidation.NanoAndroidService.ClientDowncall message) {
+      if (message == null) { return null; }
+      return new ClientDowncall(message.serial,
+          com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version.fromMessageNano(message.version),
+          com.google.ipc.invalidation.ticl.proto.AndroidService.ClientDowncall.StartDowncall.fromMessageNano(message.start),
+          com.google.ipc.invalidation.ticl.proto.AndroidService.ClientDowncall.StopDowncall.fromMessageNano(message.stop),
+          com.google.ipc.invalidation.ticl.proto.AndroidService.ClientDowncall.AckDowncall.fromMessageNano(message.ack),
+          com.google.ipc.invalidation.ticl.proto.AndroidService.ClientDowncall.RegistrationDowncall.fromMessageNano(message.registrations));
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoAndroidService.ClientDowncall toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoAndroidService.ClientDowncall msg = new com.google.protos.ipc.invalidation.NanoAndroidService.ClientDowncall();
+      msg.serial = hasSerial() ? serial : null;
+      msg.version = version.toMessageNano();
+      msg.start = hasStart() ? start.toMessageNano() : null;
+      msg.stop = hasStop() ? stop.toMessageNano() : null;
+      msg.ack = this.ack != null ? ack.toMessageNano() : null;
+      msg.registrations = this.registrations != null ? registrations.toMessageNano() : null;
+      return msg;
+    }
+  }
+
+  public static final class InternalDowncall extends ProtoWrapper {
+    public static final class ServerMessage extends ProtoWrapper {
+      public static ServerMessage create(Bytes data) {
+        return new ServerMessage(data);
+      }
+
+      private final Bytes data;
+
+      private ServerMessage(Bytes data) throws ValidationArgumentException {
+        required("data", data);
+        this.data = data;
+      }
+
+      public Bytes getData() { return data; }
+
+      @Override public final boolean equals(Object obj) {
+        if (this == obj) { return true; }
+        if (!(obj instanceof ServerMessage)) { return false; }
+        ServerMessage other = (ServerMessage) obj;
+        return equals(data, other.data);
+      }
+
+      @Override protected int computeHashCode() {
+        int result = 1;
+        result = result * 31 + data.hashCode();
+        return result;
+      }
+
+      @Override public void toCompactString(TextBuilder builder) {
+        builder.append("<ServerMessage:");
+        builder.append(" data=").append(data);
+        builder.append('>');
+      }
+
+      public static ServerMessage parseFrom(byte[] data) throws ValidationException {
+        try {
+          return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoAndroidService.InternalDowncall.ServerMessage(), data));
+        } catch (InvalidProtocolBufferNanoException exception) {
+          throw new ValidationException(exception);
+        } catch (ValidationArgumentException exception) {
+          throw new ValidationException(exception.getMessage());
+        }
+      }
+
+      static ServerMessage fromMessageNano(com.google.protos.ipc.invalidation.NanoAndroidService.InternalDowncall.ServerMessage message) {
+        if (message == null) { return null; }
+        return new ServerMessage(Bytes.fromByteArray(message.data));
+      }
+
+      public byte[] toByteArray() {
+        return MessageNano.toByteArray(toMessageNano());
+      }
+
+      com.google.protos.ipc.invalidation.NanoAndroidService.InternalDowncall.ServerMessage toMessageNano() {
+        com.google.protos.ipc.invalidation.NanoAndroidService.InternalDowncall.ServerMessage msg = new com.google.protos.ipc.invalidation.NanoAndroidService.InternalDowncall.ServerMessage();
+        msg.data = data.getByteArray();
+        return msg;
+      }
+    }
+    public static final class NetworkStatus extends ProtoWrapper {
+      public static NetworkStatus create(boolean isOnline) {
+        return new NetworkStatus(isOnline);
+      }
+
+      private final boolean isOnline;
+
+      private NetworkStatus(Boolean isOnline) throws ValidationArgumentException {
+        required("is_online", isOnline);
+        this.isOnline = isOnline;
+      }
+
+      public boolean getIsOnline() { return isOnline; }
+
+      @Override public final boolean equals(Object obj) {
+        if (this == obj) { return true; }
+        if (!(obj instanceof NetworkStatus)) { return false; }
+        NetworkStatus other = (NetworkStatus) obj;
+        return isOnline == other.isOnline;
+      }
+
+      @Override protected int computeHashCode() {
+        int result = 1;
+        result = result * 31 + hash(isOnline);
+        return result;
+      }
+
+      @Override public void toCompactString(TextBuilder builder) {
+        builder.append("<NetworkStatus:");
+        builder.append(" is_online=").append(isOnline);
+        builder.append('>');
+      }
+
+      public static NetworkStatus parseFrom(byte[] data) throws ValidationException {
+        try {
+          return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoAndroidService.InternalDowncall.NetworkStatus(), data));
+        } catch (InvalidProtocolBufferNanoException exception) {
+          throw new ValidationException(exception);
+        } catch (ValidationArgumentException exception) {
+          throw new ValidationException(exception.getMessage());
+        }
+      }
+
+      static NetworkStatus fromMessageNano(com.google.protos.ipc.invalidation.NanoAndroidService.InternalDowncall.NetworkStatus message) {
+        if (message == null) { return null; }
+        return new NetworkStatus(message.isOnline);
+      }
+
+      public byte[] toByteArray() {
+        return MessageNano.toByteArray(toMessageNano());
+      }
+
+      com.google.protos.ipc.invalidation.NanoAndroidService.InternalDowncall.NetworkStatus toMessageNano() {
+        com.google.protos.ipc.invalidation.NanoAndroidService.InternalDowncall.NetworkStatus msg = new com.google.protos.ipc.invalidation.NanoAndroidService.InternalDowncall.NetworkStatus();
+        msg.isOnline = isOnline;
+        return msg;
+      }
+    }
+    public static final class CreateClient extends ProtoWrapper {
+      public static CreateClient create(int clientType,
+          Bytes clientName,
+          com.google.ipc.invalidation.ticl.proto.ClientProtocol.ClientConfigP clientConfig,
+          boolean skipStartForTest) {
+        return new CreateClient(clientType, clientName, clientConfig, skipStartForTest);
+      }
+
+      private final int clientType;
+      private final Bytes clientName;
+      private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.ClientConfigP clientConfig;
+      private final boolean skipStartForTest;
+
+      private CreateClient(Integer clientType,
+          Bytes clientName,
+          com.google.ipc.invalidation.ticl.proto.ClientProtocol.ClientConfigP clientConfig,
+          Boolean skipStartForTest) throws ValidationArgumentException {
+        required("client_type", clientType);
+        this.clientType = clientType;
+        required("client_name", clientName);
+        this.clientName = clientName;
+        required("client_config", clientConfig);
+        this.clientConfig = clientConfig;
+        required("skip_start_for_test", skipStartForTest);
+        this.skipStartForTest = skipStartForTest;
+      }
+
+      public int getClientType() { return clientType; }
+
+      public Bytes getClientName() { return clientName; }
+
+      public com.google.ipc.invalidation.ticl.proto.ClientProtocol.ClientConfigP getClientConfig() { return clientConfig; }
+
+      public boolean getSkipStartForTest() { return skipStartForTest; }
+
+      @Override public final boolean equals(Object obj) {
+        if (this == obj) { return true; }
+        if (!(obj instanceof CreateClient)) { return false; }
+        CreateClient other = (CreateClient) obj;
+        return clientType == other.clientType
+            && equals(clientName, other.clientName)
+            && equals(clientConfig, other.clientConfig)
+            && skipStartForTest == other.skipStartForTest;
+      }
+
+      @Override protected int computeHashCode() {
+        int result = 1;
+        result = result * 31 + hash(clientType);
+        result = result * 31 + clientName.hashCode();
+        result = result * 31 + clientConfig.hashCode();
+        result = result * 31 + hash(skipStartForTest);
+        return result;
+      }
+
+      @Override public void toCompactString(TextBuilder builder) {
+        builder.append("<CreateClient:");
+        builder.append(" client_type=").append(clientType);
+        builder.append(" client_name=").append(clientName);
+        builder.append(" client_config=").append(clientConfig);
+        builder.append(" skip_start_for_test=").append(skipStartForTest);
+        builder.append('>');
+      }
+
+      public static CreateClient parseFrom(byte[] data) throws ValidationException {
+        try {
+          return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoAndroidService.InternalDowncall.CreateClient(), data));
+        } catch (InvalidProtocolBufferNanoException exception) {
+          throw new ValidationException(exception);
+        } catch (ValidationArgumentException exception) {
+          throw new ValidationException(exception.getMessage());
+        }
+      }
+
+      static CreateClient fromMessageNano(com.google.protos.ipc.invalidation.NanoAndroidService.InternalDowncall.CreateClient message) {
+        if (message == null) { return null; }
+        return new CreateClient(message.clientType,
+            Bytes.fromByteArray(message.clientName),
+            com.google.ipc.invalidation.ticl.proto.ClientProtocol.ClientConfigP.fromMessageNano(message.clientConfig),
+            message.skipStartForTest);
+      }
+
+      public byte[] toByteArray() {
+        return MessageNano.toByteArray(toMessageNano());
+      }
+
+      com.google.protos.ipc.invalidation.NanoAndroidService.InternalDowncall.CreateClient toMessageNano() {
+        com.google.protos.ipc.invalidation.NanoAndroidService.InternalDowncall.CreateClient msg = new com.google.protos.ipc.invalidation.NanoAndroidService.InternalDowncall.CreateClient();
+        msg.clientType = clientType;
+        msg.clientName = clientName.getByteArray();
+        msg.clientConfig = clientConfig.toMessageNano();
+        msg.skipStartForTest = skipStartForTest;
+        return msg;
+      }
+    }
+    public static InternalDowncall createWithNetworkAddrChange(com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version version,
+        boolean networkAddrChange) {
+      return new InternalDowncall(version, null, null, networkAddrChange, null);
+    }
+
+    public static InternalDowncall createWithCreateClient(com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version version,
+        com.google.ipc.invalidation.ticl.proto.AndroidService.InternalDowncall.CreateClient createClient) {
+      return new InternalDowncall(version, null, null, null, createClient);
+    }
+
+    public static InternalDowncall createWithServerMessage(com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version version,
+        com.google.ipc.invalidation.ticl.proto.AndroidService.InternalDowncall.ServerMessage serverMessage) {
+      return new InternalDowncall(version, serverMessage, null, null, null);
+    }
+
+    public static InternalDowncall createWithNetworkStatus(com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version version,
+        com.google.ipc.invalidation.ticl.proto.AndroidService.InternalDowncall.NetworkStatus networkStatus) {
+      return new InternalDowncall(version, null, networkStatus, null, null);
+    }
+
+    private final long __hazzerBits;
+    private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version version;
+    private final com.google.ipc.invalidation.ticl.proto.AndroidService.InternalDowncall.ServerMessage serverMessage;
+    private final com.google.ipc.invalidation.ticl.proto.AndroidService.InternalDowncall.NetworkStatus networkStatus;
+    private final boolean networkAddrChange;
+    private final com.google.ipc.invalidation.ticl.proto.AndroidService.InternalDowncall.CreateClient createClient;
+
+    private InternalDowncall(com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version version,
+        com.google.ipc.invalidation.ticl.proto.AndroidService.InternalDowncall.ServerMessage serverMessage,
+        com.google.ipc.invalidation.ticl.proto.AndroidService.InternalDowncall.NetworkStatus networkStatus,
+        Boolean networkAddrChange,
+        com.google.ipc.invalidation.ticl.proto.AndroidService.InternalDowncall.CreateClient createClient) throws ValidationArgumentException {
+      int hazzerBits = 0;
+      required("version", version);
+      this.version = version;
+      this.serverMessage = serverMessage;
+      this.networkStatus = networkStatus;
+      if (networkAddrChange != null) {
+        hazzerBits |= 0x1;
+        this.networkAddrChange = networkAddrChange;
+      } else {
+        this.networkAddrChange = false;
+      }
+      this.createClient = createClient;
+      this.__hazzerBits = hazzerBits;
+      String existingOneOfField = null;
+      if (hasNetworkAddrChange()) {
+        existingOneOfField = "network_addr_change";
+      }
+      if (this.createClient != null) {
+        if (existingOneOfField != null) {
+          oneOfViolation(existingOneOfField, "create_client");
+        }
+        existingOneOfField = "create_client";
+      }
+      if (this.serverMessage != null) {
+        if (existingOneOfField != null) {
+          oneOfViolation(existingOneOfField, "server_message");
+        }
+        existingOneOfField = "server_message";
+      }
+      if (this.networkStatus != null) {
+        if (existingOneOfField != null) {
+          oneOfViolation(existingOneOfField, "network_status");
+        }
+        existingOneOfField = "network_status";
+      }
+      if (existingOneOfField == null) { oneOfViolation(); }
+    }
+
+    public com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version getVersion() { return version; }
+
+    public com.google.ipc.invalidation.ticl.proto.AndroidService.InternalDowncall.ServerMessage getNullableServerMessage() { return serverMessage; }
+
+    public com.google.ipc.invalidation.ticl.proto.AndroidService.InternalDowncall.NetworkStatus getNullableNetworkStatus() { return networkStatus; }
+
+    public boolean getNetworkAddrChange() { return networkAddrChange; }
+    public boolean hasNetworkAddrChange() { return (0x1 & __hazzerBits) != 0; }
+
+    public com.google.ipc.invalidation.ticl.proto.AndroidService.InternalDowncall.CreateClient getNullableCreateClient() { return createClient; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof InternalDowncall)) { return false; }
+      InternalDowncall other = (InternalDowncall) obj;
+      return __hazzerBits == other.__hazzerBits
+          && equals(version, other.version)
+          && equals(serverMessage, other.serverMessage)
+          && equals(networkStatus, other.networkStatus)
+          && (!hasNetworkAddrChange() || networkAddrChange == other.networkAddrChange)
+          && equals(createClient, other.createClient);
+    }
+
+    @Override protected int computeHashCode() {
+      int result = hash(__hazzerBits);
+      result = result * 31 + version.hashCode();
+      if (serverMessage != null) {
+        result = result * 31 + serverMessage.hashCode();
+      }
+      if (networkStatus != null) {
+        result = result * 31 + networkStatus.hashCode();
+      }
+      if (hasNetworkAddrChange()) {
+        result = result * 31 + hash(networkAddrChange);
+      }
+      if (createClient != null) {
+        result = result * 31 + createClient.hashCode();
+      }
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<InternalDowncall:");
+      builder.append(" version=").append(version);
+      if (serverMessage != null) {
+        builder.append(" server_message=").append(serverMessage);
+      }
+      if (networkStatus != null) {
+        builder.append(" network_status=").append(networkStatus);
+      }
+      if (hasNetworkAddrChange()) {
+        builder.append(" network_addr_change=").append(networkAddrChange);
+      }
+      if (createClient != null) {
+        builder.append(" create_client=").append(createClient);
+      }
+      builder.append('>');
+    }
+
+    public static InternalDowncall parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoAndroidService.InternalDowncall(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static InternalDowncall fromMessageNano(com.google.protos.ipc.invalidation.NanoAndroidService.InternalDowncall message) {
+      if (message == null) { return null; }
+      return new InternalDowncall(com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version.fromMessageNano(message.version),
+          com.google.ipc.invalidation.ticl.proto.AndroidService.InternalDowncall.ServerMessage.fromMessageNano(message.serverMessage),
+          com.google.ipc.invalidation.ticl.proto.AndroidService.InternalDowncall.NetworkStatus.fromMessageNano(message.networkStatus),
+          message.networkAddrChange,
+          com.google.ipc.invalidation.ticl.proto.AndroidService.InternalDowncall.CreateClient.fromMessageNano(message.createClient));
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoAndroidService.InternalDowncall toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoAndroidService.InternalDowncall msg = new com.google.protos.ipc.invalidation.NanoAndroidService.InternalDowncall();
+      msg.version = version.toMessageNano();
+      msg.serverMessage = this.serverMessage != null ? serverMessage.toMessageNano() : null;
+      msg.networkStatus = this.networkStatus != null ? networkStatus.toMessageNano() : null;
+      msg.networkAddrChange = hasNetworkAddrChange() ? networkAddrChange : null;
+      msg.createClient = this.createClient != null ? createClient.toMessageNano() : null;
+      return msg;
+    }
+  }
+
+  public static final class ListenerUpcall extends ProtoWrapper {
+    public static final class ReadyUpcall extends ProtoWrapper {
+      public static ReadyUpcall create() {
+        return new ReadyUpcall();
+      }
+
+      public static final ReadyUpcall DEFAULT_INSTANCE = new ReadyUpcall();
+
+
+      private ReadyUpcall() {
+      }
+
+
+      @Override public final boolean equals(Object obj) {
+        if (this == obj) { return true; }
+        if (!(obj instanceof ReadyUpcall)) { return false; }
+        ReadyUpcall other = (ReadyUpcall) obj;
+        return true;
+      }
+
+      @Override protected int computeHashCode() {
+        int result = 1;
+        return result;
+      }
+
+      @Override public void toCompactString(TextBuilder builder) {
+        builder.append("<ReadyUpcall:");
+        builder.append('>');
+      }
+
+      public static ReadyUpcall parseFrom(byte[] data) throws ValidationException {
+        try {
+          return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoAndroidService.ListenerUpcall.ReadyUpcall(), data));
+        } catch (InvalidProtocolBufferNanoException exception) {
+          throw new ValidationException(exception);
+        } catch (ValidationArgumentException exception) {
+          throw new ValidationException(exception.getMessage());
+        }
+      }
+
+      static ReadyUpcall fromMessageNano(com.google.protos.ipc.invalidation.NanoAndroidService.ListenerUpcall.ReadyUpcall message) {
+        if (message == null) { return null; }
+        return new ReadyUpcall();
+      }
+
+      public byte[] toByteArray() {
+        return MessageNano.toByteArray(toMessageNano());
+      }
+
+      com.google.protos.ipc.invalidation.NanoAndroidService.ListenerUpcall.ReadyUpcall toMessageNano() {
+        com.google.protos.ipc.invalidation.NanoAndroidService.ListenerUpcall.ReadyUpcall msg = new com.google.protos.ipc.invalidation.NanoAndroidService.ListenerUpcall.ReadyUpcall();
+        return msg;
+      }
+    }
+    public static final class InvalidateUpcall extends ProtoWrapper {
+      public static InvalidateUpcall createWithInvalidateUnknown(Bytes ackHandle,
+          com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP invalidateUnknown) {
+        return new InvalidateUpcall(ackHandle, null, invalidateUnknown, null);
+      }
+
+      public static InvalidateUpcall createWithInvalidateAll(Bytes ackHandle,
+          boolean invalidateAll) {
+        return new InvalidateUpcall(ackHandle, null, null, invalidateAll);
+      }
+
+      public static InvalidateUpcall createWithInvalidation(Bytes ackHandle,
+          com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationP invalidation) {
+        return new InvalidateUpcall(ackHandle, invalidation, null, null);
+      }
+
+      private final long __hazzerBits;
+      private final Bytes ackHandle;
+      private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationP invalidation;
+      private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP invalidateUnknown;
+      private final boolean invalidateAll;
+
+      private InvalidateUpcall(Bytes ackHandle,
+          com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationP invalidation,
+          com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP invalidateUnknown,
+          Boolean invalidateAll) throws ValidationArgumentException {
+        int hazzerBits = 0;
+        required("ack_handle", ackHandle);
+        this.ackHandle = ackHandle;
+        this.invalidation = invalidation;
+        this.invalidateUnknown = invalidateUnknown;
+        if (invalidateAll != null) {
+          hazzerBits |= 0x1;
+          this.invalidateAll = invalidateAll;
+        } else {
+          this.invalidateAll = false;
+        }
+        this.__hazzerBits = hazzerBits;
+        String existingOneOfField = null;
+        if (this.invalidateUnknown != null) {
+          existingOneOfField = "invalidate_unknown";
+        }
+        if (hasInvalidateAll()) {
+          if (existingOneOfField != null) {
+            oneOfViolation(existingOneOfField, "invalidate_all");
+          }
+          existingOneOfField = "invalidate_all";
+        }
+        if (this.invalidation != null) {
+          if (existingOneOfField != null) {
+            oneOfViolation(existingOneOfField, "invalidation");
+          }
+          existingOneOfField = "invalidation";
+        }
+        if (existingOneOfField == null) { oneOfViolation(); }
+      }
+
+      public Bytes getAckHandle() { return ackHandle; }
+
+      public com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationP getNullableInvalidation() { return invalidation; }
+
+      public com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP getNullableInvalidateUnknown() { return invalidateUnknown; }
+
+      public boolean getInvalidateAll() { return invalidateAll; }
+      public boolean hasInvalidateAll() { return (0x1 & __hazzerBits) != 0; }
+
+      @Override public final boolean equals(Object obj) {
+        if (this == obj) { return true; }
+        if (!(obj instanceof InvalidateUpcall)) { return false; }
+        InvalidateUpcall other = (InvalidateUpcall) obj;
+        return __hazzerBits == other.__hazzerBits
+            && equals(ackHandle, other.ackHandle)
+            && equals(invalidation, other.invalidation)
+            && equals(invalidateUnknown, other.invalidateUnknown)
+            && (!hasInvalidateAll() || invalidateAll == other.invalidateAll);
+      }
+
+      @Override protected int computeHashCode() {
+        int result = hash(__hazzerBits);
+        result = result * 31 + ackHandle.hashCode();
+        if (invalidation != null) {
+          result = result * 31 + invalidation.hashCode();
+        }
+        if (invalidateUnknown != null) {
+          result = result * 31 + invalidateUnknown.hashCode();
+        }
+        if (hasInvalidateAll()) {
+          result = result * 31 + hash(invalidateAll);
+        }
+        return result;
+      }
+
+      @Override public void toCompactString(TextBuilder builder) {
+        builder.append("<InvalidateUpcall:");
+        builder.append(" ack_handle=").append(ackHandle);
+        if (invalidation != null) {
+          builder.append(" invalidation=").append(invalidation);
+        }
+        if (invalidateUnknown != null) {
+          builder.append(" invalidate_unknown=").append(invalidateUnknown);
+        }
+        if (hasInvalidateAll()) {
+          builder.append(" invalidate_all=").append(invalidateAll);
+        }
+        builder.append('>');
+      }
+
+      public static InvalidateUpcall parseFrom(byte[] data) throws ValidationException {
+        try {
+          return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoAndroidService.ListenerUpcall.InvalidateUpcall(), data));
+        } catch (InvalidProtocolBufferNanoException exception) {
+          throw new ValidationException(exception);
+        } catch (ValidationArgumentException exception) {
+          throw new ValidationException(exception.getMessage());
+        }
+      }
+
+      static InvalidateUpcall fromMessageNano(com.google.protos.ipc.invalidation.NanoAndroidService.ListenerUpcall.InvalidateUpcall message) {
+        if (message == null) { return null; }
+        return new InvalidateUpcall(Bytes.fromByteArray(message.ackHandle),
+            com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationP.fromMessageNano(message.invalidation),
+            com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP.fromMessageNano(message.invalidateUnknown),
+            message.invalidateAll);
+      }
+
+      public byte[] toByteArray() {
+        return MessageNano.toByteArray(toMessageNano());
+      }
+
+      com.google.protos.ipc.invalidation.NanoAndroidService.ListenerUpcall.InvalidateUpcall toMessageNano() {
+        com.google.protos.ipc.invalidation.NanoAndroidService.ListenerUpcall.InvalidateUpcall msg = new com.google.protos.ipc.invalidation.NanoAndroidService.ListenerUpcall.InvalidateUpcall();
+        msg.ackHandle = ackHandle.getByteArray();
+        msg.invalidation = this.invalidation != null ? invalidation.toMessageNano() : null;
+        msg.invalidateUnknown = this.invalidateUnknown != null ? invalidateUnknown.toMessageNano() : null;
+        msg.invalidateAll = hasInvalidateAll() ? invalidateAll : null;
+        return msg;
+      }
+    }
+    public static final class RegistrationStatusUpcall extends ProtoWrapper {
+      public static RegistrationStatusUpcall create(com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP objectId,
+          boolean isRegistered) {
+        return new RegistrationStatusUpcall(objectId, isRegistered);
+      }
+
+      private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP objectId;
+      private final boolean isRegistered;
+
+      private RegistrationStatusUpcall(com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP objectId,
+          Boolean isRegistered) throws ValidationArgumentException {
+        required("object_id", objectId);
+        this.objectId = objectId;
+        required("is_registered", isRegistered);
+        this.isRegistered = isRegistered;
+      }
+
+      public com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP getObjectId() { return objectId; }
+
+      public boolean getIsRegistered() { return isRegistered; }
+
+      @Override public final boolean equals(Object obj) {
+        if (this == obj) { return true; }
+        if (!(obj instanceof RegistrationStatusUpcall)) { return false; }
+        RegistrationStatusUpcall other = (RegistrationStatusUpcall) obj;
+        return equals(objectId, other.objectId)
+            && isRegistered == other.isRegistered;
+      }
+
+      @Override protected int computeHashCode() {
+        int result = 1;
+        result = result * 31 + objectId.hashCode();
+        result = result * 31 + hash(isRegistered);
+        return result;
+      }
+
+      @Override public void toCompactString(TextBuilder builder) {
+        builder.append("<RegistrationStatusUpcall:");
+        builder.append(" object_id=").append(objectId);
+        builder.append(" is_registered=").append(isRegistered);
+        builder.append('>');
+      }
+
+      public static RegistrationStatusUpcall parseFrom(byte[] data) throws ValidationException {
+        try {
+          return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoAndroidService.ListenerUpcall.RegistrationStatusUpcall(), data));
+        } catch (InvalidProtocolBufferNanoException exception) {
+          throw new ValidationException(exception);
+        } catch (ValidationArgumentException exception) {
+          throw new ValidationException(exception.getMessage());
+        }
+      }
+
+      static RegistrationStatusUpcall fromMessageNano(com.google.protos.ipc.invalidation.NanoAndroidService.ListenerUpcall.RegistrationStatusUpcall message) {
+        if (message == null) { return null; }
+        return new RegistrationStatusUpcall(com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP.fromMessageNano(message.objectId),
+            message.isRegistered);
+      }
+
+      public byte[] toByteArray() {
+        return MessageNano.toByteArray(toMessageNano());
+      }
+
+      com.google.protos.ipc.invalidation.NanoAndroidService.ListenerUpcall.RegistrationStatusUpcall toMessageNano() {
+        com.google.protos.ipc.invalidation.NanoAndroidService.ListenerUpcall.RegistrationStatusUpcall msg = new com.google.protos.ipc.invalidation.NanoAndroidService.ListenerUpcall.RegistrationStatusUpcall();
+        msg.objectId = objectId.toMessageNano();
+        msg.isRegistered = isRegistered;
+        return msg;
+      }
+    }
+    public static final class RegistrationFailureUpcall extends ProtoWrapper {
+      public static RegistrationFailureUpcall create(com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP objectId,
+          boolean transient_,
+          String message) {
+        return new RegistrationFailureUpcall(objectId, transient_, message);
+      }
+
+      private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP objectId;
+      private final boolean transient_;
+      private final String message;
+
+      private RegistrationFailureUpcall(com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP objectId,
+          Boolean transient_,
+          String message) throws ValidationArgumentException {
+        required("object_id", objectId);
+        this.objectId = objectId;
+        required("transient", transient_);
+        this.transient_ = transient_;
+        required("message", message);
+        this.message = message;
+      }
+
+      public com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP getObjectId() { return objectId; }
+
+      public boolean getTransient() { return transient_; }
+
+      public String getMessage() { return message; }
+
+      @Override public final boolean equals(Object obj) {
+        if (this == obj) { return true; }
+        if (!(obj instanceof RegistrationFailureUpcall)) { return false; }
+        RegistrationFailureUpcall other = (RegistrationFailureUpcall) obj;
+        return equals(objectId, other.objectId)
+            && transient_ == other.transient_
+            && equals(message, other.message);
+      }
+
+      @Override protected int computeHashCode() {
+        int result = 1;
+        result = result * 31 + objectId.hashCode();
+        result = result * 31 + hash(transient_);
+        result = result * 31 + message.hashCode();
+        return result;
+      }
+
+      @Override public void toCompactString(TextBuilder builder) {
+        builder.append("<RegistrationFailureUpcall:");
+        builder.append(" object_id=").append(objectId);
+        builder.append(" transient=").append(transient_);
+        builder.append(" message=").append(message);
+        builder.append('>');
+      }
+
+      public static RegistrationFailureUpcall parseFrom(byte[] data) throws ValidationException {
+        try {
+          return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoAndroidService.ListenerUpcall.RegistrationFailureUpcall(), data));
+        } catch (InvalidProtocolBufferNanoException exception) {
+          throw new ValidationException(exception);
+        } catch (ValidationArgumentException exception) {
+          throw new ValidationException(exception.getMessage());
+        }
+      }
+
+      static RegistrationFailureUpcall fromMessageNano(com.google.protos.ipc.invalidation.NanoAndroidService.ListenerUpcall.RegistrationFailureUpcall message) {
+        if (message == null) { return null; }
+        return new RegistrationFailureUpcall(com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP.fromMessageNano(message.objectId),
+            message.transient_,
+            message.message);
+      }
+
+      public byte[] toByteArray() {
+        return MessageNano.toByteArray(toMessageNano());
+      }
+
+      com.google.protos.ipc.invalidation.NanoAndroidService.ListenerUpcall.RegistrationFailureUpcall toMessageNano() {
+        com.google.protos.ipc.invalidation.NanoAndroidService.ListenerUpcall.RegistrationFailureUpcall msg = new com.google.protos.ipc.invalidation.NanoAndroidService.ListenerUpcall.RegistrationFailureUpcall();
+        msg.objectId = objectId.toMessageNano();
+        msg.transient_ = transient_;
+        msg.message = message;
+        return msg;
+      }
+    }
+    public static final class ReissueRegistrationsUpcall extends ProtoWrapper {
+      public static ReissueRegistrationsUpcall create(Bytes prefix,
+          int length) {
+        return new ReissueRegistrationsUpcall(prefix, length);
+      }
+
+      private final Bytes prefix;
+      private final int length;
+
+      private ReissueRegistrationsUpcall(Bytes prefix,
+          Integer length) throws ValidationArgumentException {
+        required("prefix", prefix);
+        this.prefix = prefix;
+        required("length", length);
+        this.length = length;
+      }
+
+      public Bytes getPrefix() { return prefix; }
+
+      public int getLength() { return length; }
+
+      @Override public final boolean equals(Object obj) {
+        if (this == obj) { return true; }
+        if (!(obj instanceof ReissueRegistrationsUpcall)) { return false; }
+        ReissueRegistrationsUpcall other = (ReissueRegistrationsUpcall) obj;
+        return equals(prefix, other.prefix)
+            && length == other.length;
+      }
+
+      @Override protected int computeHashCode() {
+        int result = 1;
+        result = result * 31 + prefix.hashCode();
+        result = result * 31 + hash(length);
+        return result;
+      }
+
+      @Override public void toCompactString(TextBuilder builder) {
+        builder.append("<ReissueRegistrationsUpcall:");
+        builder.append(" prefix=").append(prefix);
+        builder.append(" length=").append(length);
+        builder.append('>');
+      }
+
+      public static ReissueRegistrationsUpcall parseFrom(byte[] data) throws ValidationException {
+        try {
+          return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoAndroidService.ListenerUpcall.ReissueRegistrationsUpcall(), data));
+        } catch (InvalidProtocolBufferNanoException exception) {
+          throw new ValidationException(exception);
+        } catch (ValidationArgumentException exception) {
+          throw new ValidationException(exception.getMessage());
+        }
+      }
+
+      static ReissueRegistrationsUpcall fromMessageNano(com.google.protos.ipc.invalidation.NanoAndroidService.ListenerUpcall.ReissueRegistrationsUpcall message) {
+        if (message == null) { return null; }
+        return new ReissueRegistrationsUpcall(Bytes.fromByteArray(message.prefix),
+            message.length);
+      }
+
+      public byte[] toByteArray() {
+        return MessageNano.toByteArray(toMessageNano());
+      }
+
+      com.google.protos.ipc.invalidation.NanoAndroidService.ListenerUpcall.ReissueRegistrationsUpcall toMessageNano() {
+        com.google.protos.ipc.invalidation.NanoAndroidService.ListenerUpcall.ReissueRegistrationsUpcall msg = new com.google.protos.ipc.invalidation.NanoAndroidService.ListenerUpcall.ReissueRegistrationsUpcall();
+        msg.prefix = prefix.getByteArray();
+        msg.length = length;
+        return msg;
+      }
+    }
+    public static final class ErrorUpcall extends ProtoWrapper {
+      public static ErrorUpcall create(int errorCode,
+          String errorMessage,
+          boolean isTransient) {
+        return new ErrorUpcall(errorCode, errorMessage, isTransient);
+      }
+
+      private final int errorCode;
+      private final String errorMessage;
+      private final boolean isTransient;
+
+      private ErrorUpcall(Integer errorCode,
+          String errorMessage,
+          Boolean isTransient) throws ValidationArgumentException {
+        required("error_code", errorCode);
+        this.errorCode = errorCode;
+        required("error_message", errorMessage);
+        this.errorMessage = errorMessage;
+        required("is_transient", isTransient);
+        this.isTransient = isTransient;
+      }
+
+      public int getErrorCode() { return errorCode; }
+
+      public String getErrorMessage() { return errorMessage; }
+
+      public boolean getIsTransient() { return isTransient; }
+
+      @Override public final boolean equals(Object obj) {
+        if (this == obj) { return true; }
+        if (!(obj instanceof ErrorUpcall)) { return false; }
+        ErrorUpcall other = (ErrorUpcall) obj;
+        return errorCode == other.errorCode
+            && equals(errorMessage, other.errorMessage)
+            && isTransient == other.isTransient;
+      }
+
+      @Override protected int computeHashCode() {
+        int result = 1;
+        result = result * 31 + hash(errorCode);
+        result = result * 31 + errorMessage.hashCode();
+        result = result * 31 + hash(isTransient);
+        return result;
+      }
+
+      @Override public void toCompactString(TextBuilder builder) {
+        builder.append("<ErrorUpcall:");
+        builder.append(" error_code=").append(errorCode);
+        builder.append(" error_message=").append(errorMessage);
+        builder.append(" is_transient=").append(isTransient);
+        builder.append('>');
+      }
+
+      public static ErrorUpcall parseFrom(byte[] data) throws ValidationException {
+        try {
+          return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoAndroidService.ListenerUpcall.ErrorUpcall(), data));
+        } catch (InvalidProtocolBufferNanoException exception) {
+          throw new ValidationException(exception);
+        } catch (ValidationArgumentException exception) {
+          throw new ValidationException(exception.getMessage());
+        }
+      }
+
+      static ErrorUpcall fromMessageNano(com.google.protos.ipc.invalidation.NanoAndroidService.ListenerUpcall.ErrorUpcall message) {
+        if (message == null) { return null; }
+        return new ErrorUpcall(message.errorCode,
+            message.errorMessage,
+            message.isTransient);
+      }
+
+      public byte[] toByteArray() {
+        return MessageNano.toByteArray(toMessageNano());
+      }
+
+      com.google.protos.ipc.invalidation.NanoAndroidService.ListenerUpcall.ErrorUpcall toMessageNano() {
+        com.google.protos.ipc.invalidation.NanoAndroidService.ListenerUpcall.ErrorUpcall msg = new com.google.protos.ipc.invalidation.NanoAndroidService.ListenerUpcall.ErrorUpcall();
+        msg.errorCode = errorCode;
+        msg.errorMessage = errorMessage;
+        msg.isTransient = isTransient;
+        return msg;
+      }
+    }
+    public static ListenerUpcall createWithReissueRegistrations(com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version version,
+        com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.ReissueRegistrationsUpcall reissueRegistrations) {
+      return new ListenerUpcall(null, version, null, null, null, null, reissueRegistrations, null);
+    }
+
+    public static ListenerUpcall createWithReady(com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version version,
+        com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.ReadyUpcall ready) {
+      return new ListenerUpcall(null, version, ready, null, null, null, null, null);
+    }
+
+    public static ListenerUpcall createWithRegistrationFailure(com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version version,
+        com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.RegistrationFailureUpcall registrationFailure) {
+      return new ListenerUpcall(null, version, null, null, null, registrationFailure, null, null);
+    }
+
+    public static ListenerUpcall createWithError(com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version version,
+        com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.ErrorUpcall error) {
+      return new ListenerUpcall(null, version, null, null, null, null, null, error);
+    }
+
+    public static ListenerUpcall createWithInvalidate(com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version version,
+        com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.InvalidateUpcall invalidate) {
+      return new ListenerUpcall(null, version, null, invalidate, null, null, null, null);
+    }
+
+    public static ListenerUpcall createWithRegistrationStatus(com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version version,
+        com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.RegistrationStatusUpcall registrationStatus) {
+      return new ListenerUpcall(null, version, null, null, registrationStatus, null, null, null);
+    }
+
+    public static ListenerUpcall createWithSerial(long serial,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version version) {
+      return new ListenerUpcall(serial, version, null, null, null, null, null, null);
+    }
+
+    private final long __hazzerBits;
+    private final long serial;
+    private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version version;
+    private final com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.ReadyUpcall ready;
+    private final com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.InvalidateUpcall invalidate;
+    private final com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.RegistrationStatusUpcall registrationStatus;
+    private final com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.RegistrationFailureUpcall registrationFailure;
+    private final com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.ReissueRegistrationsUpcall reissueRegistrations;
+    private final com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.ErrorUpcall error;
+
+    private ListenerUpcall(Long serial,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version version,
+        com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.ReadyUpcall ready,
+        com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.InvalidateUpcall invalidate,
+        com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.RegistrationStatusUpcall registrationStatus,
+        com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.RegistrationFailureUpcall registrationFailure,
+        com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.ReissueRegistrationsUpcall reissueRegistrations,
+        com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.ErrorUpcall error) throws ValidationArgumentException {
+      int hazzerBits = 0;
+      if (serial != null) {
+        hazzerBits |= 0x1;
+        this.serial = serial;
+      } else {
+        this.serial = 0;
+      }
+      required("version", version);
+      this.version = version;
+      if (ready != null) {
+        hazzerBits |= 0x2;
+        this.ready = ready;
+      } else {
+        this.ready = com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.ReadyUpcall.DEFAULT_INSTANCE;
+      }
+      this.invalidate = invalidate;
+      this.registrationStatus = registrationStatus;
+      this.registrationFailure = registrationFailure;
+      this.reissueRegistrations = reissueRegistrations;
+      this.error = error;
+      this.__hazzerBits = hazzerBits;
+      String existingOneOfField = null;
+      if (this.reissueRegistrations != null) {
+        existingOneOfField = "reissue_registrations";
+      }
+      if (hasReady()) {
+        if (existingOneOfField != null) {
+          oneOfViolation(existingOneOfField, "ready");
+        }
+        existingOneOfField = "ready";
+      }
+      if (this.registrationFailure != null) {
+        if (existingOneOfField != null) {
+          oneOfViolation(existingOneOfField, "registration_failure");
+        }
+        existingOneOfField = "registration_failure";
+      }
+      if (this.error != null) {
+        if (existingOneOfField != null) {
+          oneOfViolation(existingOneOfField, "error");
+        }
+        existingOneOfField = "error";
+      }
+      if (this.invalidate != null) {
+        if (existingOneOfField != null) {
+          oneOfViolation(existingOneOfField, "invalidate");
+        }
+        existingOneOfField = "invalidate";
+      }
+      if (this.registrationStatus != null) {
+        if (existingOneOfField != null) {
+          oneOfViolation(existingOneOfField, "registration_status");
+        }
+        existingOneOfField = "registration_status";
+      }
+      if (hasSerial()) {
+        if (existingOneOfField != null) {
+          oneOfViolation(existingOneOfField, "serial");
+        }
+        existingOneOfField = "serial";
+      }
+      if (existingOneOfField == null) { oneOfViolation(); }
+    }
+
+    public long getSerial() { return serial; }
+    public boolean hasSerial() { return (0x1 & __hazzerBits) != 0; }
+
+    public com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version getVersion() { return version; }
+
+    public com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.ReadyUpcall getReady() { return ready; }
+    public boolean hasReady() { return (0x2 & __hazzerBits) != 0; }
+
+    public com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.InvalidateUpcall getNullableInvalidate() { return invalidate; }
+
+    public com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.RegistrationStatusUpcall getNullableRegistrationStatus() { return registrationStatus; }
+
+    public com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.RegistrationFailureUpcall getNullableRegistrationFailure() { return registrationFailure; }
+
+    public com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.ReissueRegistrationsUpcall getNullableReissueRegistrations() { return reissueRegistrations; }
+
+    public com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.ErrorUpcall getNullableError() { return error; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof ListenerUpcall)) { return false; }
+      ListenerUpcall other = (ListenerUpcall) obj;
+      return __hazzerBits == other.__hazzerBits
+          && (!hasSerial() || serial == other.serial)
+          && equals(version, other.version)
+          && (!hasReady() || equals(ready, other.ready))
+          && equals(invalidate, other.invalidate)
+          && equals(registrationStatus, other.registrationStatus)
+          && equals(registrationFailure, other.registrationFailure)
+          && equals(reissueRegistrations, other.reissueRegistrations)
+          && equals(error, other.error);
+    }
+
+    @Override protected int computeHashCode() {
+      int result = hash(__hazzerBits);
+      if (hasSerial()) {
+        result = result * 31 + hash(serial);
+      }
+      result = result * 31 + version.hashCode();
+      if (hasReady()) {
+        result = result * 31 + ready.hashCode();
+      }
+      if (invalidate != null) {
+        result = result * 31 + invalidate.hashCode();
+      }
+      if (registrationStatus != null) {
+        result = result * 31 + registrationStatus.hashCode();
+      }
+      if (registrationFailure != null) {
+        result = result * 31 + registrationFailure.hashCode();
+      }
+      if (reissueRegistrations != null) {
+        result = result * 31 + reissueRegistrations.hashCode();
+      }
+      if (error != null) {
+        result = result * 31 + error.hashCode();
+      }
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<ListenerUpcall:");
+      if (hasSerial()) {
+        builder.append(" serial=").append(serial);
+      }
+      builder.append(" version=").append(version);
+      if (hasReady()) {
+        builder.append(" ready=").append(ready);
+      }
+      if (invalidate != null) {
+        builder.append(" invalidate=").append(invalidate);
+      }
+      if (registrationStatus != null) {
+        builder.append(" registration_status=").append(registrationStatus);
+      }
+      if (registrationFailure != null) {
+        builder.append(" registration_failure=").append(registrationFailure);
+      }
+      if (reissueRegistrations != null) {
+        builder.append(" reissue_registrations=").append(reissueRegistrations);
+      }
+      if (error != null) {
+        builder.append(" error=").append(error);
+      }
+      builder.append('>');
+    }
+
+    public static ListenerUpcall parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoAndroidService.ListenerUpcall(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static ListenerUpcall fromMessageNano(com.google.protos.ipc.invalidation.NanoAndroidService.ListenerUpcall message) {
+      if (message == null) { return null; }
+      return new ListenerUpcall(message.serial,
+          com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version.fromMessageNano(message.version),
+          com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.ReadyUpcall.fromMessageNano(message.ready),
+          com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.InvalidateUpcall.fromMessageNano(message.invalidate),
+          com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.RegistrationStatusUpcall.fromMessageNano(message.registrationStatus),
+          com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.RegistrationFailureUpcall.fromMessageNano(message.registrationFailure),
+          com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.ReissueRegistrationsUpcall.fromMessageNano(message.reissueRegistrations),
+          com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.ErrorUpcall.fromMessageNano(message.error));
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoAndroidService.ListenerUpcall toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoAndroidService.ListenerUpcall msg = new com.google.protos.ipc.invalidation.NanoAndroidService.ListenerUpcall();
+      msg.serial = hasSerial() ? serial : null;
+      msg.version = version.toMessageNano();
+      msg.ready = hasReady() ? ready.toMessageNano() : null;
+      msg.invalidate = this.invalidate != null ? invalidate.toMessageNano() : null;
+      msg.registrationStatus = this.registrationStatus != null ? registrationStatus.toMessageNano() : null;
+      msg.registrationFailure = this.registrationFailure != null ? registrationFailure.toMessageNano() : null;
+      msg.reissueRegistrations = this.reissueRegistrations != null ? reissueRegistrations.toMessageNano() : null;
+      msg.error = this.error != null ? error.toMessageNano() : null;
+      return msg;
+    }
+  }
+
+  public static final class AndroidSchedulerEvent extends ProtoWrapper {
+    public static AndroidSchedulerEvent create(com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version version,
+        String eventName,
+        long ticlId) {
+      return new AndroidSchedulerEvent(version, eventName, ticlId);
+    }
+
+    private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version version;
+    private final String eventName;
+    private final long ticlId;
+
+    private AndroidSchedulerEvent(com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version version,
+        String eventName,
+        Long ticlId) throws ValidationArgumentException {
+      required("version", version);
+      this.version = version;
+      required("event_name", eventName);
+      this.eventName = eventName;
+      required("ticl_id", ticlId);
+      this.ticlId = ticlId;
+    }
+
+    public com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version getVersion() { return version; }
+
+    public String getEventName() { return eventName; }
+
+    public long getTiclId() { return ticlId; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof AndroidSchedulerEvent)) { return false; }
+      AndroidSchedulerEvent other = (AndroidSchedulerEvent) obj;
+      return equals(version, other.version)
+          && equals(eventName, other.eventName)
+          && ticlId == other.ticlId;
+    }
+
+    @Override protected int computeHashCode() {
+      int result = 1;
+      result = result * 31 + version.hashCode();
+      result = result * 31 + eventName.hashCode();
+      result = result * 31 + hash(ticlId);
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<AndroidSchedulerEvent:");
+      builder.append(" version=").append(version);
+      builder.append(" event_name=").append(eventName);
+      builder.append(" ticl_id=").append(ticlId);
+      builder.append('>');
+    }
+
+    public static AndroidSchedulerEvent parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoAndroidService.AndroidSchedulerEvent(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static AndroidSchedulerEvent fromMessageNano(com.google.protos.ipc.invalidation.NanoAndroidService.AndroidSchedulerEvent message) {
+      if (message == null) { return null; }
+      return new AndroidSchedulerEvent(com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version.fromMessageNano(message.version),
+          message.eventName,
+          message.ticlId);
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoAndroidService.AndroidSchedulerEvent toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoAndroidService.AndroidSchedulerEvent msg = new com.google.protos.ipc.invalidation.NanoAndroidService.AndroidSchedulerEvent();
+      msg.version = version.toMessageNano();
+      msg.eventName = eventName;
+      msg.ticlId = ticlId;
+      return msg;
+    }
+  }
+
+  public static final class AndroidNetworkSendRequest extends ProtoWrapper {
+    public static AndroidNetworkSendRequest create(com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version version,
+        Bytes message) {
+      return new AndroidNetworkSendRequest(version, message);
+    }
+
+    private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version version;
+    private final Bytes message;
+
+    private AndroidNetworkSendRequest(com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version version,
+        Bytes message) throws ValidationArgumentException {
+      required("version", version);
+      this.version = version;
+      required("message", message);
+      this.message = message;
+    }
+
+    public com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version getVersion() { return version; }
+
+    public Bytes getMessage() { return message; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof AndroidNetworkSendRequest)) { return false; }
+      AndroidNetworkSendRequest other = (AndroidNetworkSendRequest) obj;
+      return equals(version, other.version)
+          && equals(message, other.message);
+    }
+
+    @Override protected int computeHashCode() {
+      int result = 1;
+      result = result * 31 + version.hashCode();
+      result = result * 31 + message.hashCode();
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<AndroidNetworkSendRequest:");
+      builder.append(" version=").append(version);
+      builder.append(" message=").append(message);
+      builder.append('>');
+    }
+
+    public static AndroidNetworkSendRequest parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoAndroidService.AndroidNetworkSendRequest(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static AndroidNetworkSendRequest fromMessageNano(com.google.protos.ipc.invalidation.NanoAndroidService.AndroidNetworkSendRequest message) {
+      if (message == null) { return null; }
+      return new AndroidNetworkSendRequest(com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version.fromMessageNano(message.version),
+          Bytes.fromByteArray(message.message));
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoAndroidService.AndroidNetworkSendRequest toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoAndroidService.AndroidNetworkSendRequest msg = new com.google.protos.ipc.invalidation.NanoAndroidService.AndroidNetworkSendRequest();
+      msg.version = version.toMessageNano();
+      msg.message = message.getByteArray();
+      return msg;
+    }
+  }
+
+  public static final class AndroidTiclState extends ProtoWrapper {
+    public static final class Metadata extends ProtoWrapper {
+      public static Metadata create(int clientType,
+          Bytes clientName,
+          long ticlId,
+          com.google.ipc.invalidation.ticl.proto.ClientProtocol.ClientConfigP clientConfig) {
+        return new Metadata(clientType, clientName, ticlId, clientConfig);
+      }
+
+      private final int clientType;
+      private final Bytes clientName;
+      private final long ticlId;
+      private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.ClientConfigP clientConfig;
+
+      private Metadata(Integer clientType,
+          Bytes clientName,
+          Long ticlId,
+          com.google.ipc.invalidation.ticl.proto.ClientProtocol.ClientConfigP clientConfig) throws ValidationArgumentException {
+        required("client_type", clientType);
+        this.clientType = clientType;
+        required("client_name", clientName);
+        this.clientName = clientName;
+        required("ticl_id", ticlId);
+        this.ticlId = ticlId;
+        required("client_config", clientConfig);
+        this.clientConfig = clientConfig;
+      }
+
+      public int getClientType() { return clientType; }
+
+      public Bytes getClientName() { return clientName; }
+
+      public long getTiclId() { return ticlId; }
+
+      public com.google.ipc.invalidation.ticl.proto.ClientProtocol.ClientConfigP getClientConfig() { return clientConfig; }
+
+      @Override public final boolean equals(Object obj) {
+        if (this == obj) { return true; }
+        if (!(obj instanceof Metadata)) { return false; }
+        Metadata other = (Metadata) obj;
+        return clientType == other.clientType
+            && equals(clientName, other.clientName)
+            && ticlId == other.ticlId
+            && equals(clientConfig, other.clientConfig);
+      }
+
+      @Override protected int computeHashCode() {
+        int result = 1;
+        result = result * 31 + hash(clientType);
+        result = result * 31 + clientName.hashCode();
+        result = result * 31 + hash(ticlId);
+        result = result * 31 + clientConfig.hashCode();
+        return result;
+      }
+
+      @Override public void toCompactString(TextBuilder builder) {
+        builder.append("<Metadata:");
+        builder.append(" client_type=").append(clientType);
+        builder.append(" client_name=").append(clientName);
+        builder.append(" ticl_id=").append(ticlId);
+        builder.append(" client_config=").append(clientConfig);
+        builder.append('>');
+      }
+
+      public static Metadata parseFrom(byte[] data) throws ValidationException {
+        try {
+          return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoAndroidService.AndroidTiclState.Metadata(), data));
+        } catch (InvalidProtocolBufferNanoException exception) {
+          throw new ValidationException(exception);
+        } catch (ValidationArgumentException exception) {
+          throw new ValidationException(exception.getMessage());
+        }
+      }
+
+      static Metadata fromMessageNano(com.google.protos.ipc.invalidation.NanoAndroidService.AndroidTiclState.Metadata message) {
+        if (message == null) { return null; }
+        return new Metadata(message.clientType,
+            Bytes.fromByteArray(message.clientName),
+            message.ticlId,
+            com.google.ipc.invalidation.ticl.proto.ClientProtocol.ClientConfigP.fromMessageNano(message.clientConfig));
+      }
+
+      public byte[] toByteArray() {
+        return MessageNano.toByteArray(toMessageNano());
+      }
+
+      com.google.protos.ipc.invalidation.NanoAndroidService.AndroidTiclState.Metadata toMessageNano() {
+        com.google.protos.ipc.invalidation.NanoAndroidService.AndroidTiclState.Metadata msg = new com.google.protos.ipc.invalidation.NanoAndroidService.AndroidTiclState.Metadata();
+        msg.clientType = clientType;
+        msg.clientName = clientName.getByteArray();
+        msg.ticlId = ticlId;
+        msg.clientConfig = clientConfig.toMessageNano();
+        return msg;
+      }
+    }
+    public static AndroidTiclState create(com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version version,
+        com.google.ipc.invalidation.ticl.proto.JavaClient.InvalidationClientState ticlState,
+        com.google.ipc.invalidation.ticl.proto.AndroidService.AndroidTiclState.Metadata metadata) {
+      return new AndroidTiclState(version, ticlState, metadata);
+    }
+
+    private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version version;
+    private final com.google.ipc.invalidation.ticl.proto.JavaClient.InvalidationClientState ticlState;
+    private final com.google.ipc.invalidation.ticl.proto.AndroidService.AndroidTiclState.Metadata metadata;
+
+    private AndroidTiclState(com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version version,
+        com.google.ipc.invalidation.ticl.proto.JavaClient.InvalidationClientState ticlState,
+        com.google.ipc.invalidation.ticl.proto.AndroidService.AndroidTiclState.Metadata metadata) throws ValidationArgumentException {
+      required("version", version);
+      this.version = version;
+      required("ticl_state", ticlState);
+      this.ticlState = ticlState;
+      required("metadata", metadata);
+      this.metadata = metadata;
+    }
+
+    public com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version getVersion() { return version; }
+
+    public com.google.ipc.invalidation.ticl.proto.JavaClient.InvalidationClientState getTiclState() { return ticlState; }
+
+    public com.google.ipc.invalidation.ticl.proto.AndroidService.AndroidTiclState.Metadata getMetadata() { return metadata; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof AndroidTiclState)) { return false; }
+      AndroidTiclState other = (AndroidTiclState) obj;
+      return equals(version, other.version)
+          && equals(ticlState, other.ticlState)
+          && equals(metadata, other.metadata);
+    }
+
+    @Override protected int computeHashCode() {
+      int result = 1;
+      result = result * 31 + version.hashCode();
+      result = result * 31 + ticlState.hashCode();
+      result = result * 31 + metadata.hashCode();
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<AndroidTiclState:");
+      builder.append(" version=").append(version);
+      builder.append(" ticl_state=").append(ticlState);
+      builder.append(" metadata=").append(metadata);
+      builder.append('>');
+    }
+
+    public static AndroidTiclState parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoAndroidService.AndroidTiclState(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static AndroidTiclState fromMessageNano(com.google.protos.ipc.invalidation.NanoAndroidService.AndroidTiclState message) {
+      if (message == null) { return null; }
+      return new AndroidTiclState(com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version.fromMessageNano(message.version),
+          com.google.ipc.invalidation.ticl.proto.JavaClient.InvalidationClientState.fromMessageNano(message.ticlState),
+          com.google.ipc.invalidation.ticl.proto.AndroidService.AndroidTiclState.Metadata.fromMessageNano(message.metadata));
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoAndroidService.AndroidTiclState toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoAndroidService.AndroidTiclState msg = new com.google.protos.ipc.invalidation.NanoAndroidService.AndroidTiclState();
+      msg.version = version.toMessageNano();
+      msg.ticlState = ticlState.toMessageNano();
+      msg.metadata = metadata.toMessageNano();
+      return msg;
+    }
+  }
+
+  public static final class AndroidTiclStateWithDigest extends ProtoWrapper {
+    public static AndroidTiclStateWithDigest create(com.google.ipc.invalidation.ticl.proto.AndroidService.AndroidTiclState state,
+        Bytes digest) {
+      return new AndroidTiclStateWithDigest(state, digest);
+    }
+
+    private final com.google.ipc.invalidation.ticl.proto.AndroidService.AndroidTiclState state;
+    private final Bytes digest;
+
+    private AndroidTiclStateWithDigest(com.google.ipc.invalidation.ticl.proto.AndroidService.AndroidTiclState state,
+        Bytes digest) throws ValidationArgumentException {
+      required("state", state);
+      this.state = state;
+      required("digest", digest);
+      this.digest = digest;
+    }
+
+    public com.google.ipc.invalidation.ticl.proto.AndroidService.AndroidTiclState getState() { return state; }
+
+    public Bytes getDigest() { return digest; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof AndroidTiclStateWithDigest)) { return false; }
+      AndroidTiclStateWithDigest other = (AndroidTiclStateWithDigest) obj;
+      return equals(state, other.state)
+          && equals(digest, other.digest);
+    }
+
+    @Override protected int computeHashCode() {
+      int result = 1;
+      result = result * 31 + state.hashCode();
+      result = result * 31 + digest.hashCode();
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<AndroidTiclStateWithDigest:");
+      builder.append(" state=").append(state);
+      builder.append(" digest=").append(digest);
+      builder.append('>');
+    }
+
+    public static AndroidTiclStateWithDigest parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoAndroidService.AndroidTiclStateWithDigest(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static AndroidTiclStateWithDigest fromMessageNano(com.google.protos.ipc.invalidation.NanoAndroidService.AndroidTiclStateWithDigest message) {
+      if (message == null) { return null; }
+      return new AndroidTiclStateWithDigest(com.google.ipc.invalidation.ticl.proto.AndroidService.AndroidTiclState.fromMessageNano(message.state),
+          Bytes.fromByteArray(message.digest));
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoAndroidService.AndroidTiclStateWithDigest toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoAndroidService.AndroidTiclStateWithDigest msg = new com.google.protos.ipc.invalidation.NanoAndroidService.AndroidTiclStateWithDigest();
+      msg.state = state.toMessageNano();
+      msg.digest = digest.getByteArray();
+      return msg;
+    }
+  }
+}
diff --git a/java/com/google/ipc/invalidation/ticl/proto/ChannelCommon.java b/java/com/google/ipc/invalidation/ticl/proto/ChannelCommon.java
new file mode 100644
index 0000000..bed01e6
--- /dev/null
+++ b/java/com/google/ipc/invalidation/ticl/proto/ChannelCommon.java
@@ -0,0 +1,216 @@
+/*
+ * 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.
+ */
+// Generated by j/c/g/ipc/invalidation/common/proto_wrapper_generator
+package com.google.ipc.invalidation.ticl.proto;
+
+import com.google.ipc.invalidation.util.Bytes;
+import com.google.ipc.invalidation.util.ProtoWrapper;
+import com.google.ipc.invalidation.util.ProtoWrapper.ValidationException;
+import com.google.ipc.invalidation.util.TextBuilder;
+import com.google.protobuf.nano.MessageNano;
+import com.google.protobuf.nano.InvalidProtocolBufferNanoException;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+
+public interface ChannelCommon {
+
+  public static final class ChannelMessageEncoding extends ProtoWrapper {
+    public interface MessageEncoding {
+      public static final int PROTOBUF_BINARY_FORMAT = 1;
+      public static final int PROTOBUF_JSON_FORMAT = 2;
+    }
+
+    public static ChannelMessageEncoding create() {
+      return new ChannelMessageEncoding();
+    }
+
+    public static final ChannelMessageEncoding DEFAULT_INSTANCE = new ChannelMessageEncoding();
+
+
+    private ChannelMessageEncoding() {
+    }
+
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof ChannelMessageEncoding)) { return false; }
+      ChannelMessageEncoding other = (ChannelMessageEncoding) obj;
+      return true;
+    }
+
+    @Override protected int computeHashCode() {
+      int result = 1;
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<ChannelMessageEncoding:");
+      builder.append('>');
+    }
+
+    public static ChannelMessageEncoding parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoChannelCommon.ChannelMessageEncoding(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static ChannelMessageEncoding fromMessageNano(com.google.protos.ipc.invalidation.NanoChannelCommon.ChannelMessageEncoding message) {
+      if (message == null) { return null; }
+      return new ChannelMessageEncoding();
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoChannelCommon.ChannelMessageEncoding toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoChannelCommon.ChannelMessageEncoding msg = new com.google.protos.ipc.invalidation.NanoChannelCommon.ChannelMessageEncoding();
+      return msg;
+    }
+  }
+
+  public static final class NetworkEndpointId extends ProtoWrapper {
+    public interface NetworkAddress {
+      public static final int TEST = 1;
+      public static final int BUZZ = 111;
+      public static final int STUBBY = 112;
+      public static final int ANDROID = 113;
+      public static final int LCS = 114;
+      public static final int TIPS_STUBBY = 115;
+    }
+
+    public static NetworkEndpointId create(Integer networkAddress,
+        Bytes clientAddress,
+        Boolean isOffline) {
+      return new NetworkEndpointId(networkAddress, clientAddress, isOffline);
+    }
+
+    public static final NetworkEndpointId DEFAULT_INSTANCE = new NetworkEndpointId(null, null, null);
+
+    private final long __hazzerBits;
+    private final int networkAddress;
+    private final Bytes clientAddress;
+    private final boolean isOffline;
+
+    private NetworkEndpointId(Integer networkAddress,
+        Bytes clientAddress,
+        Boolean isOffline) {
+      int hazzerBits = 0;
+      if (networkAddress != null) {
+        hazzerBits |= 0x1;
+        this.networkAddress = networkAddress;
+      } else {
+        this.networkAddress = 1;
+      }
+      if (clientAddress != null) {
+        hazzerBits |= 0x2;
+        this.clientAddress = clientAddress;
+      } else {
+        this.clientAddress = Bytes.EMPTY_BYTES;
+      }
+      if (isOffline != null) {
+        hazzerBits |= 0x4;
+        this.isOffline = isOffline;
+      } else {
+        this.isOffline = false;
+      }
+      this.__hazzerBits = hazzerBits;
+    }
+
+    public int getNetworkAddress() { return networkAddress; }
+    public boolean hasNetworkAddress() { return (0x1 & __hazzerBits) != 0; }
+
+    public Bytes getClientAddress() { return clientAddress; }
+    public boolean hasClientAddress() { return (0x2 & __hazzerBits) != 0; }
+
+    public boolean getIsOffline() { return isOffline; }
+    public boolean hasIsOffline() { return (0x4 & __hazzerBits) != 0; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof NetworkEndpointId)) { return false; }
+      NetworkEndpointId other = (NetworkEndpointId) obj;
+      return __hazzerBits == other.__hazzerBits
+          && (!hasNetworkAddress() || networkAddress == other.networkAddress)
+          && (!hasClientAddress() || equals(clientAddress, other.clientAddress))
+          && (!hasIsOffline() || isOffline == other.isOffline);
+    }
+
+    @Override protected int computeHashCode() {
+      int result = hash(__hazzerBits);
+      if (hasNetworkAddress()) {
+        result = result * 31 + hash(networkAddress);
+      }
+      if (hasClientAddress()) {
+        result = result * 31 + clientAddress.hashCode();
+      }
+      if (hasIsOffline()) {
+        result = result * 31 + hash(isOffline);
+      }
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<NetworkEndpointId:");
+      if (hasNetworkAddress()) {
+        builder.append(" network_address=").append(networkAddress);
+      }
+      if (hasClientAddress()) {
+        builder.append(" client_address=").append(clientAddress);
+      }
+      if (hasIsOffline()) {
+        builder.append(" is_offline=").append(isOffline);
+      }
+      builder.append('>');
+    }
+
+    public static NetworkEndpointId parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoChannelCommon.NetworkEndpointId(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static NetworkEndpointId fromMessageNano(com.google.protos.ipc.invalidation.NanoChannelCommon.NetworkEndpointId message) {
+      if (message == null) { return null; }
+      return new NetworkEndpointId(message.networkAddress,
+          Bytes.fromByteArray(message.clientAddress),
+          message.isOffline);
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoChannelCommon.NetworkEndpointId toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoChannelCommon.NetworkEndpointId msg = new com.google.protos.ipc.invalidation.NanoChannelCommon.NetworkEndpointId();
+      msg.networkAddress = hasNetworkAddress() ? networkAddress : null;
+      msg.clientAddress = hasClientAddress() ? clientAddress.getByteArray() : null;
+      msg.isOffline = hasIsOffline() ? isOffline : null;
+      return msg;
+    }
+  }
+}
diff --git a/java/com/google/ipc/invalidation/ticl/proto/Client.java b/java/com/google/ipc/invalidation/ticl/proto/Client.java
new file mode 100644
index 0000000..c8e2196
--- /dev/null
+++ b/java/com/google/ipc/invalidation/ticl/proto/Client.java
@@ -0,0 +1,483 @@
+/*
+ * 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.
+ */
+// Generated by j/c/g/ipc/invalidation/common/proto_wrapper_generator
+package com.google.ipc.invalidation.ticl.proto;
+
+import com.google.ipc.invalidation.util.Bytes;
+import com.google.ipc.invalidation.util.ProtoWrapper;
+import com.google.ipc.invalidation.util.ProtoWrapper.ValidationException;
+import com.google.ipc.invalidation.util.TextBuilder;
+import com.google.protobuf.nano.MessageNano;
+import com.google.protobuf.nano.InvalidProtocolBufferNanoException;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+
+public interface Client {
+
+  public static final class AckHandleP extends ProtoWrapper {
+    public static AckHandleP create(com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationP invalidation) {
+      return new AckHandleP(invalidation);
+    }
+
+    public static final AckHandleP DEFAULT_INSTANCE = new AckHandleP(null);
+
+    private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationP invalidation;
+
+    private AckHandleP(com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationP invalidation) {
+      this.invalidation = invalidation;
+    }
+
+    public com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationP getNullableInvalidation() { return invalidation; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof AckHandleP)) { return false; }
+      AckHandleP other = (AckHandleP) obj;
+      return equals(invalidation, other.invalidation);
+    }
+
+    @Override protected int computeHashCode() {
+      int result = 1;
+      if (invalidation != null) {
+        result = result * 31 + invalidation.hashCode();
+      }
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<AckHandleP:");
+      if (invalidation != null) {
+        builder.append(" invalidation=").append(invalidation);
+      }
+      builder.append('>');
+    }
+
+    public static AckHandleP parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoClient.AckHandleP(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static AckHandleP fromMessageNano(com.google.protos.ipc.invalidation.NanoClient.AckHandleP message) {
+      if (message == null) { return null; }
+      return new AckHandleP(com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationP.fromMessageNano(message.invalidation));
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoClient.AckHandleP toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoClient.AckHandleP msg = new com.google.protos.ipc.invalidation.NanoClient.AckHandleP();
+      msg.invalidation = this.invalidation != null ? invalidation.toMessageNano() : null;
+      return msg;
+    }
+  }
+
+  public static final class PersistentTiclState extends ProtoWrapper {
+    public static final class Builder {
+      public Bytes clientToken;
+      public Long lastMessageSendTimeMs;
+      public Builder() {
+      }
+
+      public PersistentTiclState build() {
+        return new PersistentTiclState(clientToken, lastMessageSendTimeMs);
+      }
+    }
+
+    public static PersistentTiclState create(Bytes clientToken,
+        Long lastMessageSendTimeMs) {
+      return new PersistentTiclState(clientToken, lastMessageSendTimeMs);
+    }
+
+    public static final PersistentTiclState DEFAULT_INSTANCE = new PersistentTiclState(null, null);
+
+    private final long __hazzerBits;
+    private final Bytes clientToken;
+    private final long lastMessageSendTimeMs;
+
+    private PersistentTiclState(Bytes clientToken,
+        Long lastMessageSendTimeMs) {
+      int hazzerBits = 0;
+      if (clientToken != null) {
+        hazzerBits |= 0x1;
+        this.clientToken = clientToken;
+      } else {
+        this.clientToken = Bytes.EMPTY_BYTES;
+      }
+      if (lastMessageSendTimeMs != null) {
+        hazzerBits |= 0x2;
+        this.lastMessageSendTimeMs = lastMessageSendTimeMs;
+      } else {
+        this.lastMessageSendTimeMs = 0;
+      }
+      this.__hazzerBits = hazzerBits;
+    }
+
+    public Bytes getClientToken() { return clientToken; }
+    public boolean hasClientToken() { return (0x1 & __hazzerBits) != 0; }
+
+    public long getLastMessageSendTimeMs() { return lastMessageSendTimeMs; }
+    public boolean hasLastMessageSendTimeMs() { return (0x2 & __hazzerBits) != 0; }
+
+    public Builder toBuilder() {
+      Builder builder = new Builder();
+      if (hasClientToken()) {
+        builder.clientToken = clientToken;
+      }
+      if (hasLastMessageSendTimeMs()) {
+        builder.lastMessageSendTimeMs = lastMessageSendTimeMs;
+      }
+      return builder;
+    }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof PersistentTiclState)) { return false; }
+      PersistentTiclState other = (PersistentTiclState) obj;
+      return __hazzerBits == other.__hazzerBits
+          && (!hasClientToken() || equals(clientToken, other.clientToken))
+          && (!hasLastMessageSendTimeMs() || lastMessageSendTimeMs == other.lastMessageSendTimeMs);
+    }
+
+    @Override protected int computeHashCode() {
+      int result = hash(__hazzerBits);
+      if (hasClientToken()) {
+        result = result * 31 + clientToken.hashCode();
+      }
+      if (hasLastMessageSendTimeMs()) {
+        result = result * 31 + hash(lastMessageSendTimeMs);
+      }
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<PersistentTiclState:");
+      if (hasClientToken()) {
+        builder.append(" client_token=").append(clientToken);
+      }
+      if (hasLastMessageSendTimeMs()) {
+        builder.append(" last_message_send_time_ms=").append(lastMessageSendTimeMs);
+      }
+      builder.append('>');
+    }
+
+    public static PersistentTiclState parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoClient.PersistentTiclState(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static PersistentTiclState fromMessageNano(com.google.protos.ipc.invalidation.NanoClient.PersistentTiclState message) {
+      if (message == null) { return null; }
+      return new PersistentTiclState(Bytes.fromByteArray(message.clientToken),
+          message.lastMessageSendTimeMs);
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoClient.PersistentTiclState toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoClient.PersistentTiclState msg = new com.google.protos.ipc.invalidation.NanoClient.PersistentTiclState();
+      msg.clientToken = hasClientToken() ? clientToken.getByteArray() : null;
+      msg.lastMessageSendTimeMs = hasLastMessageSendTimeMs() ? lastMessageSendTimeMs : null;
+      return msg;
+    }
+  }
+
+  public static final class PersistentStateBlob extends ProtoWrapper {
+    public static PersistentStateBlob create(com.google.ipc.invalidation.ticl.proto.Client.PersistentTiclState ticlState,
+        Bytes authenticationCode) {
+      return new PersistentStateBlob(ticlState, authenticationCode);
+    }
+
+    public static final PersistentStateBlob DEFAULT_INSTANCE = new PersistentStateBlob(null, null);
+
+    private final long __hazzerBits;
+    private final com.google.ipc.invalidation.ticl.proto.Client.PersistentTiclState ticlState;
+    private final Bytes authenticationCode;
+
+    private PersistentStateBlob(com.google.ipc.invalidation.ticl.proto.Client.PersistentTiclState ticlState,
+        Bytes authenticationCode) {
+      int hazzerBits = 0;
+      if (ticlState != null) {
+        hazzerBits |= 0x1;
+        this.ticlState = ticlState;
+      } else {
+        this.ticlState = com.google.ipc.invalidation.ticl.proto.Client.PersistentTiclState.DEFAULT_INSTANCE;
+      }
+      if (authenticationCode != null) {
+        hazzerBits |= 0x2;
+        this.authenticationCode = authenticationCode;
+      } else {
+        this.authenticationCode = Bytes.EMPTY_BYTES;
+      }
+      this.__hazzerBits = hazzerBits;
+    }
+
+    public com.google.ipc.invalidation.ticl.proto.Client.PersistentTiclState getTiclState() { return ticlState; }
+    public boolean hasTiclState() { return (0x1 & __hazzerBits) != 0; }
+
+    public Bytes getAuthenticationCode() { return authenticationCode; }
+    public boolean hasAuthenticationCode() { return (0x2 & __hazzerBits) != 0; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof PersistentStateBlob)) { return false; }
+      PersistentStateBlob other = (PersistentStateBlob) obj;
+      return __hazzerBits == other.__hazzerBits
+          && (!hasTiclState() || equals(ticlState, other.ticlState))
+          && (!hasAuthenticationCode() || equals(authenticationCode, other.authenticationCode));
+    }
+
+    @Override protected int computeHashCode() {
+      int result = hash(__hazzerBits);
+      if (hasTiclState()) {
+        result = result * 31 + ticlState.hashCode();
+      }
+      if (hasAuthenticationCode()) {
+        result = result * 31 + authenticationCode.hashCode();
+      }
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<PersistentStateBlob:");
+      if (hasTiclState()) {
+        builder.append(" ticl_state=").append(ticlState);
+      }
+      if (hasAuthenticationCode()) {
+        builder.append(" authentication_code=").append(authenticationCode);
+      }
+      builder.append('>');
+    }
+
+    public static PersistentStateBlob parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoClient.PersistentStateBlob(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static PersistentStateBlob fromMessageNano(com.google.protos.ipc.invalidation.NanoClient.PersistentStateBlob message) {
+      if (message == null) { return null; }
+      return new PersistentStateBlob(com.google.ipc.invalidation.ticl.proto.Client.PersistentTiclState.fromMessageNano(message.ticlState),
+          Bytes.fromByteArray(message.authenticationCode));
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoClient.PersistentStateBlob toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoClient.PersistentStateBlob msg = new com.google.protos.ipc.invalidation.NanoClient.PersistentStateBlob();
+      msg.ticlState = hasTiclState() ? ticlState.toMessageNano() : null;
+      msg.authenticationCode = hasAuthenticationCode() ? authenticationCode.getByteArray() : null;
+      return msg;
+    }
+  }
+
+  public static final class RunStateP extends ProtoWrapper {
+    public interface State {
+      public static final int NOT_STARTED = 1;
+      public static final int STARTED = 2;
+      public static final int STOPPED = 3;
+    }
+
+    public static RunStateP create(Integer state) {
+      return new RunStateP(state);
+    }
+
+    public static final RunStateP DEFAULT_INSTANCE = new RunStateP(null);
+
+    private final long __hazzerBits;
+    private final int state;
+
+    private RunStateP(Integer state) {
+      int hazzerBits = 0;
+      if (state != null) {
+        hazzerBits |= 0x1;
+        this.state = state;
+      } else {
+        this.state = 1;
+      }
+      this.__hazzerBits = hazzerBits;
+    }
+
+    public int getState() { return state; }
+    public boolean hasState() { return (0x1 & __hazzerBits) != 0; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof RunStateP)) { return false; }
+      RunStateP other = (RunStateP) obj;
+      return __hazzerBits == other.__hazzerBits
+          && (!hasState() || state == other.state);
+    }
+
+    @Override protected int computeHashCode() {
+      int result = hash(__hazzerBits);
+      if (hasState()) {
+        result = result * 31 + hash(state);
+      }
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<RunStateP:");
+      if (hasState()) {
+        builder.append(" state=").append(state);
+      }
+      builder.append('>');
+    }
+
+    public static RunStateP parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoClient.RunStateP(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static RunStateP fromMessageNano(com.google.protos.ipc.invalidation.NanoClient.RunStateP message) {
+      if (message == null) { return null; }
+      return new RunStateP(message.state);
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoClient.RunStateP toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoClient.RunStateP msg = new com.google.protos.ipc.invalidation.NanoClient.RunStateP();
+      msg.state = hasState() ? state : null;
+      return msg;
+    }
+  }
+
+  public static final class ExponentialBackoffState extends ProtoWrapper {
+    public static ExponentialBackoffState create(Integer currentMaxDelay,
+        Boolean inRetryMode) {
+      return new ExponentialBackoffState(currentMaxDelay, inRetryMode);
+    }
+
+    public static final ExponentialBackoffState DEFAULT_INSTANCE = new ExponentialBackoffState(null, null);
+
+    private final long __hazzerBits;
+    private final int currentMaxDelay;
+    private final boolean inRetryMode;
+
+    private ExponentialBackoffState(Integer currentMaxDelay,
+        Boolean inRetryMode) {
+      int hazzerBits = 0;
+      if (currentMaxDelay != null) {
+        hazzerBits |= 0x1;
+        this.currentMaxDelay = currentMaxDelay;
+      } else {
+        this.currentMaxDelay = 0;
+      }
+      if (inRetryMode != null) {
+        hazzerBits |= 0x2;
+        this.inRetryMode = inRetryMode;
+      } else {
+        this.inRetryMode = false;
+      }
+      this.__hazzerBits = hazzerBits;
+    }
+
+    public int getCurrentMaxDelay() { return currentMaxDelay; }
+    public boolean hasCurrentMaxDelay() { return (0x1 & __hazzerBits) != 0; }
+
+    public boolean getInRetryMode() { return inRetryMode; }
+    public boolean hasInRetryMode() { return (0x2 & __hazzerBits) != 0; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof ExponentialBackoffState)) { return false; }
+      ExponentialBackoffState other = (ExponentialBackoffState) obj;
+      return __hazzerBits == other.__hazzerBits
+          && (!hasCurrentMaxDelay() || currentMaxDelay == other.currentMaxDelay)
+          && (!hasInRetryMode() || inRetryMode == other.inRetryMode);
+    }
+
+    @Override protected int computeHashCode() {
+      int result = hash(__hazzerBits);
+      if (hasCurrentMaxDelay()) {
+        result = result * 31 + hash(currentMaxDelay);
+      }
+      if (hasInRetryMode()) {
+        result = result * 31 + hash(inRetryMode);
+      }
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<ExponentialBackoffState:");
+      if (hasCurrentMaxDelay()) {
+        builder.append(" current_max_delay=").append(currentMaxDelay);
+      }
+      if (hasInRetryMode()) {
+        builder.append(" in_retry_mode=").append(inRetryMode);
+      }
+      builder.append('>');
+    }
+
+    public static ExponentialBackoffState parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoClient.ExponentialBackoffState(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static ExponentialBackoffState fromMessageNano(com.google.protos.ipc.invalidation.NanoClient.ExponentialBackoffState message) {
+      if (message == null) { return null; }
+      return new ExponentialBackoffState(message.currentMaxDelay,
+          message.inRetryMode);
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoClient.ExponentialBackoffState toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoClient.ExponentialBackoffState msg = new com.google.protos.ipc.invalidation.NanoClient.ExponentialBackoffState();
+      msg.currentMaxDelay = hasCurrentMaxDelay() ? currentMaxDelay : null;
+      msg.inRetryMode = hasInRetryMode() ? inRetryMode : null;
+      return msg;
+    }
+  }
+}
diff --git a/java/com/google/ipc/invalidation/ticl/proto/ClientConstants.java b/java/com/google/ipc/invalidation/ticl/proto/ClientConstants.java
new file mode 100644
index 0000000..9612e40
--- /dev/null
+++ b/java/com/google/ipc/invalidation/ticl/proto/ClientConstants.java
@@ -0,0 +1,55 @@
+/*
+ * 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.proto;
+
+import com.google.ipc.invalidation.common.BaseCommonInvalidationConstants;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.ProtocolVersion;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version;
+import com.google.ipc.invalidation.util.Bytes;
+
+/** Various constant protobufs used in version 2 of the Ticl. */
+public class ClientConstants extends BaseCommonInvalidationConstants {
+
+  /** Version of the client currently being used by the client. */
+  public static final Version CLIENT_VERSION_VALUE;
+
+  /** Version of the protocol currently being used by the client/server for v2 clients. */
+  public static final ProtocolVersion PROTOCOL_VERSION;
+
+  /** Version of the protocol currently being used by the client/server for v1 clients. */
+  public static final ProtocolVersion PROTOCOL_VERSION_V1;
+
+  /** The value of ObjectSource.Type from types.proto. Must be kept in sync with that file. */
+  public static final int INTERNAL_OBJECT_SOURCE_TYPE;
+
+  /** Object id used to trigger a refresh of all cached objects ("invalidate-all"). */
+  public static final ObjectIdP ALL_OBJECT_ID;
+
+  static {
+    CLIENT_VERSION_VALUE = Version.create(CLIENT_MAJOR_VERSION, CLIENT_MINOR_VERSION);
+    PROTOCOL_VERSION =
+        ProtocolVersion.create(Version.create(PROTOCOL_MAJOR_VERSION, PROTOCOL_MINOR_VERSION));
+    PROTOCOL_VERSION_V1 =
+        ProtocolVersion.create(Version.create(2, 0));
+    INTERNAL_OBJECT_SOURCE_TYPE = 1;
+    ALL_OBJECT_ID = ObjectIdP.create(INTERNAL_OBJECT_SOURCE_TYPE, Bytes.EMPTY_BYTES);
+  }
+
+  // Prevent instantiation.
+  private ClientConstants() {
+  }
+}
diff --git a/java/com/google/ipc/invalidation/ticl/proto/ClientProtocol.java b/java/com/google/ipc/invalidation/ticl/proto/ClientProtocol.java
new file mode 100644
index 0000000..95b876b
--- /dev/null
+++ b/java/com/google/ipc/invalidation/ticl/proto/ClientProtocol.java
@@ -0,0 +1,3171 @@
+/*
+ * 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.
+ */
+// Generated by j/c/g/ipc/invalidation/common/proto_wrapper_generator
+package com.google.ipc.invalidation.ticl.proto;
+
+import com.google.ipc.invalidation.util.Bytes;
+import com.google.ipc.invalidation.util.ProtoWrapper;
+import com.google.ipc.invalidation.util.ProtoWrapper.ValidationException;
+import com.google.ipc.invalidation.util.TextBuilder;
+import com.google.protobuf.nano.MessageNano;
+import com.google.protobuf.nano.InvalidProtocolBufferNanoException;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+
+public interface ClientProtocol {
+
+  public static final class Version extends ProtoWrapper {
+    public static Version create(int majorVersion,
+        int minorVersion) {
+      return new Version(majorVersion, minorVersion);
+    }
+
+    private final int majorVersion;
+    private final int minorVersion;
+
+    private Version(Integer majorVersion,
+        Integer minorVersion) throws ValidationArgumentException {
+      required("major_version", majorVersion);
+      nonNegative("major_version", majorVersion);
+      this.majorVersion = majorVersion;
+      required("minor_version", minorVersion);
+      nonNegative("minor_version", minorVersion);
+      this.minorVersion = minorVersion;
+    }
+
+    public int getMajorVersion() { return majorVersion; }
+
+    public int getMinorVersion() { return minorVersion; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof Version)) { return false; }
+      Version other = (Version) obj;
+      return majorVersion == other.majorVersion
+          && minorVersion == other.minorVersion;
+    }
+
+    @Override protected int computeHashCode() {
+      int result = 1;
+      result = result * 31 + hash(majorVersion);
+      result = result * 31 + hash(minorVersion);
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<Version:");
+      builder.append(" major_version=").append(majorVersion);
+      builder.append(" minor_version=").append(minorVersion);
+      builder.append('>');
+    }
+
+    public static Version parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoClientProtocol.Version(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static Version fromMessageNano(com.google.protos.ipc.invalidation.NanoClientProtocol.Version message) {
+      if (message == null) { return null; }
+      return new Version(message.majorVersion,
+          message.minorVersion);
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoClientProtocol.Version toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoClientProtocol.Version msg = new com.google.protos.ipc.invalidation.NanoClientProtocol.Version();
+      msg.majorVersion = majorVersion;
+      msg.minorVersion = minorVersion;
+      return msg;
+    }
+  }
+
+  public static final class ProtocolVersion extends ProtoWrapper {
+    public static ProtocolVersion create(com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version version) {
+      return new ProtocolVersion(version);
+    }
+
+    private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version version;
+
+    private ProtocolVersion(com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version version) throws ValidationArgumentException {
+      required("version", version);
+      this.version = version;
+    }
+
+    public com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version getVersion() { return version; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof ProtocolVersion)) { return false; }
+      ProtocolVersion other = (ProtocolVersion) obj;
+      return equals(version, other.version);
+    }
+
+    @Override protected int computeHashCode() {
+      int result = 1;
+      result = result * 31 + version.hashCode();
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<ProtocolVersion:");
+      builder.append(" version=").append(version);
+      builder.append('>');
+    }
+
+    public static ProtocolVersion parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoClientProtocol.ProtocolVersion(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static ProtocolVersion fromMessageNano(com.google.protos.ipc.invalidation.NanoClientProtocol.ProtocolVersion message) {
+      if (message == null) { return null; }
+      return new ProtocolVersion(com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version.fromMessageNano(message.version));
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoClientProtocol.ProtocolVersion toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoClientProtocol.ProtocolVersion msg = new com.google.protos.ipc.invalidation.NanoClientProtocol.ProtocolVersion();
+      msg.version = version.toMessageNano();
+      return msg;
+    }
+  }
+
+  public static final class ClientVersion extends ProtoWrapper {
+    public static ClientVersion create(com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version version,
+        String platform,
+        String language,
+        String applicationInfo) {
+      return new ClientVersion(version, platform, language, applicationInfo);
+    }
+
+    private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version version;
+    private final String platform;
+    private final String language;
+    private final String applicationInfo;
+
+    private ClientVersion(com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version version,
+        String platform,
+        String language,
+        String applicationInfo) throws ValidationArgumentException {
+      required("version", version);
+      this.version = version;
+      required("platform", platform);
+      this.platform = platform;
+      required("language", language);
+      this.language = language;
+      required("application_info", applicationInfo);
+      this.applicationInfo = applicationInfo;
+    }
+
+    public com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version getVersion() { return version; }
+
+    public String getPlatform() { return platform; }
+
+    public String getLanguage() { return language; }
+
+    public String getApplicationInfo() { return applicationInfo; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof ClientVersion)) { return false; }
+      ClientVersion other = (ClientVersion) obj;
+      return equals(version, other.version)
+          && equals(platform, other.platform)
+          && equals(language, other.language)
+          && equals(applicationInfo, other.applicationInfo);
+    }
+
+    @Override protected int computeHashCode() {
+      int result = 1;
+      result = result * 31 + version.hashCode();
+      result = result * 31 + platform.hashCode();
+      result = result * 31 + language.hashCode();
+      result = result * 31 + applicationInfo.hashCode();
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<ClientVersion:");
+      builder.append(" version=").append(version);
+      builder.append(" platform=").append(platform);
+      builder.append(" language=").append(language);
+      builder.append(" application_info=").append(applicationInfo);
+      builder.append('>');
+    }
+
+    public static ClientVersion parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoClientProtocol.ClientVersion(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static ClientVersion fromMessageNano(com.google.protos.ipc.invalidation.NanoClientProtocol.ClientVersion message) {
+      if (message == null) { return null; }
+      return new ClientVersion(com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version.fromMessageNano(message.version),
+          message.platform,
+          message.language,
+          message.applicationInfo);
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoClientProtocol.ClientVersion toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoClientProtocol.ClientVersion msg = new com.google.protos.ipc.invalidation.NanoClientProtocol.ClientVersion();
+      msg.version = version.toMessageNano();
+      msg.platform = platform;
+      msg.language = language;
+      msg.applicationInfo = applicationInfo;
+      return msg;
+    }
+  }
+
+  public static final class StatusP extends ProtoWrapper {
+    public interface Code {
+      public static final int SUCCESS = 1;
+      public static final int TRANSIENT_FAILURE = 2;
+      public static final int PERMANENT_FAILURE = 3;
+    }
+
+    public static StatusP create(int code,
+        String description) {
+      return new StatusP(code, description);
+    }
+
+    private final long __hazzerBits;
+    private final int code;
+    private final String description;
+
+    private StatusP(Integer code,
+        String description) throws ValidationArgumentException {
+      int hazzerBits = 0;
+      required("code", code);
+      this.code = code;
+      if (description != null) {
+        hazzerBits |= 0x1;
+        this.description = description;
+      } else {
+        this.description = "";
+      }
+      this.__hazzerBits = hazzerBits;
+    }
+
+    public int getCode() { return code; }
+
+    public String getDescription() { return description; }
+    public boolean hasDescription() { return (0x1 & __hazzerBits) != 0; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof StatusP)) { return false; }
+      StatusP other = (StatusP) obj;
+      return __hazzerBits == other.__hazzerBits
+          && code == other.code
+          && (!hasDescription() || equals(description, other.description));
+    }
+
+    @Override protected int computeHashCode() {
+      int result = hash(__hazzerBits);
+      result = result * 31 + hash(code);
+      if (hasDescription()) {
+        result = result * 31 + description.hashCode();
+      }
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<StatusP:");
+      builder.append(" code=").append(code);
+      if (hasDescription()) {
+        builder.append(" description=").append(description);
+      }
+      builder.append('>');
+    }
+
+    public static StatusP parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoClientProtocol.StatusP(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static StatusP fromMessageNano(com.google.protos.ipc.invalidation.NanoClientProtocol.StatusP message) {
+      if (message == null) { return null; }
+      return new StatusP(message.code,
+          message.description);
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoClientProtocol.StatusP toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoClientProtocol.StatusP msg = new com.google.protos.ipc.invalidation.NanoClientProtocol.StatusP();
+      msg.code = code;
+      msg.description = hasDescription() ? description : null;
+      return msg;
+    }
+  }
+
+  public static final class ObjectIdP extends ProtoWrapper {
+    public static ObjectIdP create(int source,
+        Bytes name) {
+      return new ObjectIdP(source, name);
+    }
+
+    private final int source;
+    private final Bytes name;
+
+    private ObjectIdP(Integer source,
+        Bytes name) throws ValidationArgumentException {
+      required("source", source);
+      nonNegative("source", source);
+      this.source = source;
+      required("name", name);
+      this.name = name;
+    }
+
+    public int getSource() { return source; }
+
+    public Bytes getName() { return name; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof ObjectIdP)) { return false; }
+      ObjectIdP other = (ObjectIdP) obj;
+      return source == other.source
+          && equals(name, other.name);
+    }
+
+    @Override protected int computeHashCode() {
+      int result = 1;
+      result = result * 31 + hash(source);
+      result = result * 31 + name.hashCode();
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<ObjectIdP:");
+      builder.append(" source=").append(source);
+      builder.append(" name=").append(name);
+      builder.append('>');
+    }
+
+    public static ObjectIdP parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoClientProtocol.ObjectIdP(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static ObjectIdP fromMessageNano(com.google.protos.ipc.invalidation.NanoClientProtocol.ObjectIdP message) {
+      if (message == null) { return null; }
+      return new ObjectIdP(message.source,
+          Bytes.fromByteArray(message.name));
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoClientProtocol.ObjectIdP toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoClientProtocol.ObjectIdP msg = new com.google.protos.ipc.invalidation.NanoClientProtocol.ObjectIdP();
+      msg.source = source;
+      msg.name = name.getByteArray();
+      return msg;
+    }
+  }
+
+  public static final class ApplicationClientIdP extends ProtoWrapper {
+    public static ApplicationClientIdP create(Integer clientType,
+        Bytes clientName) {
+      return new ApplicationClientIdP(clientType, clientName);
+    }
+
+    private final long __hazzerBits;
+    private final int clientType;
+    private final Bytes clientName;
+
+    private ApplicationClientIdP(Integer clientType,
+        Bytes clientName) throws ValidationArgumentException {
+      int hazzerBits = 0;
+      if (clientType != null) {
+        hazzerBits |= 0x1;
+        this.clientType = clientType;
+      } else {
+        this.clientType = 0;
+      }
+      required("client_name", clientName);
+      nonEmpty("client_name", clientName);
+      this.clientName = clientName;
+      this.__hazzerBits = hazzerBits;
+    }
+
+    public int getClientType() { return clientType; }
+    public boolean hasClientType() { return (0x1 & __hazzerBits) != 0; }
+
+    public Bytes getClientName() { return clientName; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof ApplicationClientIdP)) { return false; }
+      ApplicationClientIdP other = (ApplicationClientIdP) obj;
+      return __hazzerBits == other.__hazzerBits
+          && (!hasClientType() || clientType == other.clientType)
+          && equals(clientName, other.clientName);
+    }
+
+    @Override protected int computeHashCode() {
+      int result = hash(__hazzerBits);
+      if (hasClientType()) {
+        result = result * 31 + hash(clientType);
+      }
+      result = result * 31 + clientName.hashCode();
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<ApplicationClientIdP:");
+      if (hasClientType()) {
+        builder.append(" client_type=").append(clientType);
+      }
+      builder.append(" client_name=").append(clientName);
+      builder.append('>');
+    }
+
+    public static ApplicationClientIdP parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoClientProtocol.ApplicationClientIdP(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static ApplicationClientIdP fromMessageNano(com.google.protos.ipc.invalidation.NanoClientProtocol.ApplicationClientIdP message) {
+      if (message == null) { return null; }
+      return new ApplicationClientIdP(message.clientType,
+          Bytes.fromByteArray(message.clientName));
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoClientProtocol.ApplicationClientIdP toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoClientProtocol.ApplicationClientIdP msg = new com.google.protos.ipc.invalidation.NanoClientProtocol.ApplicationClientIdP();
+      msg.clientType = hasClientType() ? clientType : null;
+      msg.clientName = clientName.getByteArray();
+      return msg;
+    }
+  }
+
+  public static final class InvalidationP extends ProtoWrapper {
+    public static final class Builder {
+      public com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP objectId;
+      public boolean isKnownVersion;
+      public long version;
+      public Bytes payload;
+      public Long bridgeArrivalTimeMsDeprecated;
+      public Boolean isTrickleRestart;
+      public Builder(com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP objectId,
+          boolean isKnownVersion,
+          long version) {
+        this.objectId = objectId;this.isKnownVersion = isKnownVersion;this.version = version;}
+
+      public InvalidationP build() {
+        return new InvalidationP(objectId, isKnownVersion, version, payload, bridgeArrivalTimeMsDeprecated, isTrickleRestart);
+      }
+    }
+
+    public static InvalidationP create(com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP objectId,
+        boolean isKnownVersion,
+        long version,
+        Bytes payload,
+        Long bridgeArrivalTimeMsDeprecated,
+        Boolean isTrickleRestart) {
+      return new InvalidationP(objectId, isKnownVersion, version, payload, bridgeArrivalTimeMsDeprecated, isTrickleRestart);
+    }
+
+    private final long __hazzerBits;
+    private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP objectId;
+    private final boolean isKnownVersion;
+    private final long version;
+    private final boolean isTrickleRestart;
+    private final Bytes payload;
+    private final long bridgeArrivalTimeMsDeprecated;
+
+    private InvalidationP(com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP objectId,
+        Boolean isKnownVersion,
+        Long version,
+        Bytes payload,
+        Long bridgeArrivalTimeMsDeprecated,
+        Boolean isTrickleRestart) throws ValidationArgumentException {
+      int hazzerBits = 0;
+      required("object_id", objectId);
+      this.objectId = objectId;
+      required("is_known_version", isKnownVersion);
+      this.isKnownVersion = isKnownVersion;
+      required("version", version);
+      nonNegative("version", version);
+      this.version = version;
+      if (isTrickleRestart != null) {
+        hazzerBits |= 0x1;
+        this.isTrickleRestart = isTrickleRestart;
+      } else {
+        this.isTrickleRestart = true;
+      }
+      if (payload != null) {
+        hazzerBits |= 0x2;
+        this.payload = payload;
+      } else {
+        this.payload = Bytes.EMPTY_BYTES;
+      }
+      if (bridgeArrivalTimeMsDeprecated != null) {
+        hazzerBits |= 0x4;
+        this.bridgeArrivalTimeMsDeprecated = bridgeArrivalTimeMsDeprecated;
+      } else {
+        this.bridgeArrivalTimeMsDeprecated = 0;
+      }
+      this.__hazzerBits = hazzerBits;
+      check(isKnownVersion || (isTrickleRestart == null || isTrickleRestart),
+          "is_trickle_restart required if not is_known_version");
+    }
+
+    public com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP getObjectId() { return objectId; }
+
+    public boolean getIsKnownVersion() { return isKnownVersion; }
+
+    public long getVersion() { return version; }
+
+    public boolean getIsTrickleRestart() { return isTrickleRestart; }
+    public boolean hasIsTrickleRestart() { return (0x1 & __hazzerBits) != 0; }
+
+    public Bytes getPayload() { return payload; }
+    public boolean hasPayload() { return (0x2 & __hazzerBits) != 0; }
+
+    public long getBridgeArrivalTimeMsDeprecated() { return bridgeArrivalTimeMsDeprecated; }
+    public boolean hasBridgeArrivalTimeMsDeprecated() { return (0x4 & __hazzerBits) != 0; }
+
+    public Builder toBuilder() {
+      Builder builder = new Builder(objectId, isKnownVersion, version);
+      if (hasPayload()) {
+        builder.payload = payload;
+      }
+      if (hasBridgeArrivalTimeMsDeprecated()) {
+        builder.bridgeArrivalTimeMsDeprecated = bridgeArrivalTimeMsDeprecated;
+      }
+      if (hasIsTrickleRestart()) {
+        builder.isTrickleRestart = isTrickleRestart;
+      }
+      return builder;
+    }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof InvalidationP)) { return false; }
+      InvalidationP other = (InvalidationP) obj;
+      return __hazzerBits == other.__hazzerBits
+          && equals(objectId, other.objectId)
+          && isKnownVersion == other.isKnownVersion
+          && version == other.version
+          && (!hasIsTrickleRestart() || isTrickleRestart == other.isTrickleRestart)
+          && (!hasPayload() || equals(payload, other.payload))
+          && (!hasBridgeArrivalTimeMsDeprecated() || bridgeArrivalTimeMsDeprecated == other.bridgeArrivalTimeMsDeprecated);
+    }
+
+    @Override protected int computeHashCode() {
+      int result = hash(__hazzerBits);
+      result = result * 31 + objectId.hashCode();
+      result = result * 31 + hash(isKnownVersion);
+      result = result * 31 + hash(version);
+      if (hasIsTrickleRestart()) {
+        result = result * 31 + hash(isTrickleRestart);
+      }
+      if (hasPayload()) {
+        result = result * 31 + payload.hashCode();
+      }
+      if (hasBridgeArrivalTimeMsDeprecated()) {
+        result = result * 31 + hash(bridgeArrivalTimeMsDeprecated);
+      }
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<InvalidationP:");
+      builder.append(" object_id=").append(objectId);
+      builder.append(" is_known_version=").append(isKnownVersion);
+      builder.append(" version=").append(version);
+      if (hasIsTrickleRestart()) {
+        builder.append(" is_trickle_restart=").append(isTrickleRestart);
+      }
+      if (hasPayload()) {
+        builder.append(" payload=").append(payload);
+      }
+      if (hasBridgeArrivalTimeMsDeprecated()) {
+        builder.append(" bridge_arrival_time_ms_deprecated=").append(bridgeArrivalTimeMsDeprecated);
+      }
+      builder.append('>');
+    }
+
+    public static InvalidationP parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoClientProtocol.InvalidationP(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static InvalidationP fromMessageNano(com.google.protos.ipc.invalidation.NanoClientProtocol.InvalidationP message) {
+      if (message == null) { return null; }
+      return new InvalidationP(com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP.fromMessageNano(message.objectId),
+          message.isKnownVersion,
+          message.version,
+          Bytes.fromByteArray(message.payload),
+          message.bridgeArrivalTimeMsDeprecated,
+          message.isTrickleRestart);
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoClientProtocol.InvalidationP toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoClientProtocol.InvalidationP msg = new com.google.protos.ipc.invalidation.NanoClientProtocol.InvalidationP();
+      msg.objectId = objectId.toMessageNano();
+      msg.isKnownVersion = isKnownVersion;
+      msg.version = version;
+      msg.isTrickleRestart = hasIsTrickleRestart() ? isTrickleRestart : null;
+      msg.payload = hasPayload() ? payload.getByteArray() : null;
+      msg.bridgeArrivalTimeMsDeprecated = hasBridgeArrivalTimeMsDeprecated() ? bridgeArrivalTimeMsDeprecated : null;
+      return msg;
+    }
+  }
+
+  public static final class RegistrationP extends ProtoWrapper {
+    public interface OpType {
+      public static final int REGISTER = 1;
+      public static final int UNREGISTER = 2;
+    }
+
+    public static RegistrationP create(com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP objectId,
+        int opType) {
+      return new RegistrationP(objectId, opType);
+    }
+
+    private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP objectId;
+    private final int opType;
+
+    private RegistrationP(com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP objectId,
+        Integer opType) throws ValidationArgumentException {
+      required("object_id", objectId);
+      this.objectId = objectId;
+      required("op_type", opType);
+      this.opType = opType;
+    }
+
+    public com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP getObjectId() { return objectId; }
+
+    public int getOpType() { return opType; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof RegistrationP)) { return false; }
+      RegistrationP other = (RegistrationP) obj;
+      return equals(objectId, other.objectId)
+          && opType == other.opType;
+    }
+
+    @Override protected int computeHashCode() {
+      int result = 1;
+      result = result * 31 + objectId.hashCode();
+      result = result * 31 + hash(opType);
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<RegistrationP:");
+      builder.append(" object_id=").append(objectId);
+      builder.append(" op_type=").append(opType);
+      builder.append('>');
+    }
+
+    public static RegistrationP parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoClientProtocol.RegistrationP(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static RegistrationP fromMessageNano(com.google.protos.ipc.invalidation.NanoClientProtocol.RegistrationP message) {
+      if (message == null) { return null; }
+      return new RegistrationP(com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP.fromMessageNano(message.objectId),
+          message.opType);
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoClientProtocol.RegistrationP toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoClientProtocol.RegistrationP msg = new com.google.protos.ipc.invalidation.NanoClientProtocol.RegistrationP();
+      msg.objectId = objectId.toMessageNano();
+      msg.opType = opType;
+      return msg;
+    }
+  }
+
+  public static final class RegistrationSummary extends ProtoWrapper {
+    public static RegistrationSummary create(int numRegistrations,
+        Bytes registrationDigest) {
+      return new RegistrationSummary(numRegistrations, registrationDigest);
+    }
+
+    private final int numRegistrations;
+    private final Bytes registrationDigest;
+
+    private RegistrationSummary(Integer numRegistrations,
+        Bytes registrationDigest) throws ValidationArgumentException {
+      required("num_registrations", numRegistrations);
+      nonNegative("num_registrations", numRegistrations);
+      this.numRegistrations = numRegistrations;
+      required("registration_digest", registrationDigest);
+      nonEmpty("registration_digest", registrationDigest);
+      this.registrationDigest = registrationDigest;
+    }
+
+    public int getNumRegistrations() { return numRegistrations; }
+
+    public Bytes getRegistrationDigest() { return registrationDigest; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof RegistrationSummary)) { return false; }
+      RegistrationSummary other = (RegistrationSummary) obj;
+      return numRegistrations == other.numRegistrations
+          && equals(registrationDigest, other.registrationDigest);
+    }
+
+    @Override protected int computeHashCode() {
+      int result = 1;
+      result = result * 31 + hash(numRegistrations);
+      result = result * 31 + registrationDigest.hashCode();
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<RegistrationSummary:");
+      builder.append(" num_registrations=").append(numRegistrations);
+      builder.append(" registration_digest=").append(registrationDigest);
+      builder.append('>');
+    }
+
+    public static RegistrationSummary parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoClientProtocol.RegistrationSummary(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static RegistrationSummary fromMessageNano(com.google.protos.ipc.invalidation.NanoClientProtocol.RegistrationSummary message) {
+      if (message == null) { return null; }
+      return new RegistrationSummary(message.numRegistrations,
+          Bytes.fromByteArray(message.registrationDigest));
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoClientProtocol.RegistrationSummary toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoClientProtocol.RegistrationSummary msg = new com.google.protos.ipc.invalidation.NanoClientProtocol.RegistrationSummary();
+      msg.numRegistrations = numRegistrations;
+      msg.registrationDigest = registrationDigest.getByteArray();
+      return msg;
+    }
+  }
+
+  public static final class ClientHeader extends ProtoWrapper {
+    public static ClientHeader create(com.google.ipc.invalidation.ticl.proto.ClientProtocol.ProtocolVersion protocolVersion,
+        Bytes clientToken,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSummary registrationSummary,
+        long clientTimeMs,
+        long maxKnownServerTimeMs,
+        String messageId,
+        Integer clientType) {
+      return new ClientHeader(protocolVersion, clientToken, registrationSummary, clientTimeMs, maxKnownServerTimeMs, messageId, clientType);
+    }
+
+    private final long __hazzerBits;
+    private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.ProtocolVersion protocolVersion;
+    private final Bytes clientToken;
+    private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSummary registrationSummary;
+    private final long clientTimeMs;
+    private final long maxKnownServerTimeMs;
+    private final String messageId;
+    private final int clientType;
+
+    private ClientHeader(com.google.ipc.invalidation.ticl.proto.ClientProtocol.ProtocolVersion protocolVersion,
+        Bytes clientToken,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSummary registrationSummary,
+        Long clientTimeMs,
+        Long maxKnownServerTimeMs,
+        String messageId,
+        Integer clientType) throws ValidationArgumentException {
+      int hazzerBits = 0;
+      required("protocol_version", protocolVersion);
+      this.protocolVersion = protocolVersion;
+      if (clientToken != null) {
+        hazzerBits |= 0x1;
+        nonEmpty("client_token", clientToken);
+        this.clientToken = clientToken;
+      } else {
+        this.clientToken = Bytes.EMPTY_BYTES;
+      }
+      this.registrationSummary = registrationSummary;
+      required("client_time_ms", clientTimeMs);
+      nonNegative("client_time_ms", clientTimeMs);
+      this.clientTimeMs = clientTimeMs;
+      required("max_known_server_time_ms", maxKnownServerTimeMs);
+      nonNegative("max_known_server_time_ms", maxKnownServerTimeMs);
+      this.maxKnownServerTimeMs = maxKnownServerTimeMs;
+      if (messageId != null) {
+        hazzerBits |= 0x2;
+        nonEmpty("message_id", messageId);
+        this.messageId = messageId;
+      } else {
+        this.messageId = "";
+      }
+      if (clientType != null) {
+        hazzerBits |= 0x4;
+        this.clientType = clientType;
+      } else {
+        this.clientType = 0;
+      }
+      this.__hazzerBits = hazzerBits;
+    }
+
+    public com.google.ipc.invalidation.ticl.proto.ClientProtocol.ProtocolVersion getProtocolVersion() { return protocolVersion; }
+
+    public Bytes getClientToken() { return clientToken; }
+    public boolean hasClientToken() { return (0x1 & __hazzerBits) != 0; }
+
+    public com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSummary getNullableRegistrationSummary() { return registrationSummary; }
+
+    public long getClientTimeMs() { return clientTimeMs; }
+
+    public long getMaxKnownServerTimeMs() { return maxKnownServerTimeMs; }
+
+    public String getMessageId() { return messageId; }
+    public boolean hasMessageId() { return (0x2 & __hazzerBits) != 0; }
+
+    public int getClientType() { return clientType; }
+    public boolean hasClientType() { return (0x4 & __hazzerBits) != 0; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof ClientHeader)) { return false; }
+      ClientHeader other = (ClientHeader) obj;
+      return __hazzerBits == other.__hazzerBits
+          && equals(protocolVersion, other.protocolVersion)
+          && (!hasClientToken() || equals(clientToken, other.clientToken))
+          && equals(registrationSummary, other.registrationSummary)
+          && clientTimeMs == other.clientTimeMs
+          && maxKnownServerTimeMs == other.maxKnownServerTimeMs
+          && (!hasMessageId() || equals(messageId, other.messageId))
+          && (!hasClientType() || clientType == other.clientType);
+    }
+
+    @Override protected int computeHashCode() {
+      int result = hash(__hazzerBits);
+      result = result * 31 + protocolVersion.hashCode();
+      if (hasClientToken()) {
+        result = result * 31 + clientToken.hashCode();
+      }
+      if (registrationSummary != null) {
+        result = result * 31 + registrationSummary.hashCode();
+      }
+      result = result * 31 + hash(clientTimeMs);
+      result = result * 31 + hash(maxKnownServerTimeMs);
+      if (hasMessageId()) {
+        result = result * 31 + messageId.hashCode();
+      }
+      if (hasClientType()) {
+        result = result * 31 + hash(clientType);
+      }
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<ClientHeader:");
+      builder.append(" protocol_version=").append(protocolVersion);
+      if (hasClientToken()) {
+        builder.append(" client_token=").append(clientToken);
+      }
+      if (registrationSummary != null) {
+        builder.append(" registration_summary=").append(registrationSummary);
+      }
+      builder.append(" client_time_ms=").append(clientTimeMs);
+      builder.append(" max_known_server_time_ms=").append(maxKnownServerTimeMs);
+      if (hasMessageId()) {
+        builder.append(" message_id=").append(messageId);
+      }
+      if (hasClientType()) {
+        builder.append(" client_type=").append(clientType);
+      }
+      builder.append('>');
+    }
+
+    public static ClientHeader parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoClientProtocol.ClientHeader(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static ClientHeader fromMessageNano(com.google.protos.ipc.invalidation.NanoClientProtocol.ClientHeader message) {
+      if (message == null) { return null; }
+      return new ClientHeader(com.google.ipc.invalidation.ticl.proto.ClientProtocol.ProtocolVersion.fromMessageNano(message.protocolVersion),
+          Bytes.fromByteArray(message.clientToken),
+          com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSummary.fromMessageNano(message.registrationSummary),
+          message.clientTimeMs,
+          message.maxKnownServerTimeMs,
+          message.messageId,
+          message.clientType);
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoClientProtocol.ClientHeader toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoClientProtocol.ClientHeader msg = new com.google.protos.ipc.invalidation.NanoClientProtocol.ClientHeader();
+      msg.protocolVersion = protocolVersion.toMessageNano();
+      msg.clientToken = hasClientToken() ? clientToken.getByteArray() : null;
+      msg.registrationSummary = this.registrationSummary != null ? registrationSummary.toMessageNano() : null;
+      msg.clientTimeMs = clientTimeMs;
+      msg.maxKnownServerTimeMs = maxKnownServerTimeMs;
+      msg.messageId = hasMessageId() ? messageId : null;
+      msg.clientType = hasClientType() ? clientType : null;
+      return msg;
+    }
+  }
+
+  public static final class ClientToServerMessage extends ProtoWrapper {
+    public static ClientToServerMessage create(com.google.ipc.invalidation.ticl.proto.ClientProtocol.ClientHeader header,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.InitializeMessage initializeMessage,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationMessage registrationMessage,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSyncMessage registrationSyncMessage,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationMessage invalidationAckMessage,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.InfoMessage infoMessage) {
+      return new ClientToServerMessage(header, initializeMessage, registrationMessage, registrationSyncMessage, invalidationAckMessage, infoMessage);
+    }
+
+    private final long __hazzerBits;
+    private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.ClientHeader header;
+    private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.InitializeMessage initializeMessage;
+    private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationMessage registrationMessage;
+    private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSyncMessage registrationSyncMessage;
+    private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationMessage invalidationAckMessage;
+    private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.InfoMessage infoMessage;
+
+    private ClientToServerMessage(com.google.ipc.invalidation.ticl.proto.ClientProtocol.ClientHeader header,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.InitializeMessage initializeMessage,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationMessage registrationMessage,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSyncMessage registrationSyncMessage,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationMessage invalidationAckMessage,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.InfoMessage infoMessage) throws ValidationArgumentException {
+      int hazzerBits = 0;
+      required("header", header);
+      this.header = header;
+      this.initializeMessage = initializeMessage;
+      this.registrationMessage = registrationMessage;
+      this.registrationSyncMessage = registrationSyncMessage;
+      this.invalidationAckMessage = invalidationAckMessage;
+      if (infoMessage != null) {
+        hazzerBits |= 0x1;
+        this.infoMessage = infoMessage;
+      } else {
+        this.infoMessage = com.google.ipc.invalidation.ticl.proto.ClientProtocol.InfoMessage.DEFAULT_INSTANCE;
+      }
+      this.__hazzerBits = hazzerBits;
+      check((initializeMessage != null) ^ header.hasClientToken(), 
+          "There should either be a client token or an initialization request");
+    }
+
+    public com.google.ipc.invalidation.ticl.proto.ClientProtocol.ClientHeader getHeader() { return header; }
+
+    public com.google.ipc.invalidation.ticl.proto.ClientProtocol.InitializeMessage getNullableInitializeMessage() { return initializeMessage; }
+
+    public com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationMessage getNullableRegistrationMessage() { return registrationMessage; }
+
+    public com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSyncMessage getNullableRegistrationSyncMessage() { return registrationSyncMessage; }
+
+    public com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationMessage getNullableInvalidationAckMessage() { return invalidationAckMessage; }
+
+    public com.google.ipc.invalidation.ticl.proto.ClientProtocol.InfoMessage getInfoMessage() { return infoMessage; }
+    public boolean hasInfoMessage() { return (0x1 & __hazzerBits) != 0; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof ClientToServerMessage)) { return false; }
+      ClientToServerMessage other = (ClientToServerMessage) obj;
+      return __hazzerBits == other.__hazzerBits
+          && equals(header, other.header)
+          && equals(initializeMessage, other.initializeMessage)
+          && equals(registrationMessage, other.registrationMessage)
+          && equals(registrationSyncMessage, other.registrationSyncMessage)
+          && equals(invalidationAckMessage, other.invalidationAckMessage)
+          && (!hasInfoMessage() || equals(infoMessage, other.infoMessage));
+    }
+
+    @Override protected int computeHashCode() {
+      int result = hash(__hazzerBits);
+      result = result * 31 + header.hashCode();
+      if (initializeMessage != null) {
+        result = result * 31 + initializeMessage.hashCode();
+      }
+      if (registrationMessage != null) {
+        result = result * 31 + registrationMessage.hashCode();
+      }
+      if (registrationSyncMessage != null) {
+        result = result * 31 + registrationSyncMessage.hashCode();
+      }
+      if (invalidationAckMessage != null) {
+        result = result * 31 + invalidationAckMessage.hashCode();
+      }
+      if (hasInfoMessage()) {
+        result = result * 31 + infoMessage.hashCode();
+      }
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<ClientToServerMessage:");
+      builder.append(" header=").append(header);
+      if (initializeMessage != null) {
+        builder.append(" initialize_message=").append(initializeMessage);
+      }
+      if (registrationMessage != null) {
+        builder.append(" registration_message=").append(registrationMessage);
+      }
+      if (registrationSyncMessage != null) {
+        builder.append(" registration_sync_message=").append(registrationSyncMessage);
+      }
+      if (invalidationAckMessage != null) {
+        builder.append(" invalidation_ack_message=").append(invalidationAckMessage);
+      }
+      if (hasInfoMessage()) {
+        builder.append(" info_message=").append(infoMessage);
+      }
+      builder.append('>');
+    }
+
+    public static ClientToServerMessage parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoClientProtocol.ClientToServerMessage(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static ClientToServerMessage fromMessageNano(com.google.protos.ipc.invalidation.NanoClientProtocol.ClientToServerMessage message) {
+      if (message == null) { return null; }
+      return new ClientToServerMessage(com.google.ipc.invalidation.ticl.proto.ClientProtocol.ClientHeader.fromMessageNano(message.header),
+          com.google.ipc.invalidation.ticl.proto.ClientProtocol.InitializeMessage.fromMessageNano(message.initializeMessage),
+          com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationMessage.fromMessageNano(message.registrationMessage),
+          com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSyncMessage.fromMessageNano(message.registrationSyncMessage),
+          com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationMessage.fromMessageNano(message.invalidationAckMessage),
+          com.google.ipc.invalidation.ticl.proto.ClientProtocol.InfoMessage.fromMessageNano(message.infoMessage));
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoClientProtocol.ClientToServerMessage toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoClientProtocol.ClientToServerMessage msg = new com.google.protos.ipc.invalidation.NanoClientProtocol.ClientToServerMessage();
+      msg.header = header.toMessageNano();
+      msg.initializeMessage = this.initializeMessage != null ? initializeMessage.toMessageNano() : null;
+      msg.registrationMessage = this.registrationMessage != null ? registrationMessage.toMessageNano() : null;
+      msg.registrationSyncMessage = this.registrationSyncMessage != null ? registrationSyncMessage.toMessageNano() : null;
+      msg.invalidationAckMessage = this.invalidationAckMessage != null ? invalidationAckMessage.toMessageNano() : null;
+      msg.infoMessage = hasInfoMessage() ? infoMessage.toMessageNano() : null;
+      return msg;
+    }
+  }
+
+  public static final class InitializeMessage extends ProtoWrapper {
+    public interface DigestSerializationType {
+      public static final int BYTE_BASED = 1;
+      public static final int NUMBER_BASED = 2;
+    }
+
+    public static InitializeMessage create(int clientType,
+        Bytes nonce,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.ApplicationClientIdP applicationClientId,
+        int digestSerializationType) {
+      return new InitializeMessage(clientType, nonce, applicationClientId, digestSerializationType);
+    }
+
+    private final int clientType;
+    private final Bytes nonce;
+    private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.ApplicationClientIdP applicationClientId;
+    private final int digestSerializationType;
+
+    private InitializeMessage(Integer clientType,
+        Bytes nonce,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.ApplicationClientIdP applicationClientId,
+        Integer digestSerializationType) throws ValidationArgumentException {
+      required("client_type", clientType);
+      nonNegative("client_type", clientType);
+      this.clientType = clientType;
+      required("nonce", nonce);
+      this.nonce = nonce;
+      required("application_client_id", applicationClientId);
+      this.applicationClientId = applicationClientId;
+      required("digest_serialization_type", digestSerializationType);
+      this.digestSerializationType = digestSerializationType;
+    }
+
+    public int getClientType() { return clientType; }
+
+    public Bytes getNonce() { return nonce; }
+
+    public com.google.ipc.invalidation.ticl.proto.ClientProtocol.ApplicationClientIdP getApplicationClientId() { return applicationClientId; }
+
+    public int getDigestSerializationType() { return digestSerializationType; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof InitializeMessage)) { return false; }
+      InitializeMessage other = (InitializeMessage) obj;
+      return clientType == other.clientType
+          && equals(nonce, other.nonce)
+          && equals(applicationClientId, other.applicationClientId)
+          && digestSerializationType == other.digestSerializationType;
+    }
+
+    @Override protected int computeHashCode() {
+      int result = 1;
+      result = result * 31 + hash(clientType);
+      result = result * 31 + nonce.hashCode();
+      result = result * 31 + applicationClientId.hashCode();
+      result = result * 31 + hash(digestSerializationType);
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<InitializeMessage:");
+      builder.append(" client_type=").append(clientType);
+      builder.append(" nonce=").append(nonce);
+      builder.append(" application_client_id=").append(applicationClientId);
+      builder.append(" digest_serialization_type=").append(digestSerializationType);
+      builder.append('>');
+    }
+
+    public static InitializeMessage parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoClientProtocol.InitializeMessage(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static InitializeMessage fromMessageNano(com.google.protos.ipc.invalidation.NanoClientProtocol.InitializeMessage message) {
+      if (message == null) { return null; }
+      return new InitializeMessage(message.clientType,
+          Bytes.fromByteArray(message.nonce),
+          com.google.ipc.invalidation.ticl.proto.ClientProtocol.ApplicationClientIdP.fromMessageNano(message.applicationClientId),
+          message.digestSerializationType);
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoClientProtocol.InitializeMessage toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoClientProtocol.InitializeMessage msg = new com.google.protos.ipc.invalidation.NanoClientProtocol.InitializeMessage();
+      msg.clientType = clientType;
+      msg.nonce = nonce.getByteArray();
+      msg.applicationClientId = applicationClientId.toMessageNano();
+      msg.digestSerializationType = digestSerializationType;
+      return msg;
+    }
+  }
+
+  public static final class RegistrationMessage extends ProtoWrapper {
+    public static RegistrationMessage create(Collection<com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationP> registration) {
+      return new RegistrationMessage(registration);
+    }
+
+    private final List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationP> registration;
+
+    private RegistrationMessage(Collection<com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationP> registration) throws ValidationArgumentException {
+      this.registration = required("registration", registration);
+    }
+
+    public List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationP> getRegistration() { return registration; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof RegistrationMessage)) { return false; }
+      RegistrationMessage other = (RegistrationMessage) obj;
+      return equals(registration, other.registration);
+    }
+
+    @Override protected int computeHashCode() {
+      int result = 1;
+      result = result * 31 + registration.hashCode();
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<RegistrationMessage:");
+      builder.append(" registration=[").append(registration).append(']');
+      builder.append('>');
+    }
+
+    public static RegistrationMessage parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoClientProtocol.RegistrationMessage(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static RegistrationMessage fromMessageNano(com.google.protos.ipc.invalidation.NanoClientProtocol.RegistrationMessage message) {
+      if (message == null) { return null; }
+      List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationP> registration = new ArrayList<com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationP>(message.registration.length);
+      for (int i = 0; i < message.registration.length; i++) {
+        registration.add(com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationP.fromMessageNano(message.registration[i]));
+      }
+      return new RegistrationMessage(registration);
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoClientProtocol.RegistrationMessage toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoClientProtocol.RegistrationMessage msg = new com.google.protos.ipc.invalidation.NanoClientProtocol.RegistrationMessage();
+      msg.registration = new com.google.protos.ipc.invalidation.NanoClientProtocol.RegistrationP[registration.size()];
+      for (int i = 0; i < msg.registration.length; i++) {
+        msg.registration[i] = registration.get(i).toMessageNano();
+      }
+      return msg;
+    }
+  }
+
+  public static final class RegistrationSyncMessage extends ProtoWrapper {
+    public static RegistrationSyncMessage create(Collection<com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSubtree> subtree) {
+      return new RegistrationSyncMessage(subtree);
+    }
+
+    private final List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSubtree> subtree;
+
+    private RegistrationSyncMessage(Collection<com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSubtree> subtree) throws ValidationArgumentException {
+      this.subtree = required("subtree", subtree);
+    }
+
+    public List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSubtree> getSubtree() { return subtree; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof RegistrationSyncMessage)) { return false; }
+      RegistrationSyncMessage other = (RegistrationSyncMessage) obj;
+      return equals(subtree, other.subtree);
+    }
+
+    @Override protected int computeHashCode() {
+      int result = 1;
+      result = result * 31 + subtree.hashCode();
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<RegistrationSyncMessage:");
+      builder.append(" subtree=[").append(subtree).append(']');
+      builder.append('>');
+    }
+
+    public static RegistrationSyncMessage parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoClientProtocol.RegistrationSyncMessage(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static RegistrationSyncMessage fromMessageNano(com.google.protos.ipc.invalidation.NanoClientProtocol.RegistrationSyncMessage message) {
+      if (message == null) { return null; }
+      List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSubtree> subtree = new ArrayList<com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSubtree>(message.subtree.length);
+      for (int i = 0; i < message.subtree.length; i++) {
+        subtree.add(com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSubtree.fromMessageNano(message.subtree[i]));
+      }
+      return new RegistrationSyncMessage(subtree);
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoClientProtocol.RegistrationSyncMessage toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoClientProtocol.RegistrationSyncMessage msg = new com.google.protos.ipc.invalidation.NanoClientProtocol.RegistrationSyncMessage();
+      msg.subtree = new com.google.protos.ipc.invalidation.NanoClientProtocol.RegistrationSubtree[subtree.size()];
+      for (int i = 0; i < msg.subtree.length; i++) {
+        msg.subtree[i] = subtree.get(i).toMessageNano();
+      }
+      return msg;
+    }
+  }
+
+  public static final class RegistrationSubtree extends ProtoWrapper {
+    public static RegistrationSubtree create(Collection<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP> registeredObject) {
+      return new RegistrationSubtree(registeredObject);
+    }
+
+    public static final RegistrationSubtree DEFAULT_INSTANCE = new RegistrationSubtree(null);
+
+    private final List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP> registeredObject;
+
+    private RegistrationSubtree(Collection<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP> registeredObject) {
+      this.registeredObject = optional("registered_object", registeredObject);
+    }
+
+    public List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP> getRegisteredObject() { return registeredObject; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof RegistrationSubtree)) { return false; }
+      RegistrationSubtree other = (RegistrationSubtree) obj;
+      return equals(registeredObject, other.registeredObject);
+    }
+
+    @Override protected int computeHashCode() {
+      int result = 1;
+      result = result * 31 + registeredObject.hashCode();
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<RegistrationSubtree:");
+      builder.append(" registered_object=[").append(registeredObject).append(']');
+      builder.append('>');
+    }
+
+    public static RegistrationSubtree parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoClientProtocol.RegistrationSubtree(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static RegistrationSubtree fromMessageNano(com.google.protos.ipc.invalidation.NanoClientProtocol.RegistrationSubtree message) {
+      if (message == null) { return null; }
+      List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP> registeredObject = new ArrayList<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP>(message.registeredObject.length);
+      for (int i = 0; i < message.registeredObject.length; i++) {
+        registeredObject.add(com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP.fromMessageNano(message.registeredObject[i]));
+      }
+      return new RegistrationSubtree(registeredObject);
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoClientProtocol.RegistrationSubtree toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoClientProtocol.RegistrationSubtree msg = new com.google.protos.ipc.invalidation.NanoClientProtocol.RegistrationSubtree();
+      msg.registeredObject = new com.google.protos.ipc.invalidation.NanoClientProtocol.ObjectIdP[registeredObject.size()];
+      for (int i = 0; i < msg.registeredObject.length; i++) {
+        msg.registeredObject[i] = registeredObject.get(i).toMessageNano();
+      }
+      return msg;
+    }
+  }
+
+  public static final class InfoMessage extends ProtoWrapper {
+    public static InfoMessage create(com.google.ipc.invalidation.ticl.proto.ClientProtocol.ClientVersion clientVersion,
+        Collection<com.google.ipc.invalidation.ticl.proto.ClientProtocol.PropertyRecord> configParameter,
+        Collection<com.google.ipc.invalidation.ticl.proto.ClientProtocol.PropertyRecord> performanceCounter,
+        Boolean serverRegistrationSummaryRequested,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.ClientConfigP clientConfig) {
+      return new InfoMessage(clientVersion, configParameter, performanceCounter, serverRegistrationSummaryRequested, clientConfig);
+    }
+
+    public static final InfoMessage DEFAULT_INSTANCE = new InfoMessage(null, null, null, null, null);
+
+    private final long __hazzerBits;
+    private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.ClientVersion clientVersion;
+    private final List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.PropertyRecord> configParameter;
+    private final List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.PropertyRecord> performanceCounter;
+    private final boolean serverRegistrationSummaryRequested;
+    private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.ClientConfigP clientConfig;
+
+    private InfoMessage(com.google.ipc.invalidation.ticl.proto.ClientProtocol.ClientVersion clientVersion,
+        Collection<com.google.ipc.invalidation.ticl.proto.ClientProtocol.PropertyRecord> configParameter,
+        Collection<com.google.ipc.invalidation.ticl.proto.ClientProtocol.PropertyRecord> performanceCounter,
+        Boolean serverRegistrationSummaryRequested,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.ClientConfigP clientConfig) {
+      int hazzerBits = 0;
+      this.clientVersion = clientVersion;
+      this.configParameter = optional("config_parameter", configParameter);
+      this.performanceCounter = optional("performance_counter", performanceCounter);
+      if (serverRegistrationSummaryRequested != null) {
+        hazzerBits |= 0x1;
+        this.serverRegistrationSummaryRequested = serverRegistrationSummaryRequested;
+      } else {
+        this.serverRegistrationSummaryRequested = false;
+      }
+      this.clientConfig = clientConfig;
+      this.__hazzerBits = hazzerBits;
+    }
+
+    public com.google.ipc.invalidation.ticl.proto.ClientProtocol.ClientVersion getNullableClientVersion() { return clientVersion; }
+
+    public List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.PropertyRecord> getConfigParameter() { return configParameter; }
+
+    public List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.PropertyRecord> getPerformanceCounter() { return performanceCounter; }
+
+    public boolean getServerRegistrationSummaryRequested() { return serverRegistrationSummaryRequested; }
+    public boolean hasServerRegistrationSummaryRequested() { return (0x1 & __hazzerBits) != 0; }
+
+    public com.google.ipc.invalidation.ticl.proto.ClientProtocol.ClientConfigP getNullableClientConfig() { return clientConfig; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof InfoMessage)) { return false; }
+      InfoMessage other = (InfoMessage) obj;
+      return __hazzerBits == other.__hazzerBits
+          && equals(clientVersion, other.clientVersion)
+          && equals(configParameter, other.configParameter)
+          && equals(performanceCounter, other.performanceCounter)
+          && (!hasServerRegistrationSummaryRequested() || serverRegistrationSummaryRequested == other.serverRegistrationSummaryRequested)
+          && equals(clientConfig, other.clientConfig);
+    }
+
+    @Override protected int computeHashCode() {
+      int result = hash(__hazzerBits);
+      if (clientVersion != null) {
+        result = result * 31 + clientVersion.hashCode();
+      }
+      result = result * 31 + configParameter.hashCode();
+      result = result * 31 + performanceCounter.hashCode();
+      if (hasServerRegistrationSummaryRequested()) {
+        result = result * 31 + hash(serverRegistrationSummaryRequested);
+      }
+      if (clientConfig != null) {
+        result = result * 31 + clientConfig.hashCode();
+      }
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<InfoMessage:");
+      if (clientVersion != null) {
+        builder.append(" client_version=").append(clientVersion);
+      }
+      builder.append(" config_parameter=[").append(configParameter).append(']');
+      builder.append(" performance_counter=[").append(performanceCounter).append(']');
+      if (hasServerRegistrationSummaryRequested()) {
+        builder.append(" server_registration_summary_requested=").append(serverRegistrationSummaryRequested);
+      }
+      if (clientConfig != null) {
+        builder.append(" client_config=").append(clientConfig);
+      }
+      builder.append('>');
+    }
+
+    public static InfoMessage parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoClientProtocol.InfoMessage(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static InfoMessage fromMessageNano(com.google.protos.ipc.invalidation.NanoClientProtocol.InfoMessage message) {
+      if (message == null) { return null; }
+      List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.PropertyRecord> configParameter = new ArrayList<com.google.ipc.invalidation.ticl.proto.ClientProtocol.PropertyRecord>(message.configParameter.length);
+      for (int i = 0; i < message.configParameter.length; i++) {
+        configParameter.add(com.google.ipc.invalidation.ticl.proto.ClientProtocol.PropertyRecord.fromMessageNano(message.configParameter[i]));
+      }
+      List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.PropertyRecord> performanceCounter = new ArrayList<com.google.ipc.invalidation.ticl.proto.ClientProtocol.PropertyRecord>(message.performanceCounter.length);
+      for (int i = 0; i < message.performanceCounter.length; i++) {
+        performanceCounter.add(com.google.ipc.invalidation.ticl.proto.ClientProtocol.PropertyRecord.fromMessageNano(message.performanceCounter[i]));
+      }
+      return new InfoMessage(com.google.ipc.invalidation.ticl.proto.ClientProtocol.ClientVersion.fromMessageNano(message.clientVersion),
+          configParameter,
+          performanceCounter,
+          message.serverRegistrationSummaryRequested,
+          com.google.ipc.invalidation.ticl.proto.ClientProtocol.ClientConfigP.fromMessageNano(message.clientConfig));
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoClientProtocol.InfoMessage toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoClientProtocol.InfoMessage msg = new com.google.protos.ipc.invalidation.NanoClientProtocol.InfoMessage();
+      msg.clientVersion = this.clientVersion != null ? clientVersion.toMessageNano() : null;
+      msg.configParameter = new com.google.protos.ipc.invalidation.NanoClientProtocol.PropertyRecord[configParameter.size()];
+      for (int i = 0; i < msg.configParameter.length; i++) {
+        msg.configParameter[i] = configParameter.get(i).toMessageNano();
+      }
+      msg.performanceCounter = new com.google.protos.ipc.invalidation.NanoClientProtocol.PropertyRecord[performanceCounter.size()];
+      for (int i = 0; i < msg.performanceCounter.length; i++) {
+        msg.performanceCounter[i] = performanceCounter.get(i).toMessageNano();
+      }
+      msg.serverRegistrationSummaryRequested = hasServerRegistrationSummaryRequested() ? serverRegistrationSummaryRequested : null;
+      msg.clientConfig = this.clientConfig != null ? clientConfig.toMessageNano() : null;
+      return msg;
+    }
+  }
+
+  public static final class PropertyRecord extends ProtoWrapper {
+    public static PropertyRecord create(String name,
+        Integer value) {
+      return new PropertyRecord(name, value);
+    }
+
+    public static final PropertyRecord DEFAULT_INSTANCE = new PropertyRecord(null, null);
+
+    private final long __hazzerBits;
+    private final String name;
+    private final int value;
+
+    private PropertyRecord(String name,
+        Integer value) {
+      int hazzerBits = 0;
+      if (name != null) {
+        hazzerBits |= 0x1;
+        this.name = name;
+      } else {
+        this.name = "";
+      }
+      if (value != null) {
+        hazzerBits |= 0x2;
+        this.value = value;
+      } else {
+        this.value = 0;
+      }
+      this.__hazzerBits = hazzerBits;
+    }
+
+    public String getName() { return name; }
+    public boolean hasName() { return (0x1 & __hazzerBits) != 0; }
+
+    public int getValue() { return value; }
+    public boolean hasValue() { return (0x2 & __hazzerBits) != 0; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof PropertyRecord)) { return false; }
+      PropertyRecord other = (PropertyRecord) obj;
+      return __hazzerBits == other.__hazzerBits
+          && (!hasName() || equals(name, other.name))
+          && (!hasValue() || value == other.value);
+    }
+
+    @Override protected int computeHashCode() {
+      int result = hash(__hazzerBits);
+      if (hasName()) {
+        result = result * 31 + name.hashCode();
+      }
+      if (hasValue()) {
+        result = result * 31 + hash(value);
+      }
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<PropertyRecord:");
+      if (hasName()) {
+        builder.append(" name=").append(name);
+      }
+      if (hasValue()) {
+        builder.append(" value=").append(value);
+      }
+      builder.append('>');
+    }
+
+    public static PropertyRecord parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoClientProtocol.PropertyRecord(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static PropertyRecord fromMessageNano(com.google.protos.ipc.invalidation.NanoClientProtocol.PropertyRecord message) {
+      if (message == null) { return null; }
+      return new PropertyRecord(message.name,
+          message.value);
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoClientProtocol.PropertyRecord toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoClientProtocol.PropertyRecord msg = new com.google.protos.ipc.invalidation.NanoClientProtocol.PropertyRecord();
+      msg.name = hasName() ? name : null;
+      msg.value = hasValue() ? value : null;
+      return msg;
+    }
+  }
+
+  public static final class ServerHeader extends ProtoWrapper {
+    public static final class Builder {
+      public com.google.ipc.invalidation.ticl.proto.ClientProtocol.ProtocolVersion protocolVersion;
+      public Bytes clientToken;
+      public com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSummary registrationSummary;
+      public long serverTimeMs;
+      public String messageId;
+      public Builder(com.google.ipc.invalidation.ticl.proto.ClientProtocol.ProtocolVersion protocolVersion,
+          Bytes clientToken,
+          long serverTimeMs) {
+        this.protocolVersion = protocolVersion;this.clientToken = clientToken;this.serverTimeMs = serverTimeMs;}
+
+      public ServerHeader build() {
+        return new ServerHeader(protocolVersion, clientToken, registrationSummary, serverTimeMs, messageId);
+      }
+    }
+
+    public static ServerHeader create(com.google.ipc.invalidation.ticl.proto.ClientProtocol.ProtocolVersion protocolVersion,
+        Bytes clientToken,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSummary registrationSummary,
+        long serverTimeMs,
+        String messageId) {
+      return new ServerHeader(protocolVersion, clientToken, registrationSummary, serverTimeMs, messageId);
+    }
+
+    private final long __hazzerBits;
+    private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.ProtocolVersion protocolVersion;
+    private final Bytes clientToken;
+    private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSummary registrationSummary;
+    private final long serverTimeMs;
+    private final String messageId;
+
+    private ServerHeader(com.google.ipc.invalidation.ticl.proto.ClientProtocol.ProtocolVersion protocolVersion,
+        Bytes clientToken,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSummary registrationSummary,
+        Long serverTimeMs,
+        String messageId) throws ValidationArgumentException {
+      int hazzerBits = 0;
+      required("protocol_version", protocolVersion);
+      this.protocolVersion = protocolVersion;
+      required("client_token", clientToken);
+      nonEmpty("client_token", clientToken);
+      this.clientToken = clientToken;
+      this.registrationSummary = registrationSummary;
+      required("server_time_ms", serverTimeMs);
+      nonNegative("server_time_ms", serverTimeMs);
+      this.serverTimeMs = serverTimeMs;
+      if (messageId != null) {
+        hazzerBits |= 0x1;
+        nonEmpty("message_id", messageId);
+        this.messageId = messageId;
+      } else {
+        this.messageId = "";
+      }
+      this.__hazzerBits = hazzerBits;
+    }
+
+    public com.google.ipc.invalidation.ticl.proto.ClientProtocol.ProtocolVersion getProtocolVersion() { return protocolVersion; }
+
+    public Bytes getClientToken() { return clientToken; }
+
+    public com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSummary getNullableRegistrationSummary() { return registrationSummary; }
+
+    public long getServerTimeMs() { return serverTimeMs; }
+
+    public String getMessageId() { return messageId; }
+    public boolean hasMessageId() { return (0x1 & __hazzerBits) != 0; }
+
+    public Builder toBuilder() {
+      Builder builder = new Builder(protocolVersion, clientToken, serverTimeMs);
+      if (this.registrationSummary != null) {
+        builder.registrationSummary = registrationSummary;
+      }
+      if (hasMessageId()) {
+        builder.messageId = messageId;
+      }
+      return builder;
+    }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof ServerHeader)) { return false; }
+      ServerHeader other = (ServerHeader) obj;
+      return __hazzerBits == other.__hazzerBits
+          && equals(protocolVersion, other.protocolVersion)
+          && equals(clientToken, other.clientToken)
+          && equals(registrationSummary, other.registrationSummary)
+          && serverTimeMs == other.serverTimeMs
+          && (!hasMessageId() || equals(messageId, other.messageId));
+    }
+
+    @Override protected int computeHashCode() {
+      int result = hash(__hazzerBits);
+      result = result * 31 + protocolVersion.hashCode();
+      result = result * 31 + clientToken.hashCode();
+      if (registrationSummary != null) {
+        result = result * 31 + registrationSummary.hashCode();
+      }
+      result = result * 31 + hash(serverTimeMs);
+      if (hasMessageId()) {
+        result = result * 31 + messageId.hashCode();
+      }
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<ServerHeader:");
+      builder.append(" protocol_version=").append(protocolVersion);
+      builder.append(" client_token=").append(clientToken);
+      if (registrationSummary != null) {
+        builder.append(" registration_summary=").append(registrationSummary);
+      }
+      builder.append(" server_time_ms=").append(serverTimeMs);
+      if (hasMessageId()) {
+        builder.append(" message_id=").append(messageId);
+      }
+      builder.append('>');
+    }
+
+    public static ServerHeader parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoClientProtocol.ServerHeader(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static ServerHeader fromMessageNano(com.google.protos.ipc.invalidation.NanoClientProtocol.ServerHeader message) {
+      if (message == null) { return null; }
+      return new ServerHeader(com.google.ipc.invalidation.ticl.proto.ClientProtocol.ProtocolVersion.fromMessageNano(message.protocolVersion),
+          Bytes.fromByteArray(message.clientToken),
+          com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSummary.fromMessageNano(message.registrationSummary),
+          message.serverTimeMs,
+          message.messageId);
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoClientProtocol.ServerHeader toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoClientProtocol.ServerHeader msg = new com.google.protos.ipc.invalidation.NanoClientProtocol.ServerHeader();
+      msg.protocolVersion = protocolVersion.toMessageNano();
+      msg.clientToken = clientToken.getByteArray();
+      msg.registrationSummary = this.registrationSummary != null ? registrationSummary.toMessageNano() : null;
+      msg.serverTimeMs = serverTimeMs;
+      msg.messageId = hasMessageId() ? messageId : null;
+      return msg;
+    }
+  }
+
+  public static final class ServerToClientMessage extends ProtoWrapper {
+    public static final class Builder {
+      public com.google.ipc.invalidation.ticl.proto.ClientProtocol.ServerHeader header;
+      public com.google.ipc.invalidation.ticl.proto.ClientProtocol.TokenControlMessage tokenControlMessage;
+      public com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationMessage invalidationMessage;
+      public com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationStatusMessage registrationStatusMessage;
+      public com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSyncRequestMessage registrationSyncRequestMessage;
+      public com.google.ipc.invalidation.ticl.proto.ClientProtocol.ConfigChangeMessage configChangeMessage;
+      public com.google.ipc.invalidation.ticl.proto.ClientProtocol.InfoRequestMessage infoRequestMessage;
+      public com.google.ipc.invalidation.ticl.proto.ClientProtocol.ErrorMessage errorMessage;
+      public Builder(com.google.ipc.invalidation.ticl.proto.ClientProtocol.ServerHeader header) {
+        this.header = header;}
+
+      public ServerToClientMessage build() {
+        return new ServerToClientMessage(header, tokenControlMessage, invalidationMessage, registrationStatusMessage, registrationSyncRequestMessage, configChangeMessage, infoRequestMessage, errorMessage);
+      }
+    }
+
+    public static ServerToClientMessage create(com.google.ipc.invalidation.ticl.proto.ClientProtocol.ServerHeader header,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.TokenControlMessage tokenControlMessage,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationMessage invalidationMessage,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationStatusMessage registrationStatusMessage,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSyncRequestMessage registrationSyncRequestMessage,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.ConfigChangeMessage configChangeMessage,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.InfoRequestMessage infoRequestMessage,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.ErrorMessage errorMessage) {
+      return new ServerToClientMessage(header, tokenControlMessage, invalidationMessage, registrationStatusMessage, registrationSyncRequestMessage, configChangeMessage, infoRequestMessage, errorMessage);
+    }
+
+    private final long __hazzerBits;
+    private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.ServerHeader header;
+    private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.TokenControlMessage tokenControlMessage;
+    private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationMessage invalidationMessage;
+    private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationStatusMessage registrationStatusMessage;
+    private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSyncRequestMessage registrationSyncRequestMessage;
+    private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.ConfigChangeMessage configChangeMessage;
+    private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.InfoRequestMessage infoRequestMessage;
+    private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.ErrorMessage errorMessage;
+
+    private ServerToClientMessage(com.google.ipc.invalidation.ticl.proto.ClientProtocol.ServerHeader header,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.TokenControlMessage tokenControlMessage,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationMessage invalidationMessage,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationStatusMessage registrationStatusMessage,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSyncRequestMessage registrationSyncRequestMessage,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.ConfigChangeMessage configChangeMessage,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.InfoRequestMessage infoRequestMessage,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.ErrorMessage errorMessage) throws ValidationArgumentException {
+      int hazzerBits = 0;
+      required("header", header);
+      this.header = header;
+      if (tokenControlMessage != null) {
+        hazzerBits |= 0x1;
+        this.tokenControlMessage = tokenControlMessage;
+      } else {
+        this.tokenControlMessage = com.google.ipc.invalidation.ticl.proto.ClientProtocol.TokenControlMessage.DEFAULT_INSTANCE;
+      }
+      this.invalidationMessage = invalidationMessage;
+      this.registrationStatusMessage = registrationStatusMessage;
+      if (registrationSyncRequestMessage != null) {
+        hazzerBits |= 0x2;
+        this.registrationSyncRequestMessage = registrationSyncRequestMessage;
+      } else {
+        this.registrationSyncRequestMessage = com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSyncRequestMessage.DEFAULT_INSTANCE;
+      }
+      if (configChangeMessage != null) {
+        hazzerBits |= 0x4;
+        this.configChangeMessage = configChangeMessage;
+      } else {
+        this.configChangeMessage = com.google.ipc.invalidation.ticl.proto.ClientProtocol.ConfigChangeMessage.DEFAULT_INSTANCE;
+      }
+      this.infoRequestMessage = infoRequestMessage;
+      this.errorMessage = errorMessage;
+      this.__hazzerBits = hazzerBits;
+    }
+
+    public com.google.ipc.invalidation.ticl.proto.ClientProtocol.ServerHeader getHeader() { return header; }
+
+    public com.google.ipc.invalidation.ticl.proto.ClientProtocol.TokenControlMessage getTokenControlMessage() { return tokenControlMessage; }
+    public boolean hasTokenControlMessage() { return (0x1 & __hazzerBits) != 0; }
+
+    public com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationMessage getNullableInvalidationMessage() { return invalidationMessage; }
+
+    public com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationStatusMessage getNullableRegistrationStatusMessage() { return registrationStatusMessage; }
+
+    public com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSyncRequestMessage getRegistrationSyncRequestMessage() { return registrationSyncRequestMessage; }
+    public boolean hasRegistrationSyncRequestMessage() { return (0x2 & __hazzerBits) != 0; }
+
+    public com.google.ipc.invalidation.ticl.proto.ClientProtocol.ConfigChangeMessage getConfigChangeMessage() { return configChangeMessage; }
+    public boolean hasConfigChangeMessage() { return (0x4 & __hazzerBits) != 0; }
+
+    public com.google.ipc.invalidation.ticl.proto.ClientProtocol.InfoRequestMessage getNullableInfoRequestMessage() { return infoRequestMessage; }
+
+    public com.google.ipc.invalidation.ticl.proto.ClientProtocol.ErrorMessage getNullableErrorMessage() { return errorMessage; }
+
+    public Builder toBuilder() {
+      Builder builder = new Builder(header);
+      if (hasTokenControlMessage()) {
+        builder.tokenControlMessage = tokenControlMessage;
+      }
+      if (this.invalidationMessage != null) {
+        builder.invalidationMessage = invalidationMessage;
+      }
+      if (this.registrationStatusMessage != null) {
+        builder.registrationStatusMessage = registrationStatusMessage;
+      }
+      if (hasRegistrationSyncRequestMessage()) {
+        builder.registrationSyncRequestMessage = registrationSyncRequestMessage;
+      }
+      if (hasConfigChangeMessage()) {
+        builder.configChangeMessage = configChangeMessage;
+      }
+      if (this.infoRequestMessage != null) {
+        builder.infoRequestMessage = infoRequestMessage;
+      }
+      if (this.errorMessage != null) {
+        builder.errorMessage = errorMessage;
+      }
+      return builder;
+    }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof ServerToClientMessage)) { return false; }
+      ServerToClientMessage other = (ServerToClientMessage) obj;
+      return __hazzerBits == other.__hazzerBits
+          && equals(header, other.header)
+          && (!hasTokenControlMessage() || equals(tokenControlMessage, other.tokenControlMessage))
+          && equals(invalidationMessage, other.invalidationMessage)
+          && equals(registrationStatusMessage, other.registrationStatusMessage)
+          && (!hasRegistrationSyncRequestMessage() || equals(registrationSyncRequestMessage, other.registrationSyncRequestMessage))
+          && (!hasConfigChangeMessage() || equals(configChangeMessage, other.configChangeMessage))
+          && equals(infoRequestMessage, other.infoRequestMessage)
+          && equals(errorMessage, other.errorMessage);
+    }
+
+    @Override protected int computeHashCode() {
+      int result = hash(__hazzerBits);
+      result = result * 31 + header.hashCode();
+      if (hasTokenControlMessage()) {
+        result = result * 31 + tokenControlMessage.hashCode();
+      }
+      if (invalidationMessage != null) {
+        result = result * 31 + invalidationMessage.hashCode();
+      }
+      if (registrationStatusMessage != null) {
+        result = result * 31 + registrationStatusMessage.hashCode();
+      }
+      if (hasRegistrationSyncRequestMessage()) {
+        result = result * 31 + registrationSyncRequestMessage.hashCode();
+      }
+      if (hasConfigChangeMessage()) {
+        result = result * 31 + configChangeMessage.hashCode();
+      }
+      if (infoRequestMessage != null) {
+        result = result * 31 + infoRequestMessage.hashCode();
+      }
+      if (errorMessage != null) {
+        result = result * 31 + errorMessage.hashCode();
+      }
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<ServerToClientMessage:");
+      builder.append(" header=").append(header);
+      if (hasTokenControlMessage()) {
+        builder.append(" token_control_message=").append(tokenControlMessage);
+      }
+      if (invalidationMessage != null) {
+        builder.append(" invalidation_message=").append(invalidationMessage);
+      }
+      if (registrationStatusMessage != null) {
+        builder.append(" registration_status_message=").append(registrationStatusMessage);
+      }
+      if (hasRegistrationSyncRequestMessage()) {
+        builder.append(" registration_sync_request_message=").append(registrationSyncRequestMessage);
+      }
+      if (hasConfigChangeMessage()) {
+        builder.append(" config_change_message=").append(configChangeMessage);
+      }
+      if (infoRequestMessage != null) {
+        builder.append(" info_request_message=").append(infoRequestMessage);
+      }
+      if (errorMessage != null) {
+        builder.append(" error_message=").append(errorMessage);
+      }
+      builder.append('>');
+    }
+
+    public static ServerToClientMessage parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoClientProtocol.ServerToClientMessage(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static ServerToClientMessage fromMessageNano(com.google.protos.ipc.invalidation.NanoClientProtocol.ServerToClientMessage message) {
+      if (message == null) { return null; }
+      return new ServerToClientMessage(com.google.ipc.invalidation.ticl.proto.ClientProtocol.ServerHeader.fromMessageNano(message.header),
+          com.google.ipc.invalidation.ticl.proto.ClientProtocol.TokenControlMessage.fromMessageNano(message.tokenControlMessage),
+          com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationMessage.fromMessageNano(message.invalidationMessage),
+          com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationStatusMessage.fromMessageNano(message.registrationStatusMessage),
+          com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSyncRequestMessage.fromMessageNano(message.registrationSyncRequestMessage),
+          com.google.ipc.invalidation.ticl.proto.ClientProtocol.ConfigChangeMessage.fromMessageNano(message.configChangeMessage),
+          com.google.ipc.invalidation.ticl.proto.ClientProtocol.InfoRequestMessage.fromMessageNano(message.infoRequestMessage),
+          com.google.ipc.invalidation.ticl.proto.ClientProtocol.ErrorMessage.fromMessageNano(message.errorMessage));
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoClientProtocol.ServerToClientMessage toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoClientProtocol.ServerToClientMessage msg = new com.google.protos.ipc.invalidation.NanoClientProtocol.ServerToClientMessage();
+      msg.header = header.toMessageNano();
+      msg.tokenControlMessage = hasTokenControlMessage() ? tokenControlMessage.toMessageNano() : null;
+      msg.invalidationMessage = this.invalidationMessage != null ? invalidationMessage.toMessageNano() : null;
+      msg.registrationStatusMessage = this.registrationStatusMessage != null ? registrationStatusMessage.toMessageNano() : null;
+      msg.registrationSyncRequestMessage = hasRegistrationSyncRequestMessage() ? registrationSyncRequestMessage.toMessageNano() : null;
+      msg.configChangeMessage = hasConfigChangeMessage() ? configChangeMessage.toMessageNano() : null;
+      msg.infoRequestMessage = this.infoRequestMessage != null ? infoRequestMessage.toMessageNano() : null;
+      msg.errorMessage = this.errorMessage != null ? errorMessage.toMessageNano() : null;
+      return msg;
+    }
+  }
+
+  public static final class TokenControlMessage extends ProtoWrapper {
+    public static TokenControlMessage create(Bytes newToken) {
+      return new TokenControlMessage(newToken);
+    }
+
+    public static final TokenControlMessage DEFAULT_INSTANCE = new TokenControlMessage(null);
+
+    private final long __hazzerBits;
+    private final Bytes newToken;
+
+    private TokenControlMessage(Bytes newToken) {
+      int hazzerBits = 0;
+      if (newToken != null) {
+        hazzerBits |= 0x1;
+        this.newToken = newToken;
+      } else {
+        this.newToken = Bytes.EMPTY_BYTES;
+      }
+      this.__hazzerBits = hazzerBits;
+    }
+
+    public Bytes getNewToken() { return newToken; }
+    public boolean hasNewToken() { return (0x1 & __hazzerBits) != 0; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof TokenControlMessage)) { return false; }
+      TokenControlMessage other = (TokenControlMessage) obj;
+      return __hazzerBits == other.__hazzerBits
+          && (!hasNewToken() || equals(newToken, other.newToken));
+    }
+
+    @Override protected int computeHashCode() {
+      int result = hash(__hazzerBits);
+      if (hasNewToken()) {
+        result = result * 31 + newToken.hashCode();
+      }
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<TokenControlMessage:");
+      if (hasNewToken()) {
+        builder.append(" new_token=").append(newToken);
+      }
+      builder.append('>');
+    }
+
+    public static TokenControlMessage parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoClientProtocol.TokenControlMessage(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static TokenControlMessage fromMessageNano(com.google.protos.ipc.invalidation.NanoClientProtocol.TokenControlMessage message) {
+      if (message == null) { return null; }
+      return new TokenControlMessage(Bytes.fromByteArray(message.newToken));
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoClientProtocol.TokenControlMessage toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoClientProtocol.TokenControlMessage msg = new com.google.protos.ipc.invalidation.NanoClientProtocol.TokenControlMessage();
+      msg.newToken = hasNewToken() ? newToken.getByteArray() : null;
+      return msg;
+    }
+  }
+
+  public static final class RegistrationStatus extends ProtoWrapper {
+    public static RegistrationStatus create(com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationP registration,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.StatusP status) {
+      return new RegistrationStatus(registration, status);
+    }
+
+    private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationP registration;
+    private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.StatusP status;
+
+    private RegistrationStatus(com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationP registration,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.StatusP status) throws ValidationArgumentException {
+      required("registration", registration);
+      this.registration = registration;
+      required("status", status);
+      this.status = status;
+    }
+
+    public com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationP getRegistration() { return registration; }
+
+    public com.google.ipc.invalidation.ticl.proto.ClientProtocol.StatusP getStatus() { return status; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof RegistrationStatus)) { return false; }
+      RegistrationStatus other = (RegistrationStatus) obj;
+      return equals(registration, other.registration)
+          && equals(status, other.status);
+    }
+
+    @Override protected int computeHashCode() {
+      int result = 1;
+      result = result * 31 + registration.hashCode();
+      result = result * 31 + status.hashCode();
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<RegistrationStatus:");
+      builder.append(" registration=").append(registration);
+      builder.append(" status=").append(status);
+      builder.append('>');
+    }
+
+    public static RegistrationStatus parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoClientProtocol.RegistrationStatus(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static RegistrationStatus fromMessageNano(com.google.protos.ipc.invalidation.NanoClientProtocol.RegistrationStatus message) {
+      if (message == null) { return null; }
+      return new RegistrationStatus(com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationP.fromMessageNano(message.registration),
+          com.google.ipc.invalidation.ticl.proto.ClientProtocol.StatusP.fromMessageNano(message.status));
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoClientProtocol.RegistrationStatus toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoClientProtocol.RegistrationStatus msg = new com.google.protos.ipc.invalidation.NanoClientProtocol.RegistrationStatus();
+      msg.registration = registration.toMessageNano();
+      msg.status = status.toMessageNano();
+      return msg;
+    }
+  }
+
+  public static final class RegistrationStatusMessage extends ProtoWrapper {
+    public static RegistrationStatusMessage create(Collection<com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationStatus> registrationStatus) {
+      return new RegistrationStatusMessage(registrationStatus);
+    }
+
+    private final List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationStatus> registrationStatus;
+
+    private RegistrationStatusMessage(Collection<com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationStatus> registrationStatus) throws ValidationArgumentException {
+      this.registrationStatus = required("registration_status", registrationStatus);
+    }
+
+    public List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationStatus> getRegistrationStatus() { return registrationStatus; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof RegistrationStatusMessage)) { return false; }
+      RegistrationStatusMessage other = (RegistrationStatusMessage) obj;
+      return equals(registrationStatus, other.registrationStatus);
+    }
+
+    @Override protected int computeHashCode() {
+      int result = 1;
+      result = result * 31 + registrationStatus.hashCode();
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<RegistrationStatusMessage:");
+      builder.append(" registration_status=[").append(registrationStatus).append(']');
+      builder.append('>');
+    }
+
+    public static RegistrationStatusMessage parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoClientProtocol.RegistrationStatusMessage(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static RegistrationStatusMessage fromMessageNano(com.google.protos.ipc.invalidation.NanoClientProtocol.RegistrationStatusMessage message) {
+      if (message == null) { return null; }
+      List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationStatus> registrationStatus = new ArrayList<com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationStatus>(message.registrationStatus.length);
+      for (int i = 0; i < message.registrationStatus.length; i++) {
+        registrationStatus.add(com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationStatus.fromMessageNano(message.registrationStatus[i]));
+      }
+      return new RegistrationStatusMessage(registrationStatus);
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoClientProtocol.RegistrationStatusMessage toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoClientProtocol.RegistrationStatusMessage msg = new com.google.protos.ipc.invalidation.NanoClientProtocol.RegistrationStatusMessage();
+      msg.registrationStatus = new com.google.protos.ipc.invalidation.NanoClientProtocol.RegistrationStatus[registrationStatus.size()];
+      for (int i = 0; i < msg.registrationStatus.length; i++) {
+        msg.registrationStatus[i] = registrationStatus.get(i).toMessageNano();
+      }
+      return msg;
+    }
+  }
+
+  public static final class RegistrationSyncRequestMessage extends ProtoWrapper {
+    public static RegistrationSyncRequestMessage create() {
+      return new RegistrationSyncRequestMessage();
+    }
+
+    public static final RegistrationSyncRequestMessage DEFAULT_INSTANCE = new RegistrationSyncRequestMessage();
+
+
+    private RegistrationSyncRequestMessage() {
+    }
+
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof RegistrationSyncRequestMessage)) { return false; }
+      RegistrationSyncRequestMessage other = (RegistrationSyncRequestMessage) obj;
+      return true;
+    }
+
+    @Override protected int computeHashCode() {
+      int result = 1;
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<RegistrationSyncRequestMessage:");
+      builder.append('>');
+    }
+
+    public static RegistrationSyncRequestMessage parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoClientProtocol.RegistrationSyncRequestMessage(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static RegistrationSyncRequestMessage fromMessageNano(com.google.protos.ipc.invalidation.NanoClientProtocol.RegistrationSyncRequestMessage message) {
+      if (message == null) { return null; }
+      return new RegistrationSyncRequestMessage();
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoClientProtocol.RegistrationSyncRequestMessage toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoClientProtocol.RegistrationSyncRequestMessage msg = new com.google.protos.ipc.invalidation.NanoClientProtocol.RegistrationSyncRequestMessage();
+      return msg;
+    }
+  }
+
+  public static final class InvalidationMessage extends ProtoWrapper {
+    public static InvalidationMessage create(Collection<com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationP> invalidation) {
+      return new InvalidationMessage(invalidation);
+    }
+
+    private final List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationP> invalidation;
+
+    private InvalidationMessage(Collection<com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationP> invalidation) throws ValidationArgumentException {
+      this.invalidation = required("invalidation", invalidation);
+    }
+
+    public List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationP> getInvalidation() { return invalidation; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof InvalidationMessage)) { return false; }
+      InvalidationMessage other = (InvalidationMessage) obj;
+      return equals(invalidation, other.invalidation);
+    }
+
+    @Override protected int computeHashCode() {
+      int result = 1;
+      result = result * 31 + invalidation.hashCode();
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<InvalidationMessage:");
+      builder.append(" invalidation=[").append(invalidation).append(']');
+      builder.append('>');
+    }
+
+    public static InvalidationMessage parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoClientProtocol.InvalidationMessage(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static InvalidationMessage fromMessageNano(com.google.protos.ipc.invalidation.NanoClientProtocol.InvalidationMessage message) {
+      if (message == null) { return null; }
+      List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationP> invalidation = new ArrayList<com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationP>(message.invalidation.length);
+      for (int i = 0; i < message.invalidation.length; i++) {
+        invalidation.add(com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationP.fromMessageNano(message.invalidation[i]));
+      }
+      return new InvalidationMessage(invalidation);
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoClientProtocol.InvalidationMessage toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoClientProtocol.InvalidationMessage msg = new com.google.protos.ipc.invalidation.NanoClientProtocol.InvalidationMessage();
+      msg.invalidation = new com.google.protos.ipc.invalidation.NanoClientProtocol.InvalidationP[invalidation.size()];
+      for (int i = 0; i < msg.invalidation.length; i++) {
+        msg.invalidation[i] = invalidation.get(i).toMessageNano();
+      }
+      return msg;
+    }
+  }
+
+  public static final class InfoRequestMessage extends ProtoWrapper {
+    public interface InfoType {
+      public static final int GET_PERFORMANCE_COUNTERS = 1;
+    }
+
+    public static InfoRequestMessage create(Collection<Integer> infoType) {
+      return new InfoRequestMessage(infoType);
+    }
+
+    private final List<Integer> infoType;
+
+    private InfoRequestMessage(Collection<Integer> infoType) throws ValidationArgumentException {
+      this.infoType = required("info_type", infoType);
+    }
+
+    public List<Integer> getInfoType() { return infoType; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof InfoRequestMessage)) { return false; }
+      InfoRequestMessage other = (InfoRequestMessage) obj;
+      return equals(infoType, other.infoType);
+    }
+
+    @Override protected int computeHashCode() {
+      int result = 1;
+      result = result * 31 + infoType.hashCode();
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<InfoRequestMessage:");
+      builder.append(" info_type=[").append(infoType).append(']');
+      builder.append('>');
+    }
+
+    public static InfoRequestMessage parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoClientProtocol.InfoRequestMessage(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static InfoRequestMessage fromMessageNano(com.google.protos.ipc.invalidation.NanoClientProtocol.InfoRequestMessage message) {
+      if (message == null) { return null; }
+      List<Integer> infoType = new ArrayList<Integer>(message.infoType.length);
+      for (int i = 0; i < message.infoType.length; i++) {
+        infoType.add(message.infoType[i]);
+      }
+      return new InfoRequestMessage(infoType);
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoClientProtocol.InfoRequestMessage toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoClientProtocol.InfoRequestMessage msg = new com.google.protos.ipc.invalidation.NanoClientProtocol.InfoRequestMessage();
+      msg.infoType = new int[infoType.size()];
+      for (int i = 0; i < msg.infoType.length; i++) {
+        msg.infoType[i] = infoType.get(i);
+      }
+      return msg;
+    }
+  }
+
+  public static final class RateLimitP extends ProtoWrapper {
+    public static RateLimitP create(int windowMs,
+        int count) {
+      return new RateLimitP(windowMs, count);
+    }
+
+    private final int windowMs;
+    private final int count;
+
+    private RateLimitP(Integer windowMs,
+        Integer count) throws ValidationArgumentException {
+      required("window_ms", windowMs);
+      this.windowMs = windowMs;
+      required("count", count);
+      this.count = count;
+      check(windowMs >= 1000 && windowMs > count, "Invalid window_ms and count");
+    }
+
+    public int getWindowMs() { return windowMs; }
+
+    public int getCount() { return count; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof RateLimitP)) { return false; }
+      RateLimitP other = (RateLimitP) obj;
+      return windowMs == other.windowMs
+          && count == other.count;
+    }
+
+    @Override protected int computeHashCode() {
+      int result = 1;
+      result = result * 31 + hash(windowMs);
+      result = result * 31 + hash(count);
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<RateLimitP:");
+      builder.append(" window_ms=").append(windowMs);
+      builder.append(" count=").append(count);
+      builder.append('>');
+    }
+
+    public static RateLimitP parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoClientProtocol.RateLimitP(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static RateLimitP fromMessageNano(com.google.protos.ipc.invalidation.NanoClientProtocol.RateLimitP message) {
+      if (message == null) { return null; }
+      return new RateLimitP(message.windowMs,
+          message.count);
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoClientProtocol.RateLimitP toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoClientProtocol.RateLimitP msg = new com.google.protos.ipc.invalidation.NanoClientProtocol.RateLimitP();
+      msg.windowMs = windowMs;
+      msg.count = count;
+      return msg;
+    }
+  }
+
+  public static final class ProtocolHandlerConfigP extends ProtoWrapper {
+    public static final class Builder {
+      public Integer batchingDelayMs;
+      public Collection<com.google.ipc.invalidation.ticl.proto.ClientProtocol.RateLimitP> rateLimit;
+      public Builder() {
+      }
+
+      public ProtocolHandlerConfigP build() {
+        return new ProtocolHandlerConfigP(batchingDelayMs, rateLimit);
+      }
+    }
+
+    public static ProtocolHandlerConfigP create(Integer batchingDelayMs,
+        Collection<com.google.ipc.invalidation.ticl.proto.ClientProtocol.RateLimitP> rateLimit) {
+      return new ProtocolHandlerConfigP(batchingDelayMs, rateLimit);
+    }
+
+    public static final ProtocolHandlerConfigP DEFAULT_INSTANCE = new ProtocolHandlerConfigP(null, null);
+
+    private final long __hazzerBits;
+    private final int batchingDelayMs;
+    private final List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.RateLimitP> rateLimit;
+
+    private ProtocolHandlerConfigP(Integer batchingDelayMs,
+        Collection<com.google.ipc.invalidation.ticl.proto.ClientProtocol.RateLimitP> rateLimit) {
+      int hazzerBits = 0;
+      if (batchingDelayMs != null) {
+        hazzerBits |= 0x1;
+        this.batchingDelayMs = batchingDelayMs;
+      } else {
+        this.batchingDelayMs = 500;
+      }
+      this.rateLimit = optional("rate_limit", rateLimit);
+      this.__hazzerBits = hazzerBits;
+    }
+
+    public int getBatchingDelayMs() { return batchingDelayMs; }
+    public boolean hasBatchingDelayMs() { return (0x1 & __hazzerBits) != 0; }
+
+    public List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.RateLimitP> getRateLimit() { return rateLimit; }
+
+    public Builder toBuilder() {
+      Builder builder = new Builder();
+      if (hasBatchingDelayMs()) {
+        builder.batchingDelayMs = batchingDelayMs;
+      }
+      if (!this.rateLimit.isEmpty()) {
+        builder.rateLimit = rateLimit;
+      }
+      return builder;
+    }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof ProtocolHandlerConfigP)) { return false; }
+      ProtocolHandlerConfigP other = (ProtocolHandlerConfigP) obj;
+      return __hazzerBits == other.__hazzerBits
+          && (!hasBatchingDelayMs() || batchingDelayMs == other.batchingDelayMs)
+          && equals(rateLimit, other.rateLimit);
+    }
+
+    @Override protected int computeHashCode() {
+      int result = hash(__hazzerBits);
+      if (hasBatchingDelayMs()) {
+        result = result * 31 + hash(batchingDelayMs);
+      }
+      result = result * 31 + rateLimit.hashCode();
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<ProtocolHandlerConfigP:");
+      if (hasBatchingDelayMs()) {
+        builder.append(" batching_delay_ms=").append(batchingDelayMs);
+      }
+      builder.append(" rate_limit=[").append(rateLimit).append(']');
+      builder.append('>');
+    }
+
+    public static ProtocolHandlerConfigP parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoClientProtocol.ProtocolHandlerConfigP(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static ProtocolHandlerConfigP fromMessageNano(com.google.protos.ipc.invalidation.NanoClientProtocol.ProtocolHandlerConfigP message) {
+      if (message == null) { return null; }
+      List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.RateLimitP> rateLimit = new ArrayList<com.google.ipc.invalidation.ticl.proto.ClientProtocol.RateLimitP>(message.rateLimit.length);
+      for (int i = 0; i < message.rateLimit.length; i++) {
+        rateLimit.add(com.google.ipc.invalidation.ticl.proto.ClientProtocol.RateLimitP.fromMessageNano(message.rateLimit[i]));
+      }
+      return new ProtocolHandlerConfigP(message.batchingDelayMs,
+          rateLimit);
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoClientProtocol.ProtocolHandlerConfigP toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoClientProtocol.ProtocolHandlerConfigP msg = new com.google.protos.ipc.invalidation.NanoClientProtocol.ProtocolHandlerConfigP();
+      msg.batchingDelayMs = hasBatchingDelayMs() ? batchingDelayMs : null;
+      msg.rateLimit = new com.google.protos.ipc.invalidation.NanoClientProtocol.RateLimitP[rateLimit.size()];
+      for (int i = 0; i < msg.rateLimit.length; i++) {
+        msg.rateLimit[i] = rateLimit.get(i).toMessageNano();
+      }
+      return msg;
+    }
+  }
+
+  public static final class ClientConfigP extends ProtoWrapper {
+    public static final class Builder {
+      public com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version version;
+      public Integer networkTimeoutDelayMs;
+      public Integer writeRetryDelayMs;
+      public Integer heartbeatIntervalMs;
+      public Integer perfCounterDelayMs;
+      public Integer maxExponentialBackoffFactor;
+      public Integer smearPercent;
+      public Boolean isTransient;
+      public Integer initialPersistentHeartbeatDelayMs;
+      public com.google.ipc.invalidation.ticl.proto.ClientProtocol.ProtocolHandlerConfigP protocolHandlerConfig;
+      public Boolean channelSupportsOfflineDelivery;
+      public Integer offlineHeartbeatThresholdMs;
+      public Boolean allowSuppression;
+      public Builder(com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version version,
+          com.google.ipc.invalidation.ticl.proto.ClientProtocol.ProtocolHandlerConfigP protocolHandlerConfig) {
+        this.version = version;this.protocolHandlerConfig = protocolHandlerConfig;}
+
+      public ClientConfigP build() {
+        return new ClientConfigP(version, networkTimeoutDelayMs, writeRetryDelayMs, heartbeatIntervalMs, perfCounterDelayMs, maxExponentialBackoffFactor, smearPercent, isTransient, initialPersistentHeartbeatDelayMs, protocolHandlerConfig, channelSupportsOfflineDelivery, offlineHeartbeatThresholdMs, allowSuppression);
+      }
+    }
+
+    public static ClientConfigP create(com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version version,
+        Integer networkTimeoutDelayMs,
+        Integer writeRetryDelayMs,
+        Integer heartbeatIntervalMs,
+        Integer perfCounterDelayMs,
+        Integer maxExponentialBackoffFactor,
+        Integer smearPercent,
+        Boolean isTransient,
+        Integer initialPersistentHeartbeatDelayMs,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.ProtocolHandlerConfigP protocolHandlerConfig,
+        Boolean channelSupportsOfflineDelivery,
+        Integer offlineHeartbeatThresholdMs,
+        Boolean allowSuppression) {
+      return new ClientConfigP(version, networkTimeoutDelayMs, writeRetryDelayMs, heartbeatIntervalMs, perfCounterDelayMs, maxExponentialBackoffFactor, smearPercent, isTransient, initialPersistentHeartbeatDelayMs, protocolHandlerConfig, channelSupportsOfflineDelivery, offlineHeartbeatThresholdMs, allowSuppression);
+    }
+
+    private final long __hazzerBits;
+    private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version version;
+    private final int networkTimeoutDelayMs;
+    private final int writeRetryDelayMs;
+    private final int heartbeatIntervalMs;
+    private final int perfCounterDelayMs;
+    private final int maxExponentialBackoffFactor;
+    private final int smearPercent;
+    private final boolean isTransient;
+    private final int initialPersistentHeartbeatDelayMs;
+    private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.ProtocolHandlerConfigP protocolHandlerConfig;
+    private final boolean channelSupportsOfflineDelivery;
+    private final int offlineHeartbeatThresholdMs;
+    private final boolean allowSuppression;
+
+    private ClientConfigP(com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version version,
+        Integer networkTimeoutDelayMs,
+        Integer writeRetryDelayMs,
+        Integer heartbeatIntervalMs,
+        Integer perfCounterDelayMs,
+        Integer maxExponentialBackoffFactor,
+        Integer smearPercent,
+        Boolean isTransient,
+        Integer initialPersistentHeartbeatDelayMs,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.ProtocolHandlerConfigP protocolHandlerConfig,
+        Boolean channelSupportsOfflineDelivery,
+        Integer offlineHeartbeatThresholdMs,
+        Boolean allowSuppression) throws ValidationArgumentException {
+      int hazzerBits = 0;
+      required("version", version);
+      this.version = version;
+      if (networkTimeoutDelayMs != null) {
+        hazzerBits |= 0x1;
+        this.networkTimeoutDelayMs = networkTimeoutDelayMs;
+      } else {
+        this.networkTimeoutDelayMs = 60000;
+      }
+      if (writeRetryDelayMs != null) {
+        hazzerBits |= 0x2;
+        this.writeRetryDelayMs = writeRetryDelayMs;
+      } else {
+        this.writeRetryDelayMs = 10000;
+      }
+      if (heartbeatIntervalMs != null) {
+        hazzerBits |= 0x4;
+        this.heartbeatIntervalMs = heartbeatIntervalMs;
+      } else {
+        this.heartbeatIntervalMs = 1200000;
+      }
+      if (perfCounterDelayMs != null) {
+        hazzerBits |= 0x8;
+        this.perfCounterDelayMs = perfCounterDelayMs;
+      } else {
+        this.perfCounterDelayMs = 21600000;
+      }
+      if (maxExponentialBackoffFactor != null) {
+        hazzerBits |= 0x10;
+        this.maxExponentialBackoffFactor = maxExponentialBackoffFactor;
+      } else {
+        this.maxExponentialBackoffFactor = 500;
+      }
+      if (smearPercent != null) {
+        hazzerBits |= 0x20;
+        this.smearPercent = smearPercent;
+      } else {
+        this.smearPercent = 20;
+      }
+      if (isTransient != null) {
+        hazzerBits |= 0x40;
+        this.isTransient = isTransient;
+      } else {
+        this.isTransient = false;
+      }
+      if (initialPersistentHeartbeatDelayMs != null) {
+        hazzerBits |= 0x80;
+        this.initialPersistentHeartbeatDelayMs = initialPersistentHeartbeatDelayMs;
+      } else {
+        this.initialPersistentHeartbeatDelayMs = 2000;
+      }
+      required("protocol_handler_config", protocolHandlerConfig);
+      this.protocolHandlerConfig = protocolHandlerConfig;
+      if (channelSupportsOfflineDelivery != null) {
+        hazzerBits |= 0x100;
+        this.channelSupportsOfflineDelivery = channelSupportsOfflineDelivery;
+      } else {
+        this.channelSupportsOfflineDelivery = false;
+      }
+      if (offlineHeartbeatThresholdMs != null) {
+        hazzerBits |= 0x200;
+        this.offlineHeartbeatThresholdMs = offlineHeartbeatThresholdMs;
+      } else {
+        this.offlineHeartbeatThresholdMs = 60000;
+      }
+      if (allowSuppression != null) {
+        hazzerBits |= 0x400;
+        this.allowSuppression = allowSuppression;
+      } else {
+        this.allowSuppression = true;
+      }
+      this.__hazzerBits = hazzerBits;
+    }
+
+    public com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version getVersion() { return version; }
+
+    public int getNetworkTimeoutDelayMs() { return networkTimeoutDelayMs; }
+    public boolean hasNetworkTimeoutDelayMs() { return (0x1 & __hazzerBits) != 0; }
+
+    public int getWriteRetryDelayMs() { return writeRetryDelayMs; }
+    public boolean hasWriteRetryDelayMs() { return (0x2 & __hazzerBits) != 0; }
+
+    public int getHeartbeatIntervalMs() { return heartbeatIntervalMs; }
+    public boolean hasHeartbeatIntervalMs() { return (0x4 & __hazzerBits) != 0; }
+
+    public int getPerfCounterDelayMs() { return perfCounterDelayMs; }
+    public boolean hasPerfCounterDelayMs() { return (0x8 & __hazzerBits) != 0; }
+
+    public int getMaxExponentialBackoffFactor() { return maxExponentialBackoffFactor; }
+    public boolean hasMaxExponentialBackoffFactor() { return (0x10 & __hazzerBits) != 0; }
+
+    public int getSmearPercent() { return smearPercent; }
+    public boolean hasSmearPercent() { return (0x20 & __hazzerBits) != 0; }
+
+    public boolean getIsTransient() { return isTransient; }
+    public boolean hasIsTransient() { return (0x40 & __hazzerBits) != 0; }
+
+    public int getInitialPersistentHeartbeatDelayMs() { return initialPersistentHeartbeatDelayMs; }
+    public boolean hasInitialPersistentHeartbeatDelayMs() { return (0x80 & __hazzerBits) != 0; }
+
+    public com.google.ipc.invalidation.ticl.proto.ClientProtocol.ProtocolHandlerConfigP getProtocolHandlerConfig() { return protocolHandlerConfig; }
+
+    public boolean getChannelSupportsOfflineDelivery() { return channelSupportsOfflineDelivery; }
+    public boolean hasChannelSupportsOfflineDelivery() { return (0x100 & __hazzerBits) != 0; }
+
+    public int getOfflineHeartbeatThresholdMs() { return offlineHeartbeatThresholdMs; }
+    public boolean hasOfflineHeartbeatThresholdMs() { return (0x200 & __hazzerBits) != 0; }
+
+    public boolean getAllowSuppression() { return allowSuppression; }
+    public boolean hasAllowSuppression() { return (0x400 & __hazzerBits) != 0; }
+
+    public Builder toBuilder() {
+      Builder builder = new Builder(version, protocolHandlerConfig);
+      if (hasNetworkTimeoutDelayMs()) {
+        builder.networkTimeoutDelayMs = networkTimeoutDelayMs;
+      }
+      if (hasWriteRetryDelayMs()) {
+        builder.writeRetryDelayMs = writeRetryDelayMs;
+      }
+      if (hasHeartbeatIntervalMs()) {
+        builder.heartbeatIntervalMs = heartbeatIntervalMs;
+      }
+      if (hasPerfCounterDelayMs()) {
+        builder.perfCounterDelayMs = perfCounterDelayMs;
+      }
+      if (hasMaxExponentialBackoffFactor()) {
+        builder.maxExponentialBackoffFactor = maxExponentialBackoffFactor;
+      }
+      if (hasSmearPercent()) {
+        builder.smearPercent = smearPercent;
+      }
+      if (hasIsTransient()) {
+        builder.isTransient = isTransient;
+      }
+      if (hasInitialPersistentHeartbeatDelayMs()) {
+        builder.initialPersistentHeartbeatDelayMs = initialPersistentHeartbeatDelayMs;
+      }
+      if (hasChannelSupportsOfflineDelivery()) {
+        builder.channelSupportsOfflineDelivery = channelSupportsOfflineDelivery;
+      }
+      if (hasOfflineHeartbeatThresholdMs()) {
+        builder.offlineHeartbeatThresholdMs = offlineHeartbeatThresholdMs;
+      }
+      if (hasAllowSuppression()) {
+        builder.allowSuppression = allowSuppression;
+      }
+      return builder;
+    }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof ClientConfigP)) { return false; }
+      ClientConfigP other = (ClientConfigP) obj;
+      return __hazzerBits == other.__hazzerBits
+          && equals(version, other.version)
+          && (!hasNetworkTimeoutDelayMs() || networkTimeoutDelayMs == other.networkTimeoutDelayMs)
+          && (!hasWriteRetryDelayMs() || writeRetryDelayMs == other.writeRetryDelayMs)
+          && (!hasHeartbeatIntervalMs() || heartbeatIntervalMs == other.heartbeatIntervalMs)
+          && (!hasPerfCounterDelayMs() || perfCounterDelayMs == other.perfCounterDelayMs)
+          && (!hasMaxExponentialBackoffFactor() || maxExponentialBackoffFactor == other.maxExponentialBackoffFactor)
+          && (!hasSmearPercent() || smearPercent == other.smearPercent)
+          && (!hasIsTransient() || isTransient == other.isTransient)
+          && (!hasInitialPersistentHeartbeatDelayMs() || initialPersistentHeartbeatDelayMs == other.initialPersistentHeartbeatDelayMs)
+          && equals(protocolHandlerConfig, other.protocolHandlerConfig)
+          && (!hasChannelSupportsOfflineDelivery() || channelSupportsOfflineDelivery == other.channelSupportsOfflineDelivery)
+          && (!hasOfflineHeartbeatThresholdMs() || offlineHeartbeatThresholdMs == other.offlineHeartbeatThresholdMs)
+          && (!hasAllowSuppression() || allowSuppression == other.allowSuppression);
+    }
+
+    @Override protected int computeHashCode() {
+      int result = hash(__hazzerBits);
+      result = result * 31 + version.hashCode();
+      if (hasNetworkTimeoutDelayMs()) {
+        result = result * 31 + hash(networkTimeoutDelayMs);
+      }
+      if (hasWriteRetryDelayMs()) {
+        result = result * 31 + hash(writeRetryDelayMs);
+      }
+      if (hasHeartbeatIntervalMs()) {
+        result = result * 31 + hash(heartbeatIntervalMs);
+      }
+      if (hasPerfCounterDelayMs()) {
+        result = result * 31 + hash(perfCounterDelayMs);
+      }
+      if (hasMaxExponentialBackoffFactor()) {
+        result = result * 31 + hash(maxExponentialBackoffFactor);
+      }
+      if (hasSmearPercent()) {
+        result = result * 31 + hash(smearPercent);
+      }
+      if (hasIsTransient()) {
+        result = result * 31 + hash(isTransient);
+      }
+      if (hasInitialPersistentHeartbeatDelayMs()) {
+        result = result * 31 + hash(initialPersistentHeartbeatDelayMs);
+      }
+      result = result * 31 + protocolHandlerConfig.hashCode();
+      if (hasChannelSupportsOfflineDelivery()) {
+        result = result * 31 + hash(channelSupportsOfflineDelivery);
+      }
+      if (hasOfflineHeartbeatThresholdMs()) {
+        result = result * 31 + hash(offlineHeartbeatThresholdMs);
+      }
+      if (hasAllowSuppression()) {
+        result = result * 31 + hash(allowSuppression);
+      }
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<ClientConfigP:");
+      builder.append(" version=").append(version);
+      if (hasNetworkTimeoutDelayMs()) {
+        builder.append(" network_timeout_delay_ms=").append(networkTimeoutDelayMs);
+      }
+      if (hasWriteRetryDelayMs()) {
+        builder.append(" write_retry_delay_ms=").append(writeRetryDelayMs);
+      }
+      if (hasHeartbeatIntervalMs()) {
+        builder.append(" heartbeat_interval_ms=").append(heartbeatIntervalMs);
+      }
+      if (hasPerfCounterDelayMs()) {
+        builder.append(" perf_counter_delay_ms=").append(perfCounterDelayMs);
+      }
+      if (hasMaxExponentialBackoffFactor()) {
+        builder.append(" max_exponential_backoff_factor=").append(maxExponentialBackoffFactor);
+      }
+      if (hasSmearPercent()) {
+        builder.append(" smear_percent=").append(smearPercent);
+      }
+      if (hasIsTransient()) {
+        builder.append(" is_transient=").append(isTransient);
+      }
+      if (hasInitialPersistentHeartbeatDelayMs()) {
+        builder.append(" initial_persistent_heartbeat_delay_ms=").append(initialPersistentHeartbeatDelayMs);
+      }
+      builder.append(" protocol_handler_config=").append(protocolHandlerConfig);
+      if (hasChannelSupportsOfflineDelivery()) {
+        builder.append(" channel_supports_offline_delivery=").append(channelSupportsOfflineDelivery);
+      }
+      if (hasOfflineHeartbeatThresholdMs()) {
+        builder.append(" offline_heartbeat_threshold_ms=").append(offlineHeartbeatThresholdMs);
+      }
+      if (hasAllowSuppression()) {
+        builder.append(" allow_suppression=").append(allowSuppression);
+      }
+      builder.append('>');
+    }
+
+    public static ClientConfigP parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoClientProtocol.ClientConfigP(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static ClientConfigP fromMessageNano(com.google.protos.ipc.invalidation.NanoClientProtocol.ClientConfigP message) {
+      if (message == null) { return null; }
+      return new ClientConfigP(com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version.fromMessageNano(message.version),
+          message.networkTimeoutDelayMs,
+          message.writeRetryDelayMs,
+          message.heartbeatIntervalMs,
+          message.perfCounterDelayMs,
+          message.maxExponentialBackoffFactor,
+          message.smearPercent,
+          message.isTransient,
+          message.initialPersistentHeartbeatDelayMs,
+          com.google.ipc.invalidation.ticl.proto.ClientProtocol.ProtocolHandlerConfigP.fromMessageNano(message.protocolHandlerConfig),
+          message.channelSupportsOfflineDelivery,
+          message.offlineHeartbeatThresholdMs,
+          message.allowSuppression);
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoClientProtocol.ClientConfigP toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoClientProtocol.ClientConfigP msg = new com.google.protos.ipc.invalidation.NanoClientProtocol.ClientConfigP();
+      msg.version = version.toMessageNano();
+      msg.networkTimeoutDelayMs = hasNetworkTimeoutDelayMs() ? networkTimeoutDelayMs : null;
+      msg.writeRetryDelayMs = hasWriteRetryDelayMs() ? writeRetryDelayMs : null;
+      msg.heartbeatIntervalMs = hasHeartbeatIntervalMs() ? heartbeatIntervalMs : null;
+      msg.perfCounterDelayMs = hasPerfCounterDelayMs() ? perfCounterDelayMs : null;
+      msg.maxExponentialBackoffFactor = hasMaxExponentialBackoffFactor() ? maxExponentialBackoffFactor : null;
+      msg.smearPercent = hasSmearPercent() ? smearPercent : null;
+      msg.isTransient = hasIsTransient() ? isTransient : null;
+      msg.initialPersistentHeartbeatDelayMs = hasInitialPersistentHeartbeatDelayMs() ? initialPersistentHeartbeatDelayMs : null;
+      msg.protocolHandlerConfig = protocolHandlerConfig.toMessageNano();
+      msg.channelSupportsOfflineDelivery = hasChannelSupportsOfflineDelivery() ? channelSupportsOfflineDelivery : null;
+      msg.offlineHeartbeatThresholdMs = hasOfflineHeartbeatThresholdMs() ? offlineHeartbeatThresholdMs : null;
+      msg.allowSuppression = hasAllowSuppression() ? allowSuppression : null;
+      return msg;
+    }
+  }
+
+  public static final class ConfigChangeMessage extends ProtoWrapper {
+    public static ConfigChangeMessage create(Long nextMessageDelayMs) {
+      return new ConfigChangeMessage(nextMessageDelayMs);
+    }
+
+    public static final ConfigChangeMessage DEFAULT_INSTANCE = new ConfigChangeMessage(null);
+
+    private final long __hazzerBits;
+    private final long nextMessageDelayMs;
+
+    private ConfigChangeMessage(Long nextMessageDelayMs) throws ValidationArgumentException {
+      int hazzerBits = 0;
+      if (nextMessageDelayMs != null) {
+        hazzerBits |= 0x1;
+        positive("next_message_delay_ms", nextMessageDelayMs);
+        this.nextMessageDelayMs = nextMessageDelayMs;
+      } else {
+        this.nextMessageDelayMs = 0;
+      }
+      this.__hazzerBits = hazzerBits;
+    }
+
+    public long getNextMessageDelayMs() { return nextMessageDelayMs; }
+    public boolean hasNextMessageDelayMs() { return (0x1 & __hazzerBits) != 0; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof ConfigChangeMessage)) { return false; }
+      ConfigChangeMessage other = (ConfigChangeMessage) obj;
+      return __hazzerBits == other.__hazzerBits
+          && (!hasNextMessageDelayMs() || nextMessageDelayMs == other.nextMessageDelayMs);
+    }
+
+    @Override protected int computeHashCode() {
+      int result = hash(__hazzerBits);
+      if (hasNextMessageDelayMs()) {
+        result = result * 31 + hash(nextMessageDelayMs);
+      }
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<ConfigChangeMessage:");
+      if (hasNextMessageDelayMs()) {
+        builder.append(" next_message_delay_ms=").append(nextMessageDelayMs);
+      }
+      builder.append('>');
+    }
+
+    public static ConfigChangeMessage parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoClientProtocol.ConfigChangeMessage(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static ConfigChangeMessage fromMessageNano(com.google.protos.ipc.invalidation.NanoClientProtocol.ConfigChangeMessage message) {
+      if (message == null) { return null; }
+      return new ConfigChangeMessage(message.nextMessageDelayMs);
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoClientProtocol.ConfigChangeMessage toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoClientProtocol.ConfigChangeMessage msg = new com.google.protos.ipc.invalidation.NanoClientProtocol.ConfigChangeMessage();
+      msg.nextMessageDelayMs = hasNextMessageDelayMs() ? nextMessageDelayMs : null;
+      return msg;
+    }
+  }
+
+  public static final class ErrorMessage extends ProtoWrapper {
+    public interface Code {
+      public static final int AUTH_FAILURE = 1;
+      public static final int UNKNOWN_FAILURE = 10000;
+    }
+
+    public static ErrorMessage create(int code,
+        String description) {
+      return new ErrorMessage(code, description);
+    }
+
+    private final int code;
+    private final String description;
+
+    private ErrorMessage(Integer code,
+        String description) throws ValidationArgumentException {
+      required("code", code);
+      this.code = code;
+      required("description", description);
+      this.description = description;
+    }
+
+    public int getCode() { return code; }
+
+    public String getDescription() { return description; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof ErrorMessage)) { return false; }
+      ErrorMessage other = (ErrorMessage) obj;
+      return code == other.code
+          && equals(description, other.description);
+    }
+
+    @Override protected int computeHashCode() {
+      int result = 1;
+      result = result * 31 + hash(code);
+      result = result * 31 + description.hashCode();
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<ErrorMessage:");
+      builder.append(" code=").append(code);
+      builder.append(" description=").append(description);
+      builder.append('>');
+    }
+
+    public static ErrorMessage parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoClientProtocol.ErrorMessage(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static ErrorMessage fromMessageNano(com.google.protos.ipc.invalidation.NanoClientProtocol.ErrorMessage message) {
+      if (message == null) { return null; }
+      return new ErrorMessage(message.code,
+          message.description);
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoClientProtocol.ErrorMessage toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoClientProtocol.ErrorMessage msg = new com.google.protos.ipc.invalidation.NanoClientProtocol.ErrorMessage();
+      msg.code = code;
+      msg.description = description;
+      return msg;
+    }
+  }
+}
diff --git a/java/com/google/ipc/invalidation/ticl/proto/CommonProtos.java b/java/com/google/ipc/invalidation/ticl/proto/CommonProtos.java
new file mode 100644
index 0000000..649f984
--- /dev/null
+++ b/java/com/google/ipc/invalidation/ticl/proto/CommonProtos.java
@@ -0,0 +1,120 @@
+/*
+ * 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.proto;
+
+import com.google.common.base.Preconditions;
+import com.google.ipc.invalidation.ticl.proto.AndroidChannel.AndroidEndpointId;
+import com.google.ipc.invalidation.ticl.proto.ChannelCommon.NetworkEndpointId;
+import com.google.ipc.invalidation.ticl.proto.ChannelCommon.NetworkEndpointId.NetworkAddress;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.ClientVersion;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationP;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationP;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationStatus;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSummary;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.ServerHeader;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.StatusP;
+import com.google.ipc.invalidation.ticl.proto.ClientProtocol.Version;
+import com.google.ipc.invalidation.util.Bytes;
+
+
+/** Utilities for creating protocol buffer wrappers. */
+public class CommonProtos {
+
+  public static boolean isAllObjectId(ObjectIdP objectId) {
+    return ClientConstants.ALL_OBJECT_ID.equals(objectId);
+  }
+
+  /** Returns true iff status corresponds to permanent failure. */
+  public static boolean isPermanentFailure(StatusP status) {
+    return status.getCode() == StatusP.Code.PERMANENT_FAILURE;
+  }
+
+  /** Returns true iff status corresponds to success. */
+  public static boolean isSuccess(StatusP status) {
+    return status.getCode() == StatusP.Code.SUCCESS;
+  }
+
+  /** Returns true iff status corresponds to transient failure. */
+  public static boolean isTransientFailure(StatusP status) {
+    return status.getCode() == StatusP.Code.TRANSIENT_FAILURE;
+  }
+
+  /**
+   * Constructs a network endpoint id for an Android client with the given {@code registrationId},
+   * {@code clientKey}, and {@code packageName}.
+   */
+  public static NetworkEndpointId newAndroidEndpointId(String registrationId, String clientKey,
+      String packageName, Version channelVersion) {
+    Preconditions.checkNotNull(registrationId, "Null registration id");
+    Preconditions.checkNotNull(clientKey, "Null client key");
+    Preconditions.checkNotNull(packageName, "Null package name");
+    Preconditions.checkNotNull(channelVersion, "Null channel version");
+
+    AndroidEndpointId endpoint = AndroidEndpointId.create(registrationId, clientKey,
+        /* senderId */ null, channelVersion, packageName);
+    return NetworkEndpointId.create(NetworkAddress.ANDROID, new Bytes(endpoint.toByteArray()),
+        null);
+  }
+
+  public static ClientVersion newClientVersion(String platform, String language,
+      String applicationInfo) {
+    return ClientVersion.create(ClientConstants.CLIENT_VERSION_VALUE, platform, language,
+        applicationInfo);
+  }
+
+  public static StatusP newFailureStatus(boolean isTransient, String description) {
+    return StatusP.create(
+        isTransient ? StatusP.Code.TRANSIENT_FAILURE : StatusP.Code.PERMANENT_FAILURE, description);
+  }
+
+
+  public static InvalidationP newInvalidationP(ObjectIdP objectId, long version,
+      boolean isTrickleRestart, byte[] payload) {
+    return InvalidationP.create(objectId, /* isKnownVersion */ true,
+        version, Bytes.fromByteArray(payload), /* bridgeArrivalTimeMsDeprecated */ null,
+        isTrickleRestart);
+  }
+
+  public static InvalidationP newInvalidationPForUnknownVersion(ObjectIdP oid,
+      long sequenceNumber) {
+    return InvalidationP.create(oid, /* isKnownVersion */ false, sequenceNumber, /* payload */ null,
+    /* bridgeArrivalTimeMsDeprecated */ null, /* isTrickleRestart */ true);
+  }
+
+  public static RegistrationP newRegistrationP(ObjectIdP oid, boolean isReg) {
+    return RegistrationP.create(oid,
+        isReg ? RegistrationP.OpType.REGISTER : RegistrationP.OpType.UNREGISTER);
+  }
+
+  public static ServerHeader newServerHeader(byte[] clientToken, long currentTimeMs,
+      RegistrationSummary registrationSummary, String messageId) {
+    return ServerHeader.create(ClientConstants.PROTOCOL_VERSION, new Bytes(clientToken),
+        registrationSummary, currentTimeMs, messageId);
+  }
+
+  public static StatusP newSuccessStatus() {
+    return StatusP.create(StatusP.Code.SUCCESS, null);
+  }
+
+  public static RegistrationStatus newTransientFailureRegistrationStatus(RegistrationP registration,
+      String description) {
+    return RegistrationStatus.create(registration, newFailureStatus(true, description));
+  }
+
+  // Prevent instantiation.
+  private CommonProtos() {}
+}
diff --git a/java/com/google/ipc/invalidation/ticl/proto/JavaClient.java b/java/com/google/ipc/invalidation/ticl/proto/JavaClient.java
new file mode 100644
index 0000000..fd99c90
--- /dev/null
+++ b/java/com/google/ipc/invalidation/ticl/proto/JavaClient.java
@@ -0,0 +1,1076 @@
+/*
+ * 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.
+ */
+// Generated by j/c/g/ipc/invalidation/common/proto_wrapper_generator
+package com.google.ipc.invalidation.ticl.proto;
+
+import com.google.ipc.invalidation.util.Bytes;
+import com.google.ipc.invalidation.util.ProtoWrapper;
+import com.google.ipc.invalidation.util.ProtoWrapper.ValidationException;
+import com.google.ipc.invalidation.util.TextBuilder;
+import com.google.protobuf.nano.MessageNano;
+import com.google.protobuf.nano.InvalidProtocolBufferNanoException;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+
+public interface JavaClient {
+
+  public static final class BatcherState extends ProtoWrapper {
+    public static BatcherState create(Collection<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP> registration,
+        Collection<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP> unregistration,
+        Collection<com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationP> acknowledgement,
+        Collection<com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSubtree> registrationSubtree,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.InitializeMessage initializeMessage,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.InfoMessage infoMessage) {
+      return new BatcherState(registration, unregistration, acknowledgement, registrationSubtree, initializeMessage, infoMessage);
+    }
+
+    public static final BatcherState DEFAULT_INSTANCE = new BatcherState(null, null, null, null, null, null);
+
+    private final long __hazzerBits;
+    private final List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP> registration;
+    private final List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP> unregistration;
+    private final List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationP> acknowledgement;
+    private final List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSubtree> registrationSubtree;
+    private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.InitializeMessage initializeMessage;
+    private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.InfoMessage infoMessage;
+
+    private BatcherState(Collection<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP> registration,
+        Collection<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP> unregistration,
+        Collection<com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationP> acknowledgement,
+        Collection<com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSubtree> registrationSubtree,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.InitializeMessage initializeMessage,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.InfoMessage infoMessage) {
+      int hazzerBits = 0;
+      this.registration = optional("registration", registration);
+      this.unregistration = optional("unregistration", unregistration);
+      this.acknowledgement = optional("acknowledgement", acknowledgement);
+      this.registrationSubtree = optional("registration_subtree", registrationSubtree);
+      this.initializeMessage = initializeMessage;
+      if (infoMessage != null) {
+        hazzerBits |= 0x1;
+        this.infoMessage = infoMessage;
+      } else {
+        this.infoMessage = com.google.ipc.invalidation.ticl.proto.ClientProtocol.InfoMessage.DEFAULT_INSTANCE;
+      }
+      this.__hazzerBits = hazzerBits;
+    }
+
+    public List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP> getRegistration() { return registration; }
+
+    public List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP> getUnregistration() { return unregistration; }
+
+    public List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationP> getAcknowledgement() { return acknowledgement; }
+
+    public List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSubtree> getRegistrationSubtree() { return registrationSubtree; }
+
+    public com.google.ipc.invalidation.ticl.proto.ClientProtocol.InitializeMessage getNullableInitializeMessage() { return initializeMessage; }
+
+    public com.google.ipc.invalidation.ticl.proto.ClientProtocol.InfoMessage getInfoMessage() { return infoMessage; }
+    public boolean hasInfoMessage() { return (0x1 & __hazzerBits) != 0; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof BatcherState)) { return false; }
+      BatcherState other = (BatcherState) obj;
+      return __hazzerBits == other.__hazzerBits
+          && equals(registration, other.registration)
+          && equals(unregistration, other.unregistration)
+          && equals(acknowledgement, other.acknowledgement)
+          && equals(registrationSubtree, other.registrationSubtree)
+          && equals(initializeMessage, other.initializeMessage)
+          && (!hasInfoMessage() || equals(infoMessage, other.infoMessage));
+    }
+
+    @Override protected int computeHashCode() {
+      int result = hash(__hazzerBits);
+      result = result * 31 + registration.hashCode();
+      result = result * 31 + unregistration.hashCode();
+      result = result * 31 + acknowledgement.hashCode();
+      result = result * 31 + registrationSubtree.hashCode();
+      if (initializeMessage != null) {
+        result = result * 31 + initializeMessage.hashCode();
+      }
+      if (hasInfoMessage()) {
+        result = result * 31 + infoMessage.hashCode();
+      }
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<BatcherState:");
+      builder.append(" registration=[").append(registration).append(']');
+      builder.append(" unregistration=[").append(unregistration).append(']');
+      builder.append(" acknowledgement=[").append(acknowledgement).append(']');
+      builder.append(" registration_subtree=[").append(registrationSubtree).append(']');
+      if (initializeMessage != null) {
+        builder.append(" initialize_message=").append(initializeMessage);
+      }
+      if (hasInfoMessage()) {
+        builder.append(" info_message=").append(infoMessage);
+      }
+      builder.append('>');
+    }
+
+    public static BatcherState parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoJavaClient.BatcherState(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static BatcherState fromMessageNano(com.google.protos.ipc.invalidation.NanoJavaClient.BatcherState message) {
+      if (message == null) { return null; }
+      List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP> registration = new ArrayList<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP>(message.registration.length);
+      for (int i = 0; i < message.registration.length; i++) {
+        registration.add(com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP.fromMessageNano(message.registration[i]));
+      }
+      List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP> unregistration = new ArrayList<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP>(message.unregistration.length);
+      for (int i = 0; i < message.unregistration.length; i++) {
+        unregistration.add(com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP.fromMessageNano(message.unregistration[i]));
+      }
+      List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationP> acknowledgement = new ArrayList<com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationP>(message.acknowledgement.length);
+      for (int i = 0; i < message.acknowledgement.length; i++) {
+        acknowledgement.add(com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationP.fromMessageNano(message.acknowledgement[i]));
+      }
+      List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSubtree> registrationSubtree = new ArrayList<com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSubtree>(message.registrationSubtree.length);
+      for (int i = 0; i < message.registrationSubtree.length; i++) {
+        registrationSubtree.add(com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSubtree.fromMessageNano(message.registrationSubtree[i]));
+      }
+      return new BatcherState(registration,
+          unregistration,
+          acknowledgement,
+          registrationSubtree,
+          com.google.ipc.invalidation.ticl.proto.ClientProtocol.InitializeMessage.fromMessageNano(message.initializeMessage),
+          com.google.ipc.invalidation.ticl.proto.ClientProtocol.InfoMessage.fromMessageNano(message.infoMessage));
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoJavaClient.BatcherState toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoJavaClient.BatcherState msg = new com.google.protos.ipc.invalidation.NanoJavaClient.BatcherState();
+      msg.registration = new com.google.protos.ipc.invalidation.NanoClientProtocol.ObjectIdP[registration.size()];
+      for (int i = 0; i < msg.registration.length; i++) {
+        msg.registration[i] = registration.get(i).toMessageNano();
+      }
+      msg.unregistration = new com.google.protos.ipc.invalidation.NanoClientProtocol.ObjectIdP[unregistration.size()];
+      for (int i = 0; i < msg.unregistration.length; i++) {
+        msg.unregistration[i] = unregistration.get(i).toMessageNano();
+      }
+      msg.acknowledgement = new com.google.protos.ipc.invalidation.NanoClientProtocol.InvalidationP[acknowledgement.size()];
+      for (int i = 0; i < msg.acknowledgement.length; i++) {
+        msg.acknowledgement[i] = acknowledgement.get(i).toMessageNano();
+      }
+      msg.registrationSubtree = new com.google.protos.ipc.invalidation.NanoClientProtocol.RegistrationSubtree[registrationSubtree.size()];
+      for (int i = 0; i < msg.registrationSubtree.length; i++) {
+        msg.registrationSubtree[i] = registrationSubtree.get(i).toMessageNano();
+      }
+      msg.initializeMessage = this.initializeMessage != null ? initializeMessage.toMessageNano() : null;
+      msg.infoMessage = hasInfoMessage() ? infoMessage.toMessageNano() : null;
+      return msg;
+    }
+  }
+
+  public static final class ProtocolHandlerState extends ProtoWrapper {
+    public static ProtocolHandlerState create(Integer messageId,
+        Long lastKnownServerTimeMs,
+        Long nextMessageSendTimeMs,
+        com.google.ipc.invalidation.ticl.proto.JavaClient.BatcherState batcherState) {
+      return new ProtocolHandlerState(messageId, lastKnownServerTimeMs, nextMessageSendTimeMs, batcherState);
+    }
+
+    public static final ProtocolHandlerState DEFAULT_INSTANCE = new ProtocolHandlerState(null, null, null, null);
+
+    private final long __hazzerBits;
+    private final int messageId;
+    private final long lastKnownServerTimeMs;
+    private final long nextMessageSendTimeMs;
+    private final com.google.ipc.invalidation.ticl.proto.JavaClient.BatcherState batcherState;
+
+    private ProtocolHandlerState(Integer messageId,
+        Long lastKnownServerTimeMs,
+        Long nextMessageSendTimeMs,
+        com.google.ipc.invalidation.ticl.proto.JavaClient.BatcherState batcherState) {
+      int hazzerBits = 0;
+      if (messageId != null) {
+        hazzerBits |= 0x1;
+        this.messageId = messageId;
+      } else {
+        this.messageId = 0;
+      }
+      if (lastKnownServerTimeMs != null) {
+        hazzerBits |= 0x2;
+        this.lastKnownServerTimeMs = lastKnownServerTimeMs;
+      } else {
+        this.lastKnownServerTimeMs = 0;
+      }
+      if (nextMessageSendTimeMs != null) {
+        hazzerBits |= 0x4;
+        this.nextMessageSendTimeMs = nextMessageSendTimeMs;
+      } else {
+        this.nextMessageSendTimeMs = 0;
+      }
+      if (batcherState != null) {
+        hazzerBits |= 0x8;
+        this.batcherState = batcherState;
+      } else {
+        this.batcherState = com.google.ipc.invalidation.ticl.proto.JavaClient.BatcherState.DEFAULT_INSTANCE;
+      }
+      this.__hazzerBits = hazzerBits;
+    }
+
+    public int getMessageId() { return messageId; }
+    public boolean hasMessageId() { return (0x1 & __hazzerBits) != 0; }
+
+    public long getLastKnownServerTimeMs() { return lastKnownServerTimeMs; }
+    public boolean hasLastKnownServerTimeMs() { return (0x2 & __hazzerBits) != 0; }
+
+    public long getNextMessageSendTimeMs() { return nextMessageSendTimeMs; }
+    public boolean hasNextMessageSendTimeMs() { return (0x4 & __hazzerBits) != 0; }
+
+    public com.google.ipc.invalidation.ticl.proto.JavaClient.BatcherState getBatcherState() { return batcherState; }
+    public boolean hasBatcherState() { return (0x8 & __hazzerBits) != 0; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof ProtocolHandlerState)) { return false; }
+      ProtocolHandlerState other = (ProtocolHandlerState) obj;
+      return __hazzerBits == other.__hazzerBits
+          && (!hasMessageId() || messageId == other.messageId)
+          && (!hasLastKnownServerTimeMs() || lastKnownServerTimeMs == other.lastKnownServerTimeMs)
+          && (!hasNextMessageSendTimeMs() || nextMessageSendTimeMs == other.nextMessageSendTimeMs)
+          && (!hasBatcherState() || equals(batcherState, other.batcherState));
+    }
+
+    @Override protected int computeHashCode() {
+      int result = hash(__hazzerBits);
+      if (hasMessageId()) {
+        result = result * 31 + hash(messageId);
+      }
+      if (hasLastKnownServerTimeMs()) {
+        result = result * 31 + hash(lastKnownServerTimeMs);
+      }
+      if (hasNextMessageSendTimeMs()) {
+        result = result * 31 + hash(nextMessageSendTimeMs);
+      }
+      if (hasBatcherState()) {
+        result = result * 31 + batcherState.hashCode();
+      }
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<ProtocolHandlerState:");
+      if (hasMessageId()) {
+        builder.append(" message_id=").append(messageId);
+      }
+      if (hasLastKnownServerTimeMs()) {
+        builder.append(" last_known_server_time_ms=").append(lastKnownServerTimeMs);
+      }
+      if (hasNextMessageSendTimeMs()) {
+        builder.append(" next_message_send_time_ms=").append(nextMessageSendTimeMs);
+      }
+      if (hasBatcherState()) {
+        builder.append(" batcher_state=").append(batcherState);
+      }
+      builder.append('>');
+    }
+
+    public static ProtocolHandlerState parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoJavaClient.ProtocolHandlerState(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static ProtocolHandlerState fromMessageNano(com.google.protos.ipc.invalidation.NanoJavaClient.ProtocolHandlerState message) {
+      if (message == null) { return null; }
+      return new ProtocolHandlerState(message.messageId,
+          message.lastKnownServerTimeMs,
+          message.nextMessageSendTimeMs,
+          com.google.ipc.invalidation.ticl.proto.JavaClient.BatcherState.fromMessageNano(message.batcherState));
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoJavaClient.ProtocolHandlerState toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoJavaClient.ProtocolHandlerState msg = new com.google.protos.ipc.invalidation.NanoJavaClient.ProtocolHandlerState();
+      msg.messageId = hasMessageId() ? messageId : null;
+      msg.lastKnownServerTimeMs = hasLastKnownServerTimeMs() ? lastKnownServerTimeMs : null;
+      msg.nextMessageSendTimeMs = hasNextMessageSendTimeMs() ? nextMessageSendTimeMs : null;
+      msg.batcherState = hasBatcherState() ? batcherState.toMessageNano() : null;
+      return msg;
+    }
+  }
+
+  public static final class RegistrationManagerStateP extends ProtoWrapper {
+    public static RegistrationManagerStateP create(Collection<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP> registrations,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSummary lastKnownServerSummary,
+        Collection<com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationP> pendingOperations) {
+      return new RegistrationManagerStateP(registrations, lastKnownServerSummary, pendingOperations);
+    }
+
+    public static final RegistrationManagerStateP DEFAULT_INSTANCE = new RegistrationManagerStateP(null, null, null);
+
+    private final List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP> registrations;
+    private final com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSummary lastKnownServerSummary;
+    private final List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationP> pendingOperations;
+
+    private RegistrationManagerStateP(Collection<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP> registrations,
+        com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSummary lastKnownServerSummary,
+        Collection<com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationP> pendingOperations) {
+      this.registrations = optional("registrations", registrations);
+      this.lastKnownServerSummary = lastKnownServerSummary;
+      this.pendingOperations = optional("pending_operations", pendingOperations);
+    }
+
+    public List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP> getRegistrations() { return registrations; }
+
+    public com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSummary getNullableLastKnownServerSummary() { return lastKnownServerSummary; }
+
+    public List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationP> getPendingOperations() { return pendingOperations; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof RegistrationManagerStateP)) { return false; }
+      RegistrationManagerStateP other = (RegistrationManagerStateP) obj;
+      return equals(registrations, other.registrations)
+          && equals(lastKnownServerSummary, other.lastKnownServerSummary)
+          && equals(pendingOperations, other.pendingOperations);
+    }
+
+    @Override protected int computeHashCode() {
+      int result = 1;
+      result = result * 31 + registrations.hashCode();
+      if (lastKnownServerSummary != null) {
+        result = result * 31 + lastKnownServerSummary.hashCode();
+      }
+      result = result * 31 + pendingOperations.hashCode();
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<RegistrationManagerStateP:");
+      builder.append(" registrations=[").append(registrations).append(']');
+      if (lastKnownServerSummary != null) {
+        builder.append(" last_known_server_summary=").append(lastKnownServerSummary);
+      }
+      builder.append(" pending_operations=[").append(pendingOperations).append(']');
+      builder.append('>');
+    }
+
+    public static RegistrationManagerStateP parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoJavaClient.RegistrationManagerStateP(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static RegistrationManagerStateP fromMessageNano(com.google.protos.ipc.invalidation.NanoJavaClient.RegistrationManagerStateP message) {
+      if (message == null) { return null; }
+      List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP> registrations = new ArrayList<com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP>(message.registrations.length);
+      for (int i = 0; i < message.registrations.length; i++) {
+        registrations.add(com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP.fromMessageNano(message.registrations[i]));
+      }
+      List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationP> pendingOperations = new ArrayList<com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationP>(message.pendingOperations.length);
+      for (int i = 0; i < message.pendingOperations.length; i++) {
+        pendingOperations.add(com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationP.fromMessageNano(message.pendingOperations[i]));
+      }
+      return new RegistrationManagerStateP(registrations,
+          com.google.ipc.invalidation.ticl.proto.ClientProtocol.RegistrationSummary.fromMessageNano(message.lastKnownServerSummary),
+          pendingOperations);
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoJavaClient.RegistrationManagerStateP toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoJavaClient.RegistrationManagerStateP msg = new com.google.protos.ipc.invalidation.NanoJavaClient.RegistrationManagerStateP();
+      msg.registrations = new com.google.protos.ipc.invalidation.NanoClientProtocol.ObjectIdP[registrations.size()];
+      for (int i = 0; i < msg.registrations.length; i++) {
+        msg.registrations[i] = registrations.get(i).toMessageNano();
+      }
+      msg.lastKnownServerSummary = this.lastKnownServerSummary != null ? lastKnownServerSummary.toMessageNano() : null;
+      msg.pendingOperations = new com.google.protos.ipc.invalidation.NanoClientProtocol.RegistrationP[pendingOperations.size()];
+      for (int i = 0; i < msg.pendingOperations.length; i++) {
+        msg.pendingOperations[i] = pendingOperations.get(i).toMessageNano();
+      }
+      return msg;
+    }
+  }
+
+  public static final class RecurringTaskState extends ProtoWrapper {
+    public static RecurringTaskState create(Integer initialDelayMs,
+        Integer timeoutDelayMs,
+        Boolean scheduled,
+        com.google.ipc.invalidation.ticl.proto.Client.ExponentialBackoffState backoffState) {
+      return new RecurringTaskState(initialDelayMs, timeoutDelayMs, scheduled, backoffState);
+    }
+
+    public static final RecurringTaskState DEFAULT_INSTANCE = new RecurringTaskState(null, null, null, null);
+
+    private final long __hazzerBits;
+    private final int initialDelayMs;
+    private final int timeoutDelayMs;
+    private final boolean scheduled;
+    private final com.google.ipc.invalidation.ticl.proto.Client.ExponentialBackoffState backoffState;
+
+    private RecurringTaskState(Integer initialDelayMs,
+        Integer timeoutDelayMs,
+        Boolean scheduled,
+        com.google.ipc.invalidation.ticl.proto.Client.ExponentialBackoffState backoffState) {
+      int hazzerBits = 0;
+      if (initialDelayMs != null) {
+        hazzerBits |= 0x1;
+        this.initialDelayMs = initialDelayMs;
+      } else {
+        this.initialDelayMs = 0;
+      }
+      if (timeoutDelayMs != null) {
+        hazzerBits |= 0x2;
+        this.timeoutDelayMs = timeoutDelayMs;
+      } else {
+        this.timeoutDelayMs = 0;
+      }
+      if (scheduled != null) {
+        hazzerBits |= 0x4;
+        this.scheduled = scheduled;
+      } else {
+        this.scheduled = false;
+      }
+      if (backoffState != null) {
+        hazzerBits |= 0x8;
+        this.backoffState = backoffState;
+      } else {
+        this.backoffState = com.google.ipc.invalidation.ticl.proto.Client.ExponentialBackoffState.DEFAULT_INSTANCE;
+      }
+      this.__hazzerBits = hazzerBits;
+    }
+
+    public int getInitialDelayMs() { return initialDelayMs; }
+    public boolean hasInitialDelayMs() { return (0x1 & __hazzerBits) != 0; }
+
+    public int getTimeoutDelayMs() { return timeoutDelayMs; }
+    public boolean hasTimeoutDelayMs() { return (0x2 & __hazzerBits) != 0; }
+
+    public boolean getScheduled() { return scheduled; }
+    public boolean hasScheduled() { return (0x4 & __hazzerBits) != 0; }
+
+    public com.google.ipc.invalidation.ticl.proto.Client.ExponentialBackoffState getBackoffState() { return backoffState; }
+    public boolean hasBackoffState() { return (0x8 & __hazzerBits) != 0; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof RecurringTaskState)) { return false; }
+      RecurringTaskState other = (RecurringTaskState) obj;
+      return __hazzerBits == other.__hazzerBits
+          && (!hasInitialDelayMs() || initialDelayMs == other.initialDelayMs)
+          && (!hasTimeoutDelayMs() || timeoutDelayMs == other.timeoutDelayMs)
+          && (!hasScheduled() || scheduled == other.scheduled)
+          && (!hasBackoffState() || equals(backoffState, other.backoffState));
+    }
+
+    @Override protected int computeHashCode() {
+      int result = hash(__hazzerBits);
+      if (hasInitialDelayMs()) {
+        result = result * 31 + hash(initialDelayMs);
+      }
+      if (hasTimeoutDelayMs()) {
+        result = result * 31 + hash(timeoutDelayMs);
+      }
+      if (hasScheduled()) {
+        result = result * 31 + hash(scheduled);
+      }
+      if (hasBackoffState()) {
+        result = result * 31 + backoffState.hashCode();
+      }
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<RecurringTaskState:");
+      if (hasInitialDelayMs()) {
+        builder.append(" initial_delay_ms=").append(initialDelayMs);
+      }
+      if (hasTimeoutDelayMs()) {
+        builder.append(" timeout_delay_ms=").append(timeoutDelayMs);
+      }
+      if (hasScheduled()) {
+        builder.append(" scheduled=").append(scheduled);
+      }
+      if (hasBackoffState()) {
+        builder.append(" backoff_state=").append(backoffState);
+      }
+      builder.append('>');
+    }
+
+    public static RecurringTaskState parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoJavaClient.RecurringTaskState(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static RecurringTaskState fromMessageNano(com.google.protos.ipc.invalidation.NanoJavaClient.RecurringTaskState message) {
+      if (message == null) { return null; }
+      return new RecurringTaskState(message.initialDelayMs,
+          message.timeoutDelayMs,
+          message.scheduled,
+          com.google.ipc.invalidation.ticl.proto.Client.ExponentialBackoffState.fromMessageNano(message.backoffState));
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoJavaClient.RecurringTaskState toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoJavaClient.RecurringTaskState msg = new com.google.protos.ipc.invalidation.NanoJavaClient.RecurringTaskState();
+      msg.initialDelayMs = hasInitialDelayMs() ? initialDelayMs : null;
+      msg.timeoutDelayMs = hasTimeoutDelayMs() ? timeoutDelayMs : null;
+      msg.scheduled = hasScheduled() ? scheduled : null;
+      msg.backoffState = hasBackoffState() ? backoffState.toMessageNano() : null;
+      return msg;
+    }
+  }
+
+  public static final class StatisticsState extends ProtoWrapper {
+    public static StatisticsState create(Collection<com.google.ipc.invalidation.ticl.proto.ClientProtocol.PropertyRecord> counter) {
+      return new StatisticsState(counter);
+    }
+
+    public static final StatisticsState DEFAULT_INSTANCE = new StatisticsState(null);
+
+    private final List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.PropertyRecord> counter;
+
+    private StatisticsState(Collection<com.google.ipc.invalidation.ticl.proto.ClientProtocol.PropertyRecord> counter) {
+      this.counter = optional("counter", counter);
+    }
+
+    public List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.PropertyRecord> getCounter() { return counter; }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof StatisticsState)) { return false; }
+      StatisticsState other = (StatisticsState) obj;
+      return equals(counter, other.counter);
+    }
+
+    @Override protected int computeHashCode() {
+      int result = 1;
+      result = result * 31 + counter.hashCode();
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<StatisticsState:");
+      builder.append(" counter=[").append(counter).append(']');
+      builder.append('>');
+    }
+
+    public static StatisticsState parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoJavaClient.StatisticsState(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static StatisticsState fromMessageNano(com.google.protos.ipc.invalidation.NanoJavaClient.StatisticsState message) {
+      if (message == null) { return null; }
+      List<com.google.ipc.invalidation.ticl.proto.ClientProtocol.PropertyRecord> counter = new ArrayList<com.google.ipc.invalidation.ticl.proto.ClientProtocol.PropertyRecord>(message.counter.length);
+      for (int i = 0; i < message.counter.length; i++) {
+        counter.add(com.google.ipc.invalidation.ticl.proto.ClientProtocol.PropertyRecord.fromMessageNano(message.counter[i]));
+      }
+      return new StatisticsState(counter);
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoJavaClient.StatisticsState toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoJavaClient.StatisticsState msg = new com.google.protos.ipc.invalidation.NanoJavaClient.StatisticsState();
+      msg.counter = new com.google.protos.ipc.invalidation.NanoClientProtocol.PropertyRecord[counter.size()];
+      for (int i = 0; i < msg.counter.length; i++) {
+        msg.counter[i] = counter.get(i).toMessageNano();
+      }
+      return msg;
+    }
+  }
+
+  public static final class InvalidationClientState extends ProtoWrapper {
+    public static final class Builder {
+      public com.google.ipc.invalidation.ticl.proto.Client.RunStateP runState;
+      public Bytes clientToken;
+      public Bytes nonce;
+      public Boolean shouldSendRegistrations;
+      public Long lastMessageSendTimeMs;
+      public Boolean isOnline;
+      public com.google.ipc.invalidation.ticl.proto.JavaClient.ProtocolHandlerState protocolHandlerState;
+      public com.google.ipc.invalidation.ticl.proto.JavaClient.RegistrationManagerStateP registrationManagerState;
+      public com.google.ipc.invalidation.ticl.proto.JavaClient.RecurringTaskState acquireTokenTaskState;
+      public com.google.ipc.invalidation.ticl.proto.JavaClient.RecurringTaskState regSyncHeartbeatTaskState;
+      public com.google.ipc.invalidation.ticl.proto.JavaClient.RecurringTaskState persistentWriteTaskState;
+      public com.google.ipc.invalidation.ticl.proto.JavaClient.RecurringTaskState heartbeatTaskState;
+      public com.google.ipc.invalidation.ticl.proto.JavaClient.RecurringTaskState batchingTaskState;
+      public com.google.ipc.invalidation.ticl.proto.Client.PersistentTiclState lastWrittenState;
+      public com.google.ipc.invalidation.ticl.proto.JavaClient.StatisticsState statisticsState;
+      public Builder() {
+      }
+
+      public InvalidationClientState build() {
+        return new InvalidationClientState(runState, clientToken, nonce, shouldSendRegistrations, lastMessageSendTimeMs, isOnline, protocolHandlerState, registrationManagerState, acquireTokenTaskState, regSyncHeartbeatTaskState, persistentWriteTaskState, heartbeatTaskState, batchingTaskState, lastWrittenState, statisticsState);
+      }
+    }
+
+    public static InvalidationClientState create(com.google.ipc.invalidation.ticl.proto.Client.RunStateP runState,
+        Bytes clientToken,
+        Bytes nonce,
+        Boolean shouldSendRegistrations,
+        Long lastMessageSendTimeMs,
+        Boolean isOnline,
+        com.google.ipc.invalidation.ticl.proto.JavaClient.ProtocolHandlerState protocolHandlerState,
+        com.google.ipc.invalidation.ticl.proto.JavaClient.RegistrationManagerStateP registrationManagerState,
+        com.google.ipc.invalidation.ticl.proto.JavaClient.RecurringTaskState acquireTokenTaskState,
+        com.google.ipc.invalidation.ticl.proto.JavaClient.RecurringTaskState regSyncHeartbeatTaskState,
+        com.google.ipc.invalidation.ticl.proto.JavaClient.RecurringTaskState persistentWriteTaskState,
+        com.google.ipc.invalidation.ticl.proto.JavaClient.RecurringTaskState heartbeatTaskState,
+        com.google.ipc.invalidation.ticl.proto.JavaClient.RecurringTaskState batchingTaskState,
+        com.google.ipc.invalidation.ticl.proto.Client.PersistentTiclState lastWrittenState,
+        com.google.ipc.invalidation.ticl.proto.JavaClient.StatisticsState statisticsState) {
+      return new InvalidationClientState(runState, clientToken, nonce, shouldSendRegistrations, lastMessageSendTimeMs, isOnline, protocolHandlerState, registrationManagerState, acquireTokenTaskState, regSyncHeartbeatTaskState, persistentWriteTaskState, heartbeatTaskState, batchingTaskState, lastWrittenState, statisticsState);
+    }
+
+    public static final InvalidationClientState DEFAULT_INSTANCE = new InvalidationClientState(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null);
+
+    private final long __hazzerBits;
+    private final com.google.ipc.invalidation.ticl.proto.Client.RunStateP runState;
+    private final Bytes clientToken;
+    private final Bytes nonce;
+    private final boolean shouldSendRegistrations;
+    private final long lastMessageSendTimeMs;
+    private final boolean isOnline;
+    private final com.google.ipc.invalidation.ticl.proto.JavaClient.ProtocolHandlerState protocolHandlerState;
+    private final com.google.ipc.invalidation.ticl.proto.JavaClient.RegistrationManagerStateP registrationManagerState;
+    private final com.google.ipc.invalidation.ticl.proto.JavaClient.RecurringTaskState acquireTokenTaskState;
+    private final com.google.ipc.invalidation.ticl.proto.JavaClient.RecurringTaskState regSyncHeartbeatTaskState;
+    private final com.google.ipc.invalidation.ticl.proto.JavaClient.RecurringTaskState persistentWriteTaskState;
+    private final com.google.ipc.invalidation.ticl.proto.JavaClient.RecurringTaskState heartbeatTaskState;
+    private final com.google.ipc.invalidation.ticl.proto.JavaClient.RecurringTaskState batchingTaskState;
+    private final com.google.ipc.invalidation.ticl.proto.Client.PersistentTiclState lastWrittenState;
+    private final com.google.ipc.invalidation.ticl.proto.JavaClient.StatisticsState statisticsState;
+
+    private InvalidationClientState(com.google.ipc.invalidation.ticl.proto.Client.RunStateP runState,
+        Bytes clientToken,
+        Bytes nonce,
+        Boolean shouldSendRegistrations,
+        Long lastMessageSendTimeMs,
+        Boolean isOnline,
+        com.google.ipc.invalidation.ticl.proto.JavaClient.ProtocolHandlerState protocolHandlerState,
+        com.google.ipc.invalidation.ticl.proto.JavaClient.RegistrationManagerStateP registrationManagerState,
+        com.google.ipc.invalidation.ticl.proto.JavaClient.RecurringTaskState acquireTokenTaskState,
+        com.google.ipc.invalidation.ticl.proto.JavaClient.RecurringTaskState regSyncHeartbeatTaskState,
+        com.google.ipc.invalidation.ticl.proto.JavaClient.RecurringTaskState persistentWriteTaskState,
+        com.google.ipc.invalidation.ticl.proto.JavaClient.RecurringTaskState heartbeatTaskState,
+        com.google.ipc.invalidation.ticl.proto.JavaClient.RecurringTaskState batchingTaskState,
+        com.google.ipc.invalidation.ticl.proto.Client.PersistentTiclState lastWrittenState,
+        com.google.ipc.invalidation.ticl.proto.JavaClient.StatisticsState statisticsState) {
+      int hazzerBits = 0;
+      if (runState != null) {
+        hazzerBits |= 0x1;
+        this.runState = runState;
+      } else {
+        this.runState = com.google.ipc.invalidation.ticl.proto.Client.RunStateP.DEFAULT_INSTANCE;
+      }
+      if (clientToken != null) {
+        hazzerBits |= 0x2;
+        this.clientToken = clientToken;
+      } else {
+        this.clientToken = Bytes.EMPTY_BYTES;
+      }
+      if (nonce != null) {
+        hazzerBits |= 0x4;
+        this.nonce = nonce;
+      } else {
+        this.nonce = Bytes.EMPTY_BYTES;
+      }
+      if (shouldSendRegistrations != null) {
+        hazzerBits |= 0x8;
+        this.shouldSendRegistrations = shouldSendRegistrations;
+      } else {
+        this.shouldSendRegistrations = false;
+      }
+      if (lastMessageSendTimeMs != null) {
+        hazzerBits |= 0x10;
+        this.lastMessageSendTimeMs = lastMessageSendTimeMs;
+      } else {
+        this.lastMessageSendTimeMs = 0;
+      }
+      if (isOnline != null) {
+        hazzerBits |= 0x20;
+        this.isOnline = isOnline;
+      } else {
+        this.isOnline = false;
+      }
+      if (protocolHandlerState != null) {
+        hazzerBits |= 0x40;
+        this.protocolHandlerState = protocolHandlerState;
+      } else {
+        this.protocolHandlerState = com.google.ipc.invalidation.ticl.proto.JavaClient.ProtocolHandlerState.DEFAULT_INSTANCE;
+      }
+      if (registrationManagerState != null) {
+        hazzerBits |= 0x80;
+        this.registrationManagerState = registrationManagerState;
+      } else {
+        this.registrationManagerState = com.google.ipc.invalidation.ticl.proto.JavaClient.RegistrationManagerStateP.DEFAULT_INSTANCE;
+      }
+      if (acquireTokenTaskState != null) {
+        hazzerBits |= 0x100;
+        this.acquireTokenTaskState = acquireTokenTaskState;
+      } else {
+        this.acquireTokenTaskState = com.google.ipc.invalidation.ticl.proto.JavaClient.RecurringTaskState.DEFAULT_INSTANCE;
+      }
+      if (regSyncHeartbeatTaskState != null) {
+        hazzerBits |= 0x200;
+        this.regSyncHeartbeatTaskState = regSyncHeartbeatTaskState;
+      } else {
+        this.regSyncHeartbeatTaskState = com.google.ipc.invalidation.ticl.proto.JavaClient.RecurringTaskState.DEFAULT_INSTANCE;
+      }
+      if (persistentWriteTaskState != null) {
+        hazzerBits |= 0x400;
+        this.persistentWriteTaskState = persistentWriteTaskState;
+      } else {
+        this.persistentWriteTaskState = com.google.ipc.invalidation.ticl.proto.JavaClient.RecurringTaskState.DEFAULT_INSTANCE;
+      }
+      if (heartbeatTaskState != null) {
+        hazzerBits |= 0x800;
+        this.heartbeatTaskState = heartbeatTaskState;
+      } else {
+        this.heartbeatTaskState = com.google.ipc.invalidation.ticl.proto.JavaClient.RecurringTaskState.DEFAULT_INSTANCE;
+      }
+      if (batchingTaskState != null) {
+        hazzerBits |= 0x1000;
+        this.batchingTaskState = batchingTaskState;
+      } else {
+        this.batchingTaskState = com.google.ipc.invalidation.ticl.proto.JavaClient.RecurringTaskState.DEFAULT_INSTANCE;
+      }
+      if (lastWrittenState != null) {
+        hazzerBits |= 0x2000;
+        this.lastWrittenState = lastWrittenState;
+      } else {
+        this.lastWrittenState = com.google.ipc.invalidation.ticl.proto.Client.PersistentTiclState.DEFAULT_INSTANCE;
+      }
+      if (statisticsState != null) {
+        hazzerBits |= 0x4000;
+        this.statisticsState = statisticsState;
+      } else {
+        this.statisticsState = com.google.ipc.invalidation.ticl.proto.JavaClient.StatisticsState.DEFAULT_INSTANCE;
+      }
+      this.__hazzerBits = hazzerBits;
+    }
+
+    public com.google.ipc.invalidation.ticl.proto.Client.RunStateP getRunState() { return runState; }
+    public boolean hasRunState() { return (0x1 & __hazzerBits) != 0; }
+
+    public Bytes getClientToken() { return clientToken; }
+    public boolean hasClientToken() { return (0x2 & __hazzerBits) != 0; }
+
+    public Bytes getNonce() { return nonce; }
+    public boolean hasNonce() { return (0x4 & __hazzerBits) != 0; }
+
+    public boolean getShouldSendRegistrations() { return shouldSendRegistrations; }
+    public boolean hasShouldSendRegistrations() { return (0x8 & __hazzerBits) != 0; }
+
+    public long getLastMessageSendTimeMs() { return lastMessageSendTimeMs; }
+    public boolean hasLastMessageSendTimeMs() { return (0x10 & __hazzerBits) != 0; }
+
+    public boolean getIsOnline() { return isOnline; }
+    public boolean hasIsOnline() { return (0x20 & __hazzerBits) != 0; }
+
+    public com.google.ipc.invalidation.ticl.proto.JavaClient.ProtocolHandlerState getProtocolHandlerState() { return protocolHandlerState; }
+    public boolean hasProtocolHandlerState() { return (0x40 & __hazzerBits) != 0; }
+
+    public com.google.ipc.invalidation.ticl.proto.JavaClient.RegistrationManagerStateP getRegistrationManagerState() { return registrationManagerState; }
+    public boolean hasRegistrationManagerState() { return (0x80 & __hazzerBits) != 0; }
+
+    public com.google.ipc.invalidation.ticl.proto.JavaClient.RecurringTaskState getAcquireTokenTaskState() { return acquireTokenTaskState; }
+    public boolean hasAcquireTokenTaskState() { return (0x100 & __hazzerBits) != 0; }
+
+    public com.google.ipc.invalidation.ticl.proto.JavaClient.RecurringTaskState getRegSyncHeartbeatTaskState() { return regSyncHeartbeatTaskState; }
+    public boolean hasRegSyncHeartbeatTaskState() { return (0x200 & __hazzerBits) != 0; }
+
+    public com.google.ipc.invalidation.ticl.proto.JavaClient.RecurringTaskState getPersistentWriteTaskState() { return persistentWriteTaskState; }
+    public boolean hasPersistentWriteTaskState() { return (0x400 & __hazzerBits) != 0; }
+
+    public com.google.ipc.invalidation.ticl.proto.JavaClient.RecurringTaskState getHeartbeatTaskState() { return heartbeatTaskState; }
+    public boolean hasHeartbeatTaskState() { return (0x800 & __hazzerBits) != 0; }
+
+    public com.google.ipc.invalidation.ticl.proto.JavaClient.RecurringTaskState getBatchingTaskState() { return batchingTaskState; }
+    public boolean hasBatchingTaskState() { return (0x1000 & __hazzerBits) != 0; }
+
+    public com.google.ipc.invalidation.ticl.proto.Client.PersistentTiclState getLastWrittenState() { return lastWrittenState; }
+    public boolean hasLastWrittenState() { return (0x2000 & __hazzerBits) != 0; }
+
+    public com.google.ipc.invalidation.ticl.proto.JavaClient.StatisticsState getStatisticsState() { return statisticsState; }
+    public boolean hasStatisticsState() { return (0x4000 & __hazzerBits) != 0; }
+
+    public Builder toBuilder() {
+      Builder builder = new Builder();
+      if (hasRunState()) {
+        builder.runState = runState;
+      }
+      if (hasClientToken()) {
+        builder.clientToken = clientToken;
+      }
+      if (hasNonce()) {
+        builder.nonce = nonce;
+      }
+      if (hasShouldSendRegistrations()) {
+        builder.shouldSendRegistrations = shouldSendRegistrations;
+      }
+      if (hasLastMessageSendTimeMs()) {
+        builder.lastMessageSendTimeMs = lastMessageSendTimeMs;
+      }
+      if (hasIsOnline()) {
+        builder.isOnline = isOnline;
+      }
+      if (hasProtocolHandlerState()) {
+        builder.protocolHandlerState = protocolHandlerState;
+      }
+      if (hasRegistrationManagerState()) {
+        builder.registrationManagerState = registrationManagerState;
+      }
+      if (hasAcquireTokenTaskState()) {
+        builder.acquireTokenTaskState = acquireTokenTaskState;
+      }
+      if (hasRegSyncHeartbeatTaskState()) {
+        builder.regSyncHeartbeatTaskState = regSyncHeartbeatTaskState;
+      }
+      if (hasPersistentWriteTaskState()) {
+        builder.persistentWriteTaskState = persistentWriteTaskState;
+      }
+      if (hasHeartbeatTaskState()) {
+        builder.heartbeatTaskState = heartbeatTaskState;
+      }
+      if (hasBatchingTaskState()) {
+        builder.batchingTaskState = batchingTaskState;
+      }
+      if (hasLastWrittenState()) {
+        builder.lastWrittenState = lastWrittenState;
+      }
+      if (hasStatisticsState()) {
+        builder.statisticsState = statisticsState;
+      }
+      return builder;
+    }
+
+    @Override public final boolean equals(Object obj) {
+      if (this == obj) { return true; }
+      if (!(obj instanceof InvalidationClientState)) { return false; }
+      InvalidationClientState other = (InvalidationClientState) obj;
+      return __hazzerBits == other.__hazzerBits
+          && (!hasRunState() || equals(runState, other.runState))
+          && (!hasClientToken() || equals(clientToken, other.clientToken))
+          && (!hasNonce() || equals(nonce, other.nonce))
+          && (!hasShouldSendRegistrations() || shouldSendRegistrations == other.shouldSendRegistrations)
+          && (!hasLastMessageSendTimeMs() || lastMessageSendTimeMs == other.lastMessageSendTimeMs)
+          && (!hasIsOnline() || isOnline == other.isOnline)
+          && (!hasProtocolHandlerState() || equals(protocolHandlerState, other.protocolHandlerState))
+          && (!hasRegistrationManagerState() || equals(registrationManagerState, other.registrationManagerState))
+          && (!hasAcquireTokenTaskState() || equals(acquireTokenTaskState, other.acquireTokenTaskState))
+          && (!hasRegSyncHeartbeatTaskState() || equals(regSyncHeartbeatTaskState, other.regSyncHeartbeatTaskState))
+          && (!hasPersistentWriteTaskState() || equals(persistentWriteTaskState, other.persistentWriteTaskState))
+          && (!hasHeartbeatTaskState() || equals(heartbeatTaskState, other.heartbeatTaskState))
+          && (!hasBatchingTaskState() || equals(batchingTaskState, other.batchingTaskState))
+          && (!hasLastWrittenState() || equals(lastWrittenState, other.lastWrittenState))
+          && (!hasStatisticsState() || equals(statisticsState, other.statisticsState));
+    }
+
+    @Override protected int computeHashCode() {
+      int result = hash(__hazzerBits);
+      if (hasRunState()) {
+        result = result * 31 + runState.hashCode();
+      }
+      if (hasClientToken()) {
+        result = result * 31 + clientToken.hashCode();
+      }
+      if (hasNonce()) {
+        result = result * 31 + nonce.hashCode();
+      }
+      if (hasShouldSendRegistrations()) {
+        result = result * 31 + hash(shouldSendRegistrations);
+      }
+      if (hasLastMessageSendTimeMs()) {
+        result = result * 31 + hash(lastMessageSendTimeMs);
+      }
+      if (hasIsOnline()) {
+        result = result * 31 + hash(isOnline);
+      }
+      if (hasProtocolHandlerState()) {
+        result = result * 31 + protocolHandlerState.hashCode();
+      }
+      if (hasRegistrationManagerState()) {
+        result = result * 31 + registrationManagerState.hashCode();
+      }
+      if (hasAcquireTokenTaskState()) {
+        result = result * 31 + acquireTokenTaskState.hashCode();
+      }
+      if (hasRegSyncHeartbeatTaskState()) {
+        result = result * 31 + regSyncHeartbeatTaskState.hashCode();
+      }
+      if (hasPersistentWriteTaskState()) {
+        result = result * 31 + persistentWriteTaskState.hashCode();
+      }
+      if (hasHeartbeatTaskState()) {
+        result = result * 31 + heartbeatTaskState.hashCode();
+      }
+      if (hasBatchingTaskState()) {
+        result = result * 31 + batchingTaskState.hashCode();
+      }
+      if (hasLastWrittenState()) {
+        result = result * 31 + lastWrittenState.hashCode();
+      }
+      if (hasStatisticsState()) {
+        result = result * 31 + statisticsState.hashCode();
+      }
+      return result;
+    }
+
+    @Override public void toCompactString(TextBuilder builder) {
+      builder.append("<InvalidationClientState:");
+      if (hasRunState()) {
+        builder.append(" run_state=").append(runState);
+      }
+      if (hasClientToken()) {
+        builder.append(" client_token=").append(clientToken);
+      }
+      if (hasNonce()) {
+        builder.append(" nonce=").append(nonce);
+      }
+      if (hasShouldSendRegistrations()) {
+        builder.append(" should_send_registrations=").append(shouldSendRegistrations);
+      }
+      if (hasLastMessageSendTimeMs()) {
+        builder.append(" last_message_send_time_ms=").append(lastMessageSendTimeMs);
+      }
+      if (hasIsOnline()) {
+        builder.append(" is_online=").append(isOnline);
+      }
+      if (hasProtocolHandlerState()) {
+        builder.append(" protocol_handler_state=").append(protocolHandlerState);
+      }
+      if (hasRegistrationManagerState()) {
+        builder.append(" registration_manager_state=").append(registrationManagerState);
+      }
+      if (hasAcquireTokenTaskState()) {
+        builder.append(" acquire_token_task_state=").append(acquireTokenTaskState);
+      }
+      if (hasRegSyncHeartbeatTaskState()) {
+        builder.append(" reg_sync_heartbeat_task_state=").append(regSyncHeartbeatTaskState);
+      }
+      if (hasPersistentWriteTaskState()) {
+        builder.append(" persistent_write_task_state=").append(persistentWriteTaskState);
+      }
+      if (hasHeartbeatTaskState()) {
+        builder.append(" heartbeat_task_state=").append(heartbeatTaskState);
+      }
+      if (hasBatchingTaskState()) {
+        builder.append(" batching_task_state=").append(batchingTaskState);
+      }
+      if (hasLastWrittenState()) {
+        builder.append(" last_written_state=").append(lastWrittenState);
+      }
+      if (hasStatisticsState()) {
+        builder.append(" statistics_state=").append(statisticsState);
+      }
+      builder.append('>');
+    }
+
+    public static InvalidationClientState parseFrom(byte[] data) throws ValidationException {
+      try {
+        return fromMessageNano(MessageNano.mergeFrom(new com.google.protos.ipc.invalidation.NanoJavaClient.InvalidationClientState(), data));
+      } catch (InvalidProtocolBufferNanoException exception) {
+        throw new ValidationException(exception);
+      } catch (ValidationArgumentException exception) {
+        throw new ValidationException(exception.getMessage());
+      }
+    }
+
+    static InvalidationClientState fromMessageNano(com.google.protos.ipc.invalidation.NanoJavaClient.InvalidationClientState message) {
+      if (message == null) { return null; }
+      return new InvalidationClientState(com.google.ipc.invalidation.ticl.proto.Client.RunStateP.fromMessageNano(message.runState),
+          Bytes.fromByteArray(message.clientToken),
+          Bytes.fromByteArray(message.nonce),
+          message.shouldSendRegistrations,
+          message.lastMessageSendTimeMs,
+          message.isOnline,
+          com.google.ipc.invalidation.ticl.proto.JavaClient.ProtocolHandlerState.fromMessageNano(message.protocolHandlerState),
+          com.google.ipc.invalidation.ticl.proto.JavaClient.RegistrationManagerStateP.fromMessageNano(message.registrationManagerState),
+          com.google.ipc.invalidation.ticl.proto.JavaClient.RecurringTaskState.fromMessageNano(message.acquireTokenTaskState),
+          com.google.ipc.invalidation.ticl.proto.JavaClient.RecurringTaskState.fromMessageNano(message.regSyncHeartbeatTaskState),
+          com.google.ipc.invalidation.ticl.proto.JavaClient.RecurringTaskState.fromMessageNano(message.persistentWriteTaskState),
+          com.google.ipc.invalidation.ticl.proto.JavaClient.RecurringTaskState.fromMessageNano(message.heartbeatTaskState),
+          com.google.ipc.invalidation.ticl.proto.JavaClient.RecurringTaskState.fromMessageNano(message.batchingTaskState),
+          com.google.ipc.invalidation.ticl.proto.Client.PersistentTiclState.fromMessageNano(message.lastWrittenState),
+          com.google.ipc.invalidation.ticl.proto.JavaClient.StatisticsState.fromMessageNano(message.statisticsState));
+    }
+
+    public byte[] toByteArray() {
+      return MessageNano.toByteArray(toMessageNano());
+    }
+
+    com.google.protos.ipc.invalidation.NanoJavaClient.InvalidationClientState toMessageNano() {
+      com.google.protos.ipc.invalidation.NanoJavaClient.InvalidationClientState msg = new com.google.protos.ipc.invalidation.NanoJavaClient.InvalidationClientState();
+      msg.runState = hasRunState() ? runState.toMessageNano() : null;
+      msg.clientToken = hasClientToken() ? clientToken.getByteArray() : null;
+      msg.nonce = hasNonce() ? nonce.getByteArray() : null;
+      msg.shouldSendRegistrations = hasShouldSendRegistrations() ? shouldSendRegistrations : null;
+      msg.lastMessageSendTimeMs = hasLastMessageSendTimeMs() ? lastMessageSendTimeMs : null;
+      msg.isOnline = hasIsOnline() ? isOnline : null;
+      msg.protocolHandlerState = hasProtocolHandlerState() ? protocolHandlerState.toMessageNano() : null;
+      msg.registrationManagerState = hasRegistrationManagerState() ? registrationManagerState.toMessageNano() : null;
+      msg.acquireTokenTaskState = hasAcquireTokenTaskState() ? acquireTokenTaskState.toMessageNano() : null;
+      msg.regSyncHeartbeatTaskState = hasRegSyncHeartbeatTaskState() ? regSyncHeartbeatTaskState.toMessageNano() : null;
+      msg.persistentWriteTaskState = hasPersistentWriteTaskState() ? persistentWriteTaskState.toMessageNano() : null;
+      msg.heartbeatTaskState = hasHeartbeatTaskState() ? heartbeatTaskState.toMessageNano() : null;
+      msg.batchingTaskState = hasBatchingTaskState() ? batchingTaskState.toMessageNano() : null;
+      msg.lastWrittenState = hasLastWrittenState() ? lastWrittenState.toMessageNano() : null;
+      msg.statisticsState = hasStatisticsState() ? statisticsState.toMessageNano() : null;
+      return msg;
+    }
+  }
+}
diff --git a/java/com/google/ipc/invalidation/util/Bytes.java b/java/com/google/ipc/invalidation/util/Bytes.java
index 1b6bd34..86d31a2 100644
--- a/java/com/google/ipc/invalidation/util/Bytes.java
+++ b/java/com/google/ipc/invalidation/util/Bytes.java
@@ -16,7 +16,7 @@
 package com.google.ipc.invalidation.util;
 
 import com.google.common.base.Preconditions;
-import com.google.protobuf.ByteString;
+import com.google.ipc.invalidation.util.LazyString.LazyStringReceiver;
 
 import java.nio.ByteBuffer;
 import java.nio.charset.Charset;
@@ -35,6 +35,32 @@
   private static final Charset UTF_8 = Charset.forName("UTF-8");
 
   /**
+   * Interface accessing byte elements from {@code T}, which may be (for instance)
+   * {@link com.google.protobuf.ByteString ByteString} or {@code byte[]}.
+   */
+  interface BytesAccessor<T> {
+    int size(T bytes);
+    byte get(T bytes, int index);
+  }
+
+  private static final BytesAccessor<byte[]> BYTE_ARRAY_ACCESSOR = new BytesAccessor<byte[]>() {
+    @Override public int size(byte[] bytes) {
+      return bytes == null ? 0 : bytes.length;
+    }
+
+    @Override public byte get(byte[] bytes, int index) {
+      return bytes[index];
+    }
+  };
+
+  private static final LazyStringReceiver<byte[]> BYTE_ARRAY_RECEIVER =
+      new LazyStringReceiver<byte[]>() {
+    @Override public void appendToBuilder(TextBuilder builder, byte[] element) {
+      toCompactString(builder, element);
+    }
+  };
+
+  /**
    * Three arrays that store the representation of each character from 0 to 255.
    * The ith number's octal representation is: CHAR_OCTAL_STRINGS1[i],
    * CHAR_OCTAL_STRINGS2[i], CHAR_OCTAL_STRINGS3[i]
@@ -95,10 +121,6 @@
     bytes[0] = b;
   }
 
-  public Bytes(ByteString byteString) {
-    this(byteString.toByteArray());
-  }
-
   /** Creates a Bytes object from the given string encoded as a UTF-8 byte array. */
   public static Bytes fromUtf8Encoding(String s) {
     return new Bytes(s.getBytes(UTF_8));
@@ -127,18 +149,12 @@
     return bytes;
   }
 
-  /** Converts this to a byte string. */
-  public ByteString toByteString() {
-    return ByteString.copyFrom(getByteArray());
-  }
-
   /**
-   * Returns a new {@code Bytes} containing the given subrange of bytes [{@code
-   * from}, {@code to}).
+   * Returns a new {@code Bytes} containing the given subrange of bytes [{@code from}, {@code to}).
    */
   public Bytes subsequence(int from, int to) {
-    // Identical semantics to Arrays.copyOfRange() but implemented manually
-    // so runs on Froyo (JDK 1.5).
+    // Identical semantics to Arrays.copyOfRange() but implemented manually so runs on
+    // Froyo (JDK 1.5).
     int newLength = to - from;
     if (newLength < 0) {
       throw new IllegalArgumentException(from + " > " + to);
@@ -148,8 +164,7 @@
     return new Bytes(copy);
   }
 
-  @Override
-  public boolean equals(final Object o) {
+  @Override public boolean equals(final Object o) {
     if (o == this) {
       return true;
     }
@@ -162,8 +177,7 @@
     return Arrays.equals(bytes, other.bytes);
   }
 
-  @Override
-  public int hashCode() {
+  @Override public int hashCode() {
     int h = hash;
 
     // If the hash has been not computed, go through each byte and compute it.
@@ -220,16 +234,27 @@
     return true;
   }
 
-  @Override
-  public int compareTo(Bytes other) {
+  @Override public int compareTo(Bytes other) {
     return compare(bytes, other.bytes);
   }
 
+  public static Bytes fromByteArray(byte[] bytes) {
+    return (bytes == null) ? null : new Bytes(bytes);
+  }
+
   /**
-   * Same specs as Bytes.compareTo except for the byte[] type. Null arrays are ordered before
+   * Same specs as {@link #compareTo} except for the byte[] type. Null arrays are ordered before
    * non-null arrays.
    */
   public static int compare(byte[] first, byte[] second) {
+    return compare(BYTE_ARRAY_ACCESSOR, first, second);
+  }
+
+  /**
+   * Performs lexicographic comparison of two byte sequences. Null sequences are ordered before
+   * non-null sequences.
+   */
+  static <T> int compare(BytesAccessor<T> accessor, T first, T second) {
     // Order null arrays before non-null arrays.
     if (first == null) {
       return (second == null) ? 0 : -1;
@@ -238,11 +263,12 @@
       return 1;
     }
 
-    int minLength = Math.min(first.length, second.length);
+    int minLength = Math.min(accessor.size(first), accessor.size(second));
     for (int i = 0; i < minLength; i++) {
-      if (first[i] != second[i]) {
-        int firstByte = first[i] & 0xff;
-        int secondByte = second[i] & 0xff;
+
+      if (accessor.get(first, i) != accessor.get(second, i)) {
+        int firstByte = accessor.get(first, i) & 0xff;
+        int secondByte = accessor.get(second, i) & 0xff;
         return firstByte - secondByte;
       }
     }
@@ -250,69 +276,52 @@
     // * If the arrays are of equal length, they must be identical (else we would have
     //   returned the correct value above
     // * If they are not of equal length, the one with the longer length is greater.
-    return first.length - second.length;
-  }
-
-  /** Compares lexicographic order of {@code first} and {@code second}. */
-  public static int compare(ByteString first, ByteString second) {
-    Preconditions.checkNotNull(first);
-    Preconditions.checkNotNull(second);
-
-    // Note: size() is O(1) on ByteString.
-    for (int i = 0; i < first.size(); ++i) {
-      if (i == second.size()) {
-        // 'first' is longer than 'second' (logically, think of 'second' as padded with special
-        // 'blank' symbols that are smaller than any other symbol per the usual lexicographic
-        // ordering convention.)
-        return +1;
-      }
-      byte firstByte = first.byteAt(i);
-      byte secondByte = second.byteAt(i);
-      if (firstByte != secondByte) {
-        return (firstByte & 0xff) - (secondByte & 0xff);
-      }
-    }
-    // We ran through both strings and found no differences. If 'second' is longer than 'first',
-    // then we return -1. Otherwise, it implies that both strings have been consumed and no
-    // differences discovered in which case we return 0.
-    return (second.size() > first.size()) ? -1 : 0;
+    return accessor.size(first) - accessor.size(second);
   }
 
   /**
-   * Renders the bytes as a string in standard bigtable ascii / octal mix
-   * compatible with bt and returns it. Borrowed from Bigtable's
-   * Util.keyToString().
-   */
-  public static String toString(ByteString bytes) {
-    return toString(bytes.toByteArray());
-  }
-
-  /**
-   * Renders the bytes as a string in standard bigtable ascii / octal mix
-   * compatible with bt and returns it. Borrowed from Bigtable's
-   * Util.keyToString().
+   * Renders the bytes as a string in standard bigtable ascii / octal mix compatible with bt and
+   * returns it.
    */
   public static String toString(byte[] bytes) {
     return toCompactString(new TextBuilder(), bytes).toString();
   }
 
   /**
-   * Renders the bytes as a string in standard bigtable ascii / octal mix
-   * compatible with bt and adds it to builder. Borrowed from Bigtable's
-   * Util.keyToString().
+   * Renders the bytes as a string in standard bigtable ascii / octal mix compatible with bt and
+   * adds it to builder.
    */
-  @Override
-  public void toCompactString(TextBuilder builder) {
+  @Override public void toCompactString(TextBuilder builder) {
     toCompactString(builder, bytes);
   }
 
   /**
-   * Renders the bytes as a string in standard bigtable ascii / octal mix
-   * compatible with bt and adds it to builder. Borrowed from Bigtable's
-   * Util.keyToString(). Returns {@code builder}.
+   * Renders the bytes as a string in standard bigtable ascii / octal mix compatible with bt and
+   * adds it to builder. Returns {@code builder}.
    */
   public static TextBuilder toCompactString(TextBuilder builder, byte[] bytes) {
-    for (byte c : bytes) {
+    return toCompactString(BYTE_ARRAY_ACCESSOR, builder, bytes);
+  }
+
+  /**
+   * Returns an object that lazily formats {@code bytes} when {@link Object#toString()} is called.
+   */
+  public static Object toLazyCompactString(byte[] bytes) {
+    if (bytes == null || bytes.length == 0) {
+      return "";
+    }
+    return LazyString.toLazyCompactString(bytes, BYTE_ARRAY_RECEIVER);
+  }
+
+  /**
+   * Renders the bytes as a string in standard bigtable ascii / octal mix compatible with bt and
+   * adds it to builder. Borrowed from Bigtable's {@code Util$keyToString()}.
+   * Returns {@code builder}.
+   */
+  static <T> TextBuilder toCompactString(BytesAccessor<T> accessor, TextBuilder builder,
+      T bytes) {
+    for (int i = 0; i < accessor.size(bytes); i++) {
+      byte c = accessor.get(bytes, i);
       switch(c) {
         case '\n': builder.append('\\'); builder.append('n'); break;
         case '\r': builder.append('\\'); builder.append('r'); break;
diff --git a/java/com/google/ipc/invalidation/util/ExponentialBackoffDelayGenerator.java b/java/com/google/ipc/invalidation/util/ExponentialBackoffDelayGenerator.java
index 75b8648..8283d3d 100644
--- a/java/com/google/ipc/invalidation/util/ExponentialBackoffDelayGenerator.java
+++ b/java/com/google/ipc/invalidation/util/ExponentialBackoffDelayGenerator.java
@@ -33,8 +33,8 @@
   /** Initial allowed delay time. */
   private final int initialMaxDelay;
 
-  /** Maximum allowed delay time as a factor of {@code initialMaxDelay} */
-  private final int maxExponentialFactor;
+  /** Maximum allowed delay time. */
+  private final int maxDelay;
 
   /** Next delay time to use. */
   private int currentMaxDelay;
@@ -52,9 +52,10 @@
       int maxExponentialFactor) {
     Preconditions.checkArgument(maxExponentialFactor > 0, "max factor must be positive");
     this.random = Preconditions.checkNotNull(random);
-    this.maxExponentialFactor = maxExponentialFactor;
-    this.initialMaxDelay = initialMaxDelay;
     Preconditions.checkArgument(initialMaxDelay > 0, "initial delay must be positive");
+    this.initialMaxDelay = initialMaxDelay;
+    this.maxDelay = initialMaxDelay * maxExponentialFactor;
+    Preconditions.checkState(maxDelay > 0, "max delay must be positive");
     reset();
   }
 
@@ -78,6 +79,25 @@
     this.inRetryMode = false;
   }
 
+  /**
+   * Resets the exponential backoff generator to start delays such that the specified number of
+   * retries have already been made. */
+  public void resetWithNumRetries(int numRetries) {
+    Preconditions.checkArgument(numRetries >= 0);
+    reset();
+    if (numRetries > 0) {
+      inRetryMode = true;
+      if (numRetries > Integer.SIZE) {
+        // Cap, otherwise Java will use the lower order 5 bits causing incorrect power of 2.
+        numRetries = Integer.SIZE;
+      }
+      currentMaxDelay = currentMaxDelay << (numRetries - 1);
+      if (currentMaxDelay <= 0 || currentMaxDelay > maxDelay) {
+        currentMaxDelay = maxDelay;
+      }
+    }
+  }
+
   /** Gets the next delay interval to use. */
   public int getNextDelay() {
     int delay = 0;  // After a reset, the delay is 0.
@@ -87,7 +107,6 @@
       delay = random.nextInt(currentMaxDelay) + 1;
 
       // Adjust the max for the next run.
-      int maxDelay = initialMaxDelay * maxExponentialFactor;
       if (currentMaxDelay <= maxDelay) {  // Guard against overflow.
         currentMaxDelay *= 2;
         if (currentMaxDelay > maxDelay) {
diff --git a/java/com/google/ipc/invalidation/util/LazyString.java b/java/com/google/ipc/invalidation/util/LazyString.java
index cd10cef..bc85c60 100644
--- a/java/com/google/ipc/invalidation/util/LazyString.java
+++ b/java/com/google/ipc/invalidation/util/LazyString.java
@@ -15,7 +15,7 @@
  */
 package com.google.ipc.invalidation.util;
 
-import com.google.common.base.Receiver;
+import java.util.Collection;
 
 
 /**
@@ -24,27 +24,121 @@
  */
 public class LazyString {
 
+  /** Receiver formatting objects using {@link Object#toString()}. */
+  public static final LazyStringReceiver<Object> OBJECT_RECEIVER =
+      new LazyStringReceiver<Object>() {
+        @Override
+        public void appendToBuilder(TextBuilder builder, Object element) {
+          builder.append(element);
+        }
+      };
+
+  /**
+   * Receiver appending an {@code element} to the given {@code builder}. Implementations may assume
+   * the builder and element are not {@code null}.
+   */
+  public interface LazyStringReceiver<T> {
+    void appendToBuilder(TextBuilder builder, T element);
+  }
+
   /**
    * Given an {@code element} to be logged lazily, returns null if the object is null. Otherwise,
    * return an object that would convert it to a string using {@code builderFunction}. I.e., this
-   * method will call {@code builderFunction} with a new {@link TextBuilder} return the string
-   * created with it.
+   * method will call {@code builderFunction} with a new {@link TextBuilder} and provided
+   * {@code element} and return the string created with it.
    */
   public static <T> Object toLazyCompactString(final T element,
-      final Receiver<TextBuilder> builderFunction) {
+      final LazyStringReceiver<T> builderFunction) {
     if (element == null) {
       return null;
     }
     return new Object() {
-      @Override
-      public String toString() {
+      @Override public String toString() {
         TextBuilder builder = new TextBuilder();
-        builderFunction.accept(builder);
+        builderFunction.appendToBuilder(builder, element);
         return builder.toString();
       }
     };
   }
 
+  /**
+   * Returns an object that converts the given {@code elements} array into a debug string when
+   * {@link Object#toString} is called using
+   * {@link #appendElementsToBuilder(TextBuilder, Object[], LazyStringReceiver)}.
+   */
+  public static <T> Object toLazyCompactString(final T[] elements,
+      final LazyStringReceiver<? super T> elementReceiver) {
+    if ((elements == null) || (elements.length == 0)) {
+      return null;
+    }
+    return new Object() {
+      @Override public String toString() {
+        return appendElementsToBuilder(new TextBuilder(), elements, elementReceiver).toString();
+      }
+    };
+  }
+
+  /**
+   * Returns an object that converts the given {@code elements} collection into a debug string when
+   * {@link Object#toString} is called using
+   * {@link #appendElementsToBuilder(TextBuilder, Object[], LazyStringReceiver)}.
+   */
+  public static <T> Object toLazyCompactString(final Collection<T> elements,
+      final LazyStringReceiver<? super T> elementReceiver) {
+    if ((elements == null) || elements.isEmpty()) {
+      return null;
+    }
+    return new Object() {
+      @Override public String toString() {
+        return appendElementsToBuilder(new TextBuilder(), elements, elementReceiver).toString();
+      }
+    };
+  }
+
+  /**
+   * Appends {@code elements} formatted using {@code elementReceiver} to {@code builder}. Elements
+   * are comma-separated.
+   */
+  public static <T> TextBuilder appendElementsToBuilder(TextBuilder builder, T[] elements,
+      LazyStringReceiver<? super T> elementReceiver) {
+    if (elements == null) {
+      return builder;
+    }
+    for (int i = 0; i < elements.length; i++) {
+      if (i != 0) {
+        builder.append(", ");
+      }
+      T element = elements[i];
+      if (element != null) {
+        elementReceiver.appendToBuilder(builder, element);
+      }
+    }
+    return builder;
+  }
+
+  /**
+   * Appends {@code elements} formatted using {@code elementReceiver} to {@code builder}. Elements
+   * are comma-separated.
+   */
+  public static <T> TextBuilder appendElementsToBuilder(TextBuilder builder,
+      Iterable<T> elements, LazyStringReceiver<? super T> elementReceiver) {
+    if (elements == null) {
+      return builder;
+    }
+    boolean first = true;
+    for (T element : elements) {
+      if (first) {
+        first = false;
+      } else {
+        builder.append(", ");
+      }
+      if (element != null) {
+        elementReceiver.appendToBuilder(builder, element);
+      }
+    }
+    return builder;
+  }
+
   private LazyString() {  // To prevent instantiation.
   }
 }
diff --git a/java/com/google/ipc/invalidation/util/ProtoWrapper.java b/java/com/google/ipc/invalidation/util/ProtoWrapper.java
new file mode 100644
index 0000000..db95eea
--- /dev/null
+++ b/java/com/google/ipc/invalidation/util/ProtoWrapper.java
@@ -0,0 +1,238 @@
+/*
+ * 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.util;
+
+import com.google.common.base.Preconditions;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+
+/**
+ * Base class for generated protobuf wrapper classes. Includes utilities for validation of proto
+ * fields and implements hash code memoization.
+ */
+public abstract class ProtoWrapper extends InternalBase {
+
+  /** Unchecked validation exception indicating a code issue. */
+  public static final class ValidationArgumentException extends IllegalArgumentException {
+    public ValidationArgumentException(String message) {
+      super(message);
+    }
+  }
+
+  /** Checked validation exception indicating an bogus protocol buffer instance. */
+  public static final class ValidationException extends Exception {
+    public ValidationException(String message) {
+      super(message);
+    }
+
+    public ValidationException(Throwable cause) {
+      super(cause);
+    }
+  }
+
+  /** Immutable, empty list. */
+  private static final List<?> EMPTY_LIST = Collections.unmodifiableList(new ArrayList<Object>(0));
+  private static final int UNINITIALIZED_HASH_CODE = -1;
+  private static final int NOT_UNITIALIZED_HASH_CODE = UNINITIALIZED_HASH_CODE + 1;
+  private int hashCode;
+
+  @Override
+  public final int hashCode() {
+    if (hashCode == UNINITIALIZED_HASH_CODE) {
+      int computedHashCode = computeHashCode();
+
+      // If computeHashCode() happens to return UNITIALIZED_HASH_CODE, replace it with a
+      // different (constant but arbitrary) value so that the hash code doesn't need to be
+      // recomputed.
+      hashCode = (computedHashCode == UNINITIALIZED_HASH_CODE) ? NOT_UNITIALIZED_HASH_CODE
+          : computedHashCode;
+    }
+    return hashCode;
+  }
+
+  /** Returns a hash code for this wrapper. */
+  protected abstract int computeHashCode();
+
+  /** Returns an immutable, empty list with elements of type {@code T}. */
+  @SuppressWarnings("unchecked")
+  protected static <T> List<T> emptyList() {
+    return (List<T>) EMPTY_LIST;
+  }
+
+  /** Checks that the given field is non null. */
+  protected static void required(String fieldName, Object fieldValue) {
+    if (fieldValue == null) {
+      throw new ValidationArgumentException(
+          String.format("Required field '%s' was not set", fieldName));
+    }
+  }
+
+  /**
+   * Checks that the given collection contains non-null elements. Treats {@code null} as empty.
+   * Returns an immutable copy of the given collection.
+   */
+  protected static <T> List<T> optional(String fieldName, Collection<T> fieldValues) {
+    if ((fieldValues == null) || (fieldValues.size() == 0)) {
+      return emptyList();
+    }
+    ArrayList<T> copy = new ArrayList<T>(fieldValues);
+    for (int i = 0; i < copy.size(); i++) {
+      if (copy.get(i) == null) {
+        throw new ValidationArgumentException(
+            String.format("Element %d of repeated field '%s' must not be null.", i, fieldName));
+      }
+    }
+    return Collections.unmodifiableList(copy);
+  }
+
+  /**
+   * Checks that the given field is non-empty. Returns an immutable copy of the given
+   * collection.
+   */
+  protected static <T> List<T> required(String fieldName, Collection<T> fieldValues) {
+    List<T> copy = optional(fieldName, fieldValues);
+    if (fieldValues.isEmpty()) {
+      throw new ValidationArgumentException(
+          String.format("Repeated field '%s' must have at least one element", fieldName));
+    }
+    return copy;
+  }
+
+  /** Checks that the given field is non-negative. */
+  protected static void nonNegative(String fieldName, int value) {
+    if (value < 0) {
+      throw new ValidationArgumentException(
+          String.format("Field '%s' must be non-negative: %d", fieldName, value));
+    }
+  }
+
+  /** Checks that the given field is non-negative. */
+  protected static void nonNegative(String fieldName, long value) {
+    if (value < 0) {
+      throw new ValidationArgumentException(
+          String.format("Field '%s' must be non-negative: %d", fieldName, value));
+    }
+  }
+
+  /** Checks that the given field is positive. */
+  protected static void positive(String fieldName, int value) {
+    if (value <= 0) {
+      throw new ValidationArgumentException(
+          String.format("Field '%s' must be positive: %d", fieldName, value));
+    }
+  }
+
+  /** Checks that the given field is positive. */
+  protected static void positive(String fieldName, long value) {
+    if (value <= 0) {
+      throw new ValidationArgumentException(
+          String.format("Field '%s' must be positive: %d", fieldName, value));
+    }
+  }
+
+  /**
+   * Checks that the given field is not empty. Only call when the field has a value:
+   * {@link #required} can be called first, or the check can be conditionally performed.
+   */
+  protected static void nonEmpty(String fieldName, String value) {
+    if (Preconditions.checkNotNull(value).length() == 0) {
+      throw new ValidationArgumentException(
+          String.format("Field '%s' must be non-empty", fieldName));
+    }
+  }
+
+  /**
+   * Checks that the given field is not empty. Only call when the field has a value:
+   * {@link #required} can be called first, or the check can be conditionally performed.
+   */
+  protected static void nonEmpty(String fieldName, Bytes value) {
+    if (Preconditions.checkNotNull(value).size() == 0) {
+      throw new ValidationArgumentException(
+          String.format("Field '%s' must be non-empty", fieldName));
+    }
+  }
+
+  /** Checks that the given condition holds. */
+  protected void check(boolean condition, String message) {
+    if (!condition) {
+      throw new ValidationArgumentException(String.format("%s: %s", message, this));
+    }
+  }
+
+  /** Throws exception indicating a one-of violation due to multiple defined choices. */
+  protected static void oneOfViolation(String field1, String field2) {
+    throw new ValidationArgumentException(
+        String.format("Multiple one-of fields defined, including: %s, %s", field1, field2));
+  }
+
+  /** Throws exception indicating that no one-of choices are defined. */
+  protected static void oneOfViolation() {
+    throw new ValidationArgumentException("No one-of fields defined");
+  }
+
+  //
+  // Equals helpers.
+  //
+
+  /**
+   * Returns {@code true} if the provided objects are both null or are non-null and equal. Returns
+   * {@code false} otherwise.
+   */
+  protected static boolean equals(Object x, Object y) {
+    if (x == null) {
+      return y == null;
+    }
+    if (y == null) {
+      return false;
+    }
+    return x.equals(y);
+  }
+
+  //
+  // Hash code helpers for primitive types (taken from com.google.common.primitives package).
+  //
+
+  /** Returns hash code for the provided {@code long} value. */
+  protected static int hash(long value) {
+    // See Longs#hashCode
+    return (int) (value ^ (value >>> 32));
+  }
+
+  /** Returns hash code for the provided {@code int} value. */
+  protected static int hash(int value) {
+    return value;
+  }
+
+  /** Returns hash code for the provided {@code boolean} value. */
+  protected static int hash(boolean value) {
+    // See Booleans#hashCode
+    return value ? 1231 : 1237;
+  }
+
+  /** Returns hash code for the provided {@code float} value. */
+  protected static int hash(float value) {
+    return Float.valueOf(value).hashCode();
+  }
+
+  /** Returns hash code for the provided {@code double} value. */
+  protected static int hash(double value) {
+    return Double.valueOf(value).hashCode();
+  }
+}
diff --git a/java/com/google/ipc/invalidation/util/Smearer.java b/java/com/google/ipc/invalidation/util/Smearer.java
index 3a3ef06..5a38e09 100644
--- a/java/com/google/ipc/invalidation/util/Smearer.java
+++ b/java/com/google/ipc/invalidation/util/Smearer.java
@@ -57,8 +57,4 @@
     double smearFactor = (2 * random.nextDouble() - 1.0) * smearFraction;
     return (int) Math.ceil(delay + delay * smearFactor);
   }
-
-  /** Changes the smear percent of this object to be {@code smearPercent}. */
-  public void changeSmearPercent(int smearPercent) {
-  }
 }
diff --git a/java/com/google/ipc/invalidation/util/TextBuilder.java b/java/com/google/ipc/invalidation/util/TextBuilder.java
index 230d426..5e31efb 100644
--- a/java/com/google/ipc/invalidation/util/TextBuilder.java
+++ b/java/com/google/ipc/invalidation/util/TextBuilder.java
@@ -17,7 +17,6 @@
 package com.google.ipc.invalidation.util;
 
 import com.google.common.base.Preconditions;
-import com.google.protobuf.ByteString;
 
 import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
@@ -130,7 +129,7 @@
    * Appends the comma-separated {@code InternalBase#toCompactString} representations of
    * {@code objects} to this builder.
    */
-  public TextBuilder append(Iterable<InternalBase> objects) {
+  public TextBuilder append(Iterable<? extends InternalBase> objects) {
     if (objects == null) {
       return this;
     }
@@ -147,8 +146,11 @@
   }
 
   /** Appends the {@link Bytes#toString} representation of {@code bytes} to this builder. */
-  public TextBuilder append(ByteString bytes) {
-    builder.append(Bytes.toString(bytes));
+  public TextBuilder append(byte[] bytes) {
+    if (bytes == null) {
+      return append("null");
+    }
+    Bytes.toCompactString(this, bytes);
     return this;
   }
 
diff --git a/proto/android_channel.proto b/proto/android_channel.proto
index e5d4732..e4a92f5 100644
--- a/proto/android_channel.proto
+++ b/proto/android_channel.proto
@@ -23,10 +23,10 @@
 
 option optimize_for = LITE_RUNTIME;
 
-option java_outer_classname = "AndroidChannel";
 
 
-
+option java_outer_classname = "NanoAndroidChannel";
+option java_package = "com.google.protos.ipc.invalidation";
 
 
 import "client_protocol.proto";
@@ -57,7 +57,7 @@
 
 // An id that specifies how to route a message to a Ticl on an Android device
 // via C2DM.
-message EndpointId {
+message AndroidEndpointId {
   // Field 1 was once the ProtocolVersion of this message.
 
   // The "registration_id" returned when the client registers with c2dm.  This
diff --git a/proto/android_listener.proto b/proto/android_listener.proto
index 6a81e06..dd16a83 100644
--- a/proto/android_listener.proto
+++ b/proto/android_listener.proto
@@ -25,10 +25,9 @@
 
 option optimize_for = LITE_RUNTIME;
 
-option java_outer_classname = "AndroidListenerProtocol";
 
-
-
+option java_outer_classname = "NanoAndroidListenerProtocol";
+option java_package = "com.google.protos.ipc.invalidation";
 
 
 import "client.proto";
diff --git a/proto/android_service.proto b/proto/android_service.proto
index cd3287e..e52b7d3 100644
--- a/proto/android_service.proto
+++ b/proto/android_service.proto
@@ -26,13 +26,20 @@
 
 option optimize_for = LITE_RUNTIME;
 
-option java_outer_classname = "AndroidService";
+
+
+option java_outer_classname = "NanoAndroidService";
+option java_package = "com.google.protos.ipc.invalidation";
+
 
 
 import "client_protocol.proto";
 import "java_client.proto";
 
 // Call from application to Ticl.
+//
+// Android service messages are typically validated. Validation rules may be
+// declared in ClientProtoWrapperGenerator.java.
 
 message ClientDowncall {
   message StartDowncall {}
diff --git a/proto/android_state.proto b/proto/android_state.proto
deleted file mode 100644
index fc444e2..0000000
--- a/proto/android_state.proto
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * 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.
- */
-//
-// The Android internal storage format for per-client state.
-
-syntax = "proto2";
-
-package com.google.protos.ipc.invalidation;
-
-option optimize_for = LITE_RUNTIME;
-
-option java_outer_classname = "AndroidState";
-
-
-
-
-import "client_protocol.proto";
-
-// Base metadata for an Android client instance.  All of these values
-// are required and invariant for the life of the client.
-message ClientMetadata {
-
-  // The version of this state.
-  optional Version version = 1;
-
-  // A key identifying a specific client on a device.
-  optional string client_key = 2;
-
-  // The client type for this client.
-  optional int32 client_type = 3;
-
-  // The user account name for this client.
-  optional string account_name = 4;
-
-  // The user account type for this client.
-  optional string account_type = 5;
-
-  // The authentication token type that is used for requests from this client.
-  optional string auth_type = 6;
-
-  // The application package name for the client's event listener.
-  optional string listener_pkg = 7;
-
-  // The class name for the client's event listener.
-  optional string listener_class = 8;
-
-}
-
-// Internal properties associated with the client by the client library.  These
-// properties may change or grow over time.
-message ClientProperty {
-
-  // The key of the stored property
-  optional string key = 1;
-
-  // The value of the stored property
-  optional bytes value = 2;
-}
-
-// The stored state of the client combining base metadata and internal properties.
-message StoredState {
-  optional ClientMetadata metadata = 1;
-
-  // TICL properties stored for this client.
-  repeated ClientProperty property = 9;
-}
diff --git a/proto/channel_common.proto b/proto/channel_common.proto
index 4623bc0..c68ac74 100644
--- a/proto/channel_common.proto
+++ b/proto/channel_common.proto
@@ -23,9 +23,11 @@
 
 option optimize_for = LITE_RUNTIME;
 
-option java_outer_classname = "ChannelCommon";
 
 
+option java_outer_classname = "NanoChannelCommon";
+option java_package = "com.google.protos.ipc.invalidation";
+
 
 
 message ChannelMessageEncoding {
diff --git a/proto/client.proto b/proto/client.proto
index a9018c7..b81c7f0 100644
--- a/proto/client.proto
+++ b/proto/client.proto
@@ -26,9 +26,10 @@
 
 option optimize_for = LITE_RUNTIME;
 
-option java_outer_classname = "Client";
 
 
+option java_outer_classname = "NanoClient";
+option java_package = "com.google.protos.ipc.invalidation";
 
 
 
diff --git a/proto/client_protocol.proto b/proto/client_protocol.proto
index 5713e87..dabbc05 100644
--- a/proto/client_protocol.proto
+++ b/proto/client_protocol.proto
@@ -26,9 +26,10 @@
 
 option optimize_for = LITE_RUNTIME;
 
-option java_outer_classname = "ClientProtocol";
 
 
+option java_outer_classname = "NanoClientProtocol";
+option java_package = "com.google.protos.ipc.invalidation";
 
 
 
@@ -67,6 +68,14 @@
 //    S -> C: InfoRequestMessage
 //    C -> S: InfoMessage
 //
+// Client protocol messages are typically validated. Validation rules may be
+// declared in the following locations when making changes to this file:
+//
+// 1. TiclMessageValidator2.java: validation logic that is run on the
+// server.
+//
+// 2. ClientProtoWrapperGenerator.java: validation logic that is run
+// on the client.
 // ------------------------------------------------------------------------
 
 // A basic message type used for versioning public proto messages and/or
@@ -110,14 +119,14 @@
   // All fields below are for informational/debugging/monitoring purposes only.
   // No critical code decision is supposed to be made using them.
 
-  // Information about the client operating system/platform, e.g., Windows,
-  // ChromeOS.
+  // Optional: information about the client operating system/platform, e.g.,
+  // Windows, ChromeOS.
   optional string platform = 2;
 
-  // Language used for the library.
+  // Optional: language used for the library.
   optional string language = 3;
 
-  // Extra information about the client (e.g., application name).
+  // Optional: extra information about the client (e.g., application name).
   optional string application_info = 4;
 }
 
diff --git a/proto/java_client.proto b/proto/java_client.proto
index 7e8fcf0..5c1cbd4 100644
--- a/proto/java_client.proto
+++ b/proto/java_client.proto
@@ -26,7 +26,11 @@
 
 option optimize_for = LITE_RUNTIME;
 
-option java_outer_classname = "JavaClient";
+
+
+option java_outer_classname = "NanoJavaClient";
+option java_package = "com.google.protos.ipc.invalidation";
+
 
 
 import 'client.proto';
diff --git a/proto/types.proto b/proto/types.proto
index 13b43ae..e1bba02 100644
--- a/proto/types.proto
+++ b/proto/types.proto
@@ -32,6 +32,8 @@
     CHROME_SYNC = 1004;
     CHROME_SYNC_ANDROID = 1018;
     CHROME_SYNC_IOS = 1038;
+    CHROME_SYNC_GCM_DESKTOP = 1055;
+    CHROME_SYNC_GCM_IOS = 1056;
   }
   optional Type type = 1;
 }