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

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: arv@ 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
« no previous file with comments | « chrome/browser/resources/google_now/manifest.json ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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} Task manager interface.
33 */
34 function buildTaskManager(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.<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) {
84 if (areConflicting(taskName, queue[i].name))
85 return false;
86 }
87
88 return true;
89 }
90
91 /**
92 * Adds a new task. If another task is not running, runs the task immediately.
93 * If any task in the queue is not compatible with the task, ignores the new
94 * task. Otherwise, stores the task for future execution.
95 * @param {string} taskName Name of the task.
96 * @param {function(function())} task Function to run. Takes a callback
97 * parameter.
98 */
99 function add(taskName, task) {
100 if (!canQueue(taskName))
101 return;
102
103 queue.push({name: taskName, task: task});
104
105 if (queue.length == 1) {
106 startFirst();
107 }
108 }
109
110 /**
111 * Completes the current task and starts the next queued task if available.
112 */
113 function finish() {
114 verify(queue.length >= 1, 'tasks.finish: The task queue is empty.');
115 queue.shift();
116 stepName = null;
117
118 if (queue.length >= 1)
119 startFirst();
120 }
121
122 /**
123 * Associates a name with the current step of the task. Used for diagnostics
124 * only. A task is a chain of asynchronous events; debugSetStepName should be
125 * called before starting any asynchronous operation.
126 * @param {string} step Name of new step.
127 */
128 function debugSetStepName(step) {
129 // TODO(vadimt): Pass UMA counters instead of step names.
130 stepName = step;
131 }
132
133 chrome.alarms.onAlarm.addListener(function(alarm) {
134 if (alarm.name == CANNOT_UNLOAD_ALARM_NAME) {
135 // Error if the event page wasn't unloaded after a reasonable timeout
136 // since starting the last task.
137 // TODO(vadimt): Uncomment the verify once this bug is fixed:
138 // crbug.com/177563
139 // verify(false, 'Event page didn\'t unload, queue = ' +
140 // JSON.stringify(tasks) + ', step = ' + stepName + ' (ignore this verify
141 // if devtools is attached).');
142 }
143 });
144
145 chrome.runtime.onSuspend.addListener(function() {
146 chrome.alarms.clear(CANNOT_UNLOAD_ALARM_NAME);
147 verify(queue.length == 0 && stepName == null,
148 'Incomplete task when unloading event page, queue = ' +
149 JSON.stringify(queue) + ', step = ' + stepName);
150 });
151
152 return {
153 add: add,
154 debugSetStepName: debugSetStepName
155 };
156 }
OLDNEW
« no previous file with comments | « chrome/browser/resources/google_now/manifest.json ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698