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

Side by Side Diff: chrome/browser/resources/google_now/utility.js

Issue 12316075: Preventing race conditions in Google Now extension (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Separating utilities into a separate file. Created 7 years, 9 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 'use strict';
6
7 /**
8 * @fileoverview Utility objects and functions for Google Now extension.
9 */
10
11 /**
12 * Checks for internal errors.
13 * @param {boolean} condition Condition that must be true.
14 * @param {string} message Diagnostic message for the case when the condition is
15 * false.
16 */
17 function verify(condition, message) {
18 // TODO(vadimt): Send UMAs instead of showing alert.
19 // TODO(vadimt): Make sure the execution doesn't continue after this call.
skare_ 2013/03/14 00:48:50 how? why? don't mean that to sound short, just cur
rgustafson 2013/03/14 19:05:20 This was in relation to wanting to early return on
vadimt 2013/03/14 22:56:05 Well, you asked to make sure that in startFirst(),
vadimt 2013/03/14 22:56:05 Correct. I'll accomplish this by throwing an excep
20 if (!condition) {
21 var errorText = 'ASSERT: ' + message;
22 console.error(errorText);
23 alert(errorText);
24 }
25 }
26
27 /**
28 * Builds the object to manage tasks (mutually exclusive chains of events).
29 * @param {function(string, string): boolean} areConflicting Function that
30 * checks if a new task can't be added to a task queue that contains an
31 * existing task.
32 * @return {Object} Set of methods to manage tasks.
33 */
34 function TaskManager(areConflicting) {
35 /**
36 * Name of the alarm that triggers the error saying that the event page cannot
37 * unload.
38 */
39 var CANNOT_UNLOAD_ALARM_NAME = 'CANNOT-UNLOAD';
40
41 /**
42 * Maximal time we expect the event page to stay loaded after starting a task.
43 */
44 var MAXIMUM_LOADED_TIME_MINUTES = 5;
45
46 /**
47 * Queue of scheduled tasks. The first element, if present, corresponds to the
48 * currently running task.
49 * @type {Array.<Object.<TaskName, function()>>}
skare_ 2013/03/14 00:48:50 the TaskName typedef might belong in this file.
vadimt 2013/03/14 22:56:05 Doesn't it have to list all task names, which does
skare_ 2013/03/19 18:51:39 ok... probably not an issue since we're not runnin
vadimt 2013/03/19 20:01:55 Already done.
50 */
51 var queue = [];
52
53 /**
54 * Name of the current step of the currently running task if present,
55 * otherwise, null. For diagnostics only.
56 * It's set when the task is started and before each asynchronous operation.
57 */
58 var stepName = null;
59
60 /**
61 * Starts the first queued task.
62 */
63 function startFirst() {
64 verify(queue.length >= 1, 'startFirst: queue is empty');
65
66 // Set alarm to verify that the event page will unload in a reasonable time.
67 chrome.alarms.create(CANNOT_UNLOAD_ALARM_NAME,
68 {delayInMinutes: MAXIMUM_LOADED_TIME_MINUTES});
69
70 // Starts the oldest queued task, but doesn't remove it from the queue.
skare_ 2013/03/14 00:48:50 I forget the long and storied history of this comm
vadimt 2013/03/14 22:56:05 Done.
71 verify(stepName == null, 'tasks.startFirst: stepName is not null');
72 var entry = queue[0];
73 stepName = entry.name + '-initial';
74 entry.task();
75 }
76
77 /**
78 * Checks if a new task can be added to the task queue.
79 * @param {TaskName} taskName Name of the new task.
80 * @return {boolean} Whether the new task can be added.
81 */
82 function canQueue(taskName) {
83 for (var i = 0; i < queue.length; ++i)
84 if (areConflicting(taskName, queue[i].name))
85 return false;
86
87 return true;
88 }
89
90 /**
91 * Adds a new task. If another task is not running, run the task immediately.
skare_ 2013/03/14 00:48:50 nit: s/run/runs. s/ignore/ignores and s/store/stor
vadimt 2013/03/14 22:56:05 Done.
92 * If any task in the queue is not compatible with the task, ignore the new
93 * task. Otherwise, store the task for future execution.
94 * @param {TaskName} taskName Name of the task.
95 * @param {function()} task Code of the task.
skare_ 2013/03/14 00:48:50 code of the task -> "function to run" or similar?
vadimt 2013/03/14 22:56:05 Done.
96 */
97 function submit(taskName, task) {
98 if (!canQueue(taskName))
99 return;
100
101 queue.push({name: taskName, task: task});
102
103 if (queue.length == 1) {
104 startFirst();
105 }
106 }
107
108 /**
109 * Completes the current task and start the next queued task if available.
skare_ 2013/03/14 00:48:50 s/start/starts
vadimt 2013/03/14 22:56:05 Done.
110 */
111 function finish() {
112 verify(queue.length >= 1, 'tasks.finish: The task queue is empty.');
skare_ 2013/03/14 00:48:50 referencing comment on verify() way up at the top
vadimt 2013/03/14 22:56:05 I'll build a general solution (likely, throwing an
113 queue.shift();
114 stepName = null;
115
116 if (queue.length >= 1)
117 startFirst();
118 }
119
120 /**
121 * Associates a name with the current step of the task. Used for diagnostics
122 * only. A task is a chain of asynchronous events; debugSetStepName should be
123 * called before starting any asynchronous operation.
124 * @param {string} step Name of new step.
125 */
126 function debugSetStepName(step) {
skare_ 2013/03/14 00:48:50 would this ever do anything more? If so, this clas
vadimt 2013/03/14 22:56:05 It may or may not do additional things in future.
127 // TODO(vadimt): Pass UMA counters instead of step names.
128 stepName = step;
129 }
130
131 chrome.alarms.onAlarm.addListener(function(alarm) {
132 if (alarm.name == CANNOT_UNLOAD_ALARM_NAME) {
133 // Error if the event page wasn't unloaded after a reasonable timeout
134 // since starting the last task.
135 // TODO(vadimt): Uncomment the verify once this bug is fixed:
136 // crbug.com/177563
137 // verify(false, 'Event page didn\'t unload, queue = ' +
138 // JSON.stringify(tasks) + ', step = ' + stepName + ' (ignore this verify
139 // if devtools is attached).');
140 }
141 });
142
143 chrome.runtime.onSuspend.addListener(function() {
144 chrome.alarms.clear(CANNOT_UNLOAD_ALARM_NAME);
145 verify(queue.length == 0 && stepName == null,
146 'Incomplete task when unloading event page, queue = ' +
147 JSON.stringify(queue) + ', step = ' + stepName);
148 });
149
150 return {
151 submit: submit,
skare_ 2013/03/14 00:48:50 submit -> pushTask, queueTask, addTask, schedule()
vadimt 2013/03/14 22:56:05 Done.
152 debugSetStepName: debugSetStepName,
153 finish: finish
154 };
155 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698