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

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

Issue 1162033004: Pull cacheinvalidations code directory into chromium repo. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/TiclStateManager.java
diff --git a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/TiclStateManager.java b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/TiclStateManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..bf9ded011aa3475cd580fd0f42c7e8b55dc12e38
--- /dev/null
+++ b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/TiclStateManager.java
@@ -0,0 +1,243 @@
+/*
+ * 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.ObjectIdDigestUtils.Sha1DigestFunction;
+import com.google.ipc.invalidation.external.client.SystemResources;
+import com.google.ipc.invalidation.external.client.SystemResources.Logger;
+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.Preconditions;
+import com.google.ipc.invalidation.util.ProtoWrapper.ValidationException;
+import com.google.ipc.invalidation.util.TypedUtil;
+
+import android.content.Context;
+
+import java.io.DataInput;
+import java.io.DataInputStream;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Random;
+
+
+/**
+ * Class to save and restore instances of {@code InvalidationClient} to and from stable storage.
+ *
+ */
+class TiclStateManager {
+ /** Name of the file to which Ticl state will be persisted. */
+ private static final String TICL_STATE_FILENAME = "android_ticl_service_state.bin";
+
+ /**
+ * Maximum size of a Ticl state file. Files with larger size will be ignored as invalid. We use
+ * this because we allocate an array of bytes of the same size as the Ticl file and want to
+ * avoid accidentally allocating huge arrays.
+ */
+ private static final int MAX_TICL_FILE_SIZE_BYTES = 100 * 1024; // 100 kilobytes
+
+ /** Random number generator for created Ticls. */
+ private static final Random random = new Random();
+
+ /**
+ * Restores the Ticl from persistent storage if it exists. Otherwise, returns {@code null}.
+ * @param context Android system context
+ * @param resources resources to use for the Ticl
+ */
+ static AndroidInvalidationClientImpl restoreTicl(Context context,
+ SystemResources resources) {
+ AndroidTiclState state = readTiclState(context, resources.getLogger());
+ if (state == null) {
+ return null;
+ }
+ AndroidInvalidationClientImpl ticl = new AndroidInvalidationClientImpl(context, resources,
+ random, state);
+ setSchedulerId(resources, ticl);
+ return ticl;
+ }
+
+ /** Creates a new Ticl. Persistent stroage must not exist. */
+ static void createTicl(Context context, SystemResources resources, int clientType,
+ byte[] clientName, ClientConfigP config, boolean skipStartForTest) {
+ Preconditions.checkState(!doesStateFileExist(context), "Ticl already exists");
+ AndroidInvalidationClientImpl ticl = new AndroidInvalidationClientImpl(context, resources,
+ random, clientType, clientName, config);
+ if (!skipStartForTest) {
+ // Ticls are started when created unless this should be skipped for tests; we allow tests
+ // to skip starting Ticls because many integration tests assume that Ticls will not be
+ // started when created.
+ setSchedulerId(resources, ticl);
+ ticl.start();
+ }
+ saveTicl(context, resources.getLogger(), ticl);
+ }
+
+ /**
+ * Sets the scheduling id on the scheduler in {@code resources} to {@code ticl.getSchedulingId()}.
+ */
+ private static void setSchedulerId(SystemResources resources,
+ AndroidInvalidationClientImpl ticl) {
+ AndroidInternalScheduler scheduler =
+ (AndroidInternalScheduler) resources.getInternalScheduler();
+ scheduler.setTiclId(ticl.getSchedulingId());
+ }
+
+ /**
+ * Saves a Ticl instance to persistent storage.
+ *
+ * @param context Android system context
+ * @param logger logger
+ * @param ticl the Ticl instance to save
+ */
+ static void saveTicl(Context context, Logger logger, AndroidInvalidationClientImpl ticl) {
+ FileOutputStream outputStream = null;
+ try {
+
+ // Create a protobuf with the Ticl state and a digest over it.
+ AndroidTiclStateWithDigest digestedState = createDigestedState(ticl);
+
+ // Write the protobuf to storage.
+ outputStream = openStateFileForWriting(context);
+ outputStream.write(digestedState.toByteArray());
+ outputStream.close();
+ } catch (FileNotFoundException exception) {
+ logger.warning("Could not write Ticl state: %s", exception);
+ } catch (IOException exception) {
+ logger.warning("Could not write Ticl state: %s", exception);
+ } finally {
+ try {
+ if (outputStream != null) {
+ outputStream.close();
+ }
+ } catch (IOException exception) {
+ logger.warning("Exception closing Ticl state file: %s", exception);
+ }
+ }
+ }
+
+ /**
+ * Reads and returns the Android Ticl state from persistent storage. If the state was missing
+ * or invalid, returns {@code null}.
+ */
+ static AndroidTiclState readTiclState(Context context, Logger logger) {
+ FileInputStream inputStream = null;
+ try {
+ inputStream = openStateFileForReading(context);
+ DataInput input = new DataInputStream(inputStream);
+ long fileSizeBytes = inputStream.getChannel().size();
+ if (fileSizeBytes > MAX_TICL_FILE_SIZE_BYTES) {
+ logger.warning("Ignoring too-large Ticl state file with size %s > %s",
+ fileSizeBytes, MAX_TICL_FILE_SIZE_BYTES);
+ } else {
+ // Cast to int must be safe due to the above size check.
+ byte[] fileData = new byte[(int) fileSizeBytes];
+ input.readFully(fileData);
+ AndroidTiclStateWithDigest androidState = AndroidTiclStateWithDigest.parseFrom(fileData);
+
+ // Validate the digest in the method.
+ if (isDigestValid(androidState, logger)) {
+ 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 (ValidationException exception) {
+ logger.warning("Could not read Ticl state: %s", exception);
+ } catch (IOException exception) {
+ logger.warning("Could not read Ticl state: %s", exception);
+ } finally {
+ try {
+ if (inputStream != null) {
+ inputStream.close();
+ }
+ } catch (IOException exception) {
+ logger.warning("Exception closing Ticl state file: %s", exception);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns a {@link AndroidTiclStateWithDigest} containing {@code ticlState} and its computed
+ * digest.
+ */
+ private static AndroidTiclStateWithDigest createDigestedState(
+ AndroidInvalidationClientImpl ticl) {
+ Sha1DigestFunction digester = new Sha1DigestFunction();
+ ApplicationClientIdP ticlAppId = ticl.getApplicationClientIdP();
+ 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.create(state, new Bytes(digester.getDigest()));
+ return verifiedState;
+ }
+
+ /** Returns whether the digest in {@code state} is correct. */
+ private static boolean isDigestValid(AndroidTiclStateWithDigest state, Logger logger) {
+ Sha1DigestFunction digester = new Sha1DigestFunction();
+ digester.update(state.getState().toByteArray());
+ 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;
+ }
+ return true;
+ }
+
+ /** Opens {@link #TICL_STATE_FILENAME} for writing. */
+ private static FileOutputStream openStateFileForWriting(Context context)
+ throws FileNotFoundException {
+ return context.openFileOutput(TICL_STATE_FILENAME, Context.MODE_PRIVATE);
+ }
+
+ /** Opens {@link #TICL_STATE_FILENAME} for reading. */
+ private static FileInputStream openStateFileForReading(Context context)
+ throws FileNotFoundException {
+ return context.openFileInput(TICL_STATE_FILENAME);
+ }
+
+ /** Deletes {@link #TICL_STATE_FILENAME}. */
+ public static void deleteStateFile(Context context) {
+ context.deleteFile(TICL_STATE_FILENAME);
+ }
+
+ /** Returns whether the state file exists, for tests. */
+ static boolean doesStateFileExistForTest(Context context) {
+ return doesStateFileExist(context);
+ }
+
+ /** Returns whether the state file exists. */
+ private static boolean doesStateFileExist(Context context) {
+ return context.getFileStreamPath(TICL_STATE_FILENAME).exists();
+ }
+
+ private TiclStateManager() {
+ // Disallow instantiation.
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698