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/AndroidInternalScheduler.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/AndroidInternalScheduler.java
diff --git a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/AndroidInternalScheduler.java b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/AndroidInternalScheduler.java
new file mode 100644
index 0000000000000000000000000000000000000000..f867d6c1730f595f9a0ff5d9e5ca482d57fc96a1
--- /dev/null
+++ b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/AndroidInternalScheduler.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.ipc.invalidation.ticl.android2;
+
+import com.google.ipc.invalidation.external.client.SystemResources;
+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.Preconditions;
+import com.google.ipc.invalidation.util.TypedUtil;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+import java.util.HashMap;
+import java.util.Map;
+
+
+/**
+ * Scheduler for controlling access to internal Ticl state in Android.
+ * <p>
+ * This class maintains a map from recurring task names to the recurring task instances in the
+ * associated Ticl. To schedule a recurring task, it uses the {@link AlarmManager} to schedule
+ * an intent to itself at the appropriate time in the future. This intent contains the name of
+ * the task to run; when it is received, this class looks up the appropriate recurring task
+ * instance and runs it.
+ * <p>
+ * Note that this class only supports scheduling recurring tasks, not ordinary runnables. In
+ * order for it to be used, the application must declare the AlarmReceiver of the scheduler
+ * in the application's manifest file; see the implementation comment in AlarmReceiver for
+ * details.
+ *
+ */
+public final class AndroidInternalScheduler implements Scheduler {
+ /** Class that receives AlarmManager broadcasts and reissues them as intents for this service. */
+ public static final class AlarmReceiver extends BroadcastReceiver {
+ /*
+ * This class needs to be public so that it can be instantiated by the Android runtime.
+ * Additionally, it should be declared as a broadcast receiver in the application manifest:
+ * <receiver android:name="com.google.ipc.invalidation.ticl.android2.\
+ * AndroidInternalScheduler$AlarmReceiver" android:enabled="true"/>
+ */
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ // Resend the intent to the service so that it's processed on the handler thread and with
+ // the automatic shutdown logic provided by IntentService.
+ intent.setClassName(context, new AndroidTiclManifest(context).getTiclServiceClass());
+ context.startService(intent);
+ }
+ }
+
+ /**
+ * If {@code true}, {@link #isRunningOnThread} will verify that calls are being made from either
+ * the {@link TiclService} or the {@link TestableTiclService.TestableClient}.
+ */
+ public static boolean checkStackForTest = false;
+
+ /** Class name of the testable client class, for checking call stacks in tests. */
+ private static final String TESTABLE_CLIENT_CLASSNAME_FOR_TEST =
+ "com.google.ipc.invalidation.ticl.android2.TestableTiclService$TestableClient";
+
+ /**
+ * {@link RecurringTask}-created runnables that can be executed by this instance, by their names.
+ */
+ private final Map<String, Runnable> registeredTasks = new HashMap<String, Runnable>();
+
+ /** Android system context. */
+ private final Context context;
+
+ /** Source of time for computing scheduling delays. */
+ private final AndroidClock clock;
+
+ private Logger logger;
+
+ /** Id of the Ticl for which this scheduler will process events. */
+ private long ticlId = -1;
+
+ AndroidInternalScheduler(Context context, AndroidClock clock) {
+ this.context = Preconditions.checkNotNull(context);
+ this.clock = Preconditions.checkNotNull(clock);
+ }
+
+ @Override
+ public void setSystemResources(SystemResources resources) {
+ this.logger = Preconditions.checkNotNull(resources.getLogger());
+ }
+
+ @Override
+ public void schedule(int delayMs, Runnable runnable) {
+ if (!(runnable instanceof NamedRunnable)) {
+ throw new RuntimeException("Unsupported: can only schedule named runnables, not " + runnable);
+ }
+ // Create an intent that will cause the service to run the right recurring task. We explicitly
+ // target it to our AlarmReceiver so that no other process in the system can receive it and so
+ // that our AlarmReceiver will not be able to receive events from any other broadcaster (which
+ // it would be if we used action-based targeting).
+ String taskName = ((NamedRunnable) runnable).getName();
+ Intent eventIntent = ProtocolIntents.newSchedulerIntent(taskName, ticlId);
+ eventIntent.setClass(context, AlarmReceiver.class);
+
+ // Create a pending intent that will cause the AlarmManager to fire the above intent.
+ PendingIntent sender = PendingIntent.getBroadcast(context,
+ (int) (Integer.MAX_VALUE * Math.random()), eventIntent, PendingIntent.FLAG_ONE_SHOT);
+
+ // Schedule the pending intent after the appropriate delay.
+ AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+ long executeMs = clock.nowMs() + delayMs;
+ alarmManager.set(AlarmManager.RTC, executeMs, sender);
+ }
+
+ /**
+ * Handles an event intent created in {@link #schedule} by running the corresponding recurring
+ * task.
+ * <p>
+ * REQUIRES: a recurring task with the name in the intent be present in {@link #registeredTasks}.
+ */
+ void handleSchedulerEvent(AndroidSchedulerEvent event) {
+ Runnable recurringTaskRunnable = TypedUtil.mapGet(registeredTasks, event.getEventName());
+ if (recurringTaskRunnable == null) {
+ throw new NullPointerException("No task registered for " + event.getEventName());
+ }
+ if (ticlId != event.getTiclId()) {
+ logger.warning("Ignoring event with wrong ticl id (not %s): %s", ticlId, event);
+ return;
+ }
+ recurringTaskRunnable.run();
+ }
+
+ /**
+ * Registers {@code task} so that it can be subsequently run by the scheduler.
+ * <p>
+ * REQUIRES: no recurring task with the same name be already present in {@link #registeredTasks}.
+ */
+ void registerTask(String name, Runnable runnable) {
+ Runnable previous = registeredTasks.put(name, runnable);
+ if (previous != null) {
+ String message = new StringBuilder()
+ .append("Cannot overwrite task registered on ")
+ .append(name)
+ .append(", ")
+ .append(this)
+ .append("; tasks = ")
+ .append(registeredTasks.keySet())
+ .toString();
+ throw new IllegalStateException(message);
+ }
+ }
+
+ @Override
+ public boolean isRunningOnThread() {
+ if (!checkStackForTest) {
+ return true;
+ }
+ // If requested, check that the current stack looks legitimate.
+ for (StackTraceElement stackElement : Thread.currentThread().getStackTrace()) {
+ if (stackElement.getMethodName().equals("onHandleIntent") &&
+ stackElement.getClassName().contains("TiclService")) {
+ // Called from the TiclService.
+ return true;
+ }
+ if (stackElement.getClassName().equals(TESTABLE_CLIENT_CLASSNAME_FOR_TEST)) {
+ // Called from the TestableClient.
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public long getCurrentTimeMs() {
+ return clock.nowMs();
+ }
+
+ /** Removes the registered tasks. */
+ void reset() {
+ logger.fine("Clearing registered tasks on %s", this);
+ registeredTasks.clear();
+ }
+
+ /**
+ * Sets the id of the ticl for which this scheduler will process events. We do not know the
+ * Ticl id until done constructing the Ticl, and we need the scheduler to construct a Ticl. This
+ * method breaks what would otherwise be a dependency cycle on getting the Ticl id.
+ */
+ void setTiclId(long ticlId) {
+ this.ticlId = ticlId;
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698