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

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: 3/19 comments 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.
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} TaskManager interface.
33 */
34 function TaskManager(areConflicting) {
arv (Not doing code reviews) 2013/03/21 21:40:21 make this into a class?
vadimt 2013/03/21 22:57:05 Here, I want to create a collection of methods wit
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.<string, function(function())>>}
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 // Start the oldest queued task, but don't remove it from the queue.
71 verify(stepName == null, 'tasks.startFirst: stepName is not null');
72 var entry = queue[0];
73 stepName = entry.name + '-initial';
74 entry.task(finish);
75 }
76
77 /**
78 * Checks if a new task can be added to the task queue.
79 * @param {string} 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)
arv (Not doing code reviews) 2013/03/21 21:40:21 only if has optional {}
vadimt 2013/03/21 22:57:05 Done.
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, runs the task immediately.
92 * If any task in the queue is not compatible with the task, ignores the new
93 * task. Otherwise, stores the task for future execution.
94 * @param {string} taskName Name of the task.
95 * @param {function(function())} task Function to run. Takes a callback
96 * parameter.
97 */
98 function add(taskName, task) {
99 if (!canQueue(taskName))
100 return;
101
102 queue.push({name: taskName, task: task});
103
104 if (queue.length == 1) {
105 startFirst();
106 }
107 }
108
109 /**
110 * Completes the current task and starts the next queued task if available.
111 */
112 function finish() {
113 verify(queue.length >= 1, 'tasks.finish: The task queue is empty.');
114 queue.shift();
115 stepName = null;
116
117 if (queue.length >= 1)
118 startFirst();
119 }
120
121 /**
122 * Associates a name with the current step of the task. Used for diagnostics
123 * only. A task is a chain of asynchronous events; debugSetStepName should be
124 * called before starting any asynchronous operation.
125 * @param {string} step Name of new step.
126 */
127 function debugSetStepName(step) {
128 // TODO(vadimt): Pass UMA counters instead of step names.
129 stepName = step;
130 }
131
132 chrome.alarms.onAlarm.addListener(function(alarm) {
133 if (alarm.name == CANNOT_UNLOAD_ALARM_NAME) {
134 // Error if the event page wasn't unloaded after a reasonable timeout
135 // since starting the last task.
136 // TODO(vadimt): Uncomment the verify once this bug is fixed:
137 // crbug.com/177563
138 // verify(false, 'Event page didn\'t unload, queue = ' +
139 // JSON.stringify(tasks) + ', step = ' + stepName + ' (ignore this verify
140 // if devtools is attached).');
141 }
142 });
143
144 chrome.runtime.onSuspend.addListener(function() {
145 chrome.alarms.clear(CANNOT_UNLOAD_ALARM_NAME);
146 verify(queue.length == 0 && stepName == null,
147 'Incomplete task when unloading event page, queue = ' +
148 JSON.stringify(queue) + ', step = ' + stepName);
149 });
150
151 return {
152 add: add,
153 debugSetStepName: debugSetStepName
154 };
155 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698