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

Side by Side Diff: extensions/browser/api/runtime/runtime_api.cc

Issue 1970613003: Add a new app API to enable watchdog behavior restarts in kiosk apps (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Xiyuan's comments Created 4 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 unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "extensions/browser/api/runtime/runtime_api.h" 5 #include "extensions/browser/api/runtime/runtime_api.h"
6 6
7 #include <memory> 7 #include <memory>
8 #include <utility> 8 #include <utility>
9 9
10 #include "base/lazy_instance.h" 10 #include "base/lazy_instance.h"
11 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/metrics/histogram.h" 12 #include "base/metrics/histogram.h"
13 #include "base/strings/string_number_conversions.h"
13 #include "base/values.h" 14 #include "base/values.h"
14 #include "base/version.h" 15 #include "base/version.h"
15 #include "content/public/browser/browser_context.h" 16 #include "content/public/browser/browser_context.h"
16 #include "content/public/browser/child_process_security_policy.h" 17 #include "content/public/browser/child_process_security_policy.h"
17 #include "content/public/browser/notification_service.h" 18 #include "content/public/browser/notification_service.h"
18 #include "content/public/browser/render_frame_host.h" 19 #include "content/public/browser/render_frame_host.h"
19 #include "content/public/browser/render_process_host.h" 20 #include "content/public/browser/render_process_host.h"
20 #include "extensions/browser/api/runtime/runtime_api_delegate.h" 21 #include "extensions/browser/api/runtime/runtime_api_delegate.h"
21 #include "extensions/browser/event_router.h" 22 #include "extensions/browser/event_router.h"
22 #include "extensions/browser/extension_host.h" 23 #include "extensions/browser/extension_host.h"
23 #include "extensions/browser/extension_prefs.h" 24 #include "extensions/browser/extension_prefs.h"
24 #include "extensions/browser/extension_registry.h" 25 #include "extensions/browser/extension_registry.h"
25 #include "extensions/browser/extension_system.h" 26 #include "extensions/browser/extension_system.h"
26 #include "extensions/browser/extension_util.h" 27 #include "extensions/browser/extension_util.h"
27 #include "extensions/browser/extensions_browser_client.h" 28 #include "extensions/browser/extensions_browser_client.h"
28 #include "extensions/browser/lazy_background_task_queue.h" 29 #include "extensions/browser/lazy_background_task_queue.h"
29 #include "extensions/browser/notification_types.h" 30 #include "extensions/browser/notification_types.h"
30 #include "extensions/browser/process_manager_factory.h" 31 #include "extensions/browser/process_manager_factory.h"
32 #include "extensions/browser/state_store.h"
31 #include "extensions/common/api/runtime.h" 33 #include "extensions/common/api/runtime.h"
32 #include "extensions/common/error_utils.h" 34 #include "extensions/common/error_utils.h"
33 #include "extensions/common/extension.h" 35 #include "extensions/common/extension.h"
34 #include "extensions/common/manifest_handlers/background_info.h" 36 #include "extensions/common/manifest_handlers/background_info.h"
35 #include "extensions/common/manifest_handlers/shared_module_info.h" 37 #include "extensions/common/manifest_handlers/shared_module_info.h"
36 #include "storage/browser/fileapi/isolated_context.h" 38 #include "storage/browser/fileapi/isolated_context.h"
37 #include "url/gurl.h" 39 #include "url/gurl.h"
38 40
39 using content::BrowserContext; 41 using content::BrowserContext;
40 42
(...skipping 28 matching lines...) Expand all
69 "pending_on_installed_event_dispatch_info"; 71 "pending_on_installed_event_dispatch_info";
70 72
71 // Previously installed version number. 73 // Previously installed version number.
72 const char kPrefPreviousVersion[] = "previous_version"; 74 const char kPrefPreviousVersion[] = "previous_version";
73 75
74 // The name of the directory to be returned by getPackageDirectoryEntry. This 76 // The name of the directory to be returned by getPackageDirectoryEntry. This
75 // particular value does not matter to user code, but is chosen for consistency 77 // particular value does not matter to user code, but is chosen for consistency
76 // with the equivalent Pepper API. 78 // with the equivalent Pepper API.
77 const char kPackageDirectoryPath[] = "crxfs"; 79 const char kPackageDirectoryPath[] = "crxfs";
78 80
81 // Preference key for storing the last successful restart on watchdog requests.
82 const char kPrefRestartOnWatchdogTime[] = "last_restart_on_watchdog_time";
83
84 const int kMinDurationBetweenSuccessiveRestartsHours = 3;
85
79 void DispatchOnStartupEventImpl(BrowserContext* browser_context, 86 void DispatchOnStartupEventImpl(BrowserContext* browser_context,
80 const std::string& extension_id, 87 const std::string& extension_id,
81 bool first_call, 88 bool first_call,
82 ExtensionHost* host) { 89 ExtensionHost* host) {
83 // A NULL host from the LazyBackgroundTaskQueue means the page failed to 90 // A NULL host from the LazyBackgroundTaskQueue means the page failed to
84 // load. Give up. 91 // load. Give up.
85 if (!host && !first_call) 92 if (!host && !first_call)
86 return; 93 return;
87 94
88 // Don't send onStartup events to incognito browser contexts. 95 // Don't send onStartup events to incognito browser contexts.
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
149 156
150 template <> 157 template <>
151 void BrowserContextKeyedAPIFactory<RuntimeAPI>::DeclareFactoryDependencies() { 158 void BrowserContextKeyedAPIFactory<RuntimeAPI>::DeclareFactoryDependencies() {
152 DependsOn(ProcessManagerFactory::GetInstance()); 159 DependsOn(ProcessManagerFactory::GetInstance());
153 } 160 }
154 161
155 RuntimeAPI::RuntimeAPI(content::BrowserContext* context) 162 RuntimeAPI::RuntimeAPI(content::BrowserContext* context)
156 : browser_context_(context), 163 : browser_context_(context),
157 dispatch_chrome_updated_event_(false), 164 dispatch_chrome_updated_event_(false),
158 extension_registry_observer_(this), 165 extension_registry_observer_(this),
159 process_manager_observer_(this) { 166 process_manager_observer_(this),
167 minimum_duration_between_restarts_(base::TimeDelta::FromHours(
168 kMinDurationBetweenSuccessiveRestartsHours)),
169 weak_ptr_factory_(this) {
160 // RuntimeAPI is redirected in incognito, so |browser_context_| is never 170 // RuntimeAPI is redirected in incognito, so |browser_context_| is never
161 // incognito. 171 // incognito.
162 DCHECK(!browser_context_->IsOffTheRecord()); 172 DCHECK(!browser_context_->IsOffTheRecord());
163 173
164 registrar_.Add(this, 174 registrar_.Add(this,
165 extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED, 175 extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED,
166 content::Source<BrowserContext>(context)); 176 content::Source<BrowserContext>(context));
167 extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_)); 177 extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_));
168 process_manager_observer_.Add(ProcessManager::Get(browser_context_)); 178 process_manager_observer_.Add(ProcessManager::Get(browser_context_));
169 179
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
314 } 324 }
315 325
316 bool RuntimeAPI::GetPlatformInfo(runtime::PlatformInfo* info) { 326 bool RuntimeAPI::GetPlatformInfo(runtime::PlatformInfo* info) {
317 return delegate_->GetPlatformInfo(info); 327 return delegate_->GetPlatformInfo(info);
318 } 328 }
319 329
320 bool RuntimeAPI::RestartDevice(std::string* error_message) { 330 bool RuntimeAPI::RestartDevice(std::string* error_message) {
321 return delegate_->RestartDevice(error_message); 331 return delegate_->RestartDevice(error_message);
322 } 332 }
323 333
334 void RuntimeAPI::RestartDeviceOnWatchdogTimeout(
335 const std::string& extension_id,
336 int seconds_from_now,
337 const OnWatchdogTimeoutCallback& callback) {
338 // To achieve as much accuracy as possible, record the time of the call as
339 // |now| here.
340 base::Time now = base::Time::NowFromSystemTime();
xiyuan 2016/05/16 18:25:17 nit: const base::Time
afakhry 2016/05/17 18:38:31 Done.
341
342 if (schedule_restart_first_extension_id_.empty()) {
343 schedule_restart_first_extension_id_ = extension_id;
344 } else if (extension_id != schedule_restart_first_extension_id_) {
345 // We only allow the first extension to call this API to call it repeatedly.
346 // Any other extension will fail.
347 callback.Run(false, "Error: Not the first extension to call this API.");
348 return;
349 }
350
351 if (seconds_from_now == -1) {
352 MaybeCancelRunningWatchdogTimer();
353 callback.Run(true, "No more restarts are scheduled.");
354 return;
355 }
356
357 // Try to read any previously recorded restart request time.
358 StateStore* storage = ExtensionSystem::Get(browser_context_)->state_store();
359 if (storage) {
360 storage->GetExtensionValue(
361 extension_id, kPrefRestartOnWatchdogTime,
362 base::Bind(&RuntimeAPI::ScheduleDelayedRestart,
363 weak_ptr_factory_.GetWeakPtr(), extension_id, now,
364 seconds_from_now, callback));
365 return;
366 }
367
368 std::unique_ptr<base::Value> stored_last_restart(
369 new base::FundamentalValue(0.0));
370 ScheduleDelayedRestart(extension_id, now, seconds_from_now, callback,
371 std::move(stored_last_restart));
372 }
373
324 bool RuntimeAPI::OpenOptionsPage(const Extension* extension) { 374 bool RuntimeAPI::OpenOptionsPage(const Extension* extension) {
325 return delegate_->OpenOptionsPage(extension); 375 return delegate_->OpenOptionsPage(extension);
326 } 376 }
327 377
378 void RuntimeAPI::MaybeCancelRunningWatchdogTimer() {
379 if (!watchdog_timer_.IsRunning())
380 return;
381
382 if (!current_watchdog_request_callback_.is_null()) {
383 current_watchdog_request_callback_.Run(false,
384 "Restart request was cancelled.");
385 current_watchdog_request_callback_.Reset();
386 }
387 }
388
389 void RuntimeAPI::ScheduleDelayedRestart(
390 const std::string& extension_id,
391 const base::Time& now,
392 int seconds_from_now,
xiyuan 2016/05/16 18:25:17 nit: slightly prefer to combine |now| and |seconds
afakhry 2016/05/17 18:38:31 I think this might add a bit of redundancy, since
393 const OnWatchdogTimeoutCallback& callback,
394 std::unique_ptr<base::Value> stored_last_restart) {
395 base::TimeDelta delay_till_restart =
396 base::TimeDelta::FromSeconds(seconds_from_now);
397
398 // Read the last restart time, and throttle restart requests that are
399 // received too soon successively.
400 double last_restart_time_double = 0.0;
401 if (stored_last_restart &&
402 stored_last_restart->GetAsDouble(&last_restart_time_double)) {
403 base::Time last_restart_time =
404 base::Time::FromDoubleT(last_restart_time_double);
405
406 base::Time future_restart_time = now + delay_till_restart;
407 base::TimeDelta future_time_since_last_restart =
408 future_restart_time - last_restart_time;
xiyuan 2016/05/16 18:25:17 nit: future_restart_time > last_restart_time ?
afakhry 2016/05/17 18:38:31 Done.
409 if (future_time_since_last_restart < minimum_duration_between_restarts_) {
410 // Schedule the restart after |minimum_duration_between_restarts_| has
411 // passed.
412 delay_till_restart =
413 minimum_duration_between_restarts_ - (now - last_restart_time);
414 }
415 }
416
417 MaybeCancelRunningWatchdogTimer();
418 current_watchdog_request_callback_ = callback;
419 watchdog_timer_.Start(FROM_HERE, delay_till_restart,
420 base::Bind(&RuntimeAPI::OnRestartWatchdogTimeout,
421 base::Unretained(this), extension_id));
xiyuan 2016/05/16 18:25:17 nit: replace base::Unretained with weak_ptr_factor
afakhry 2016/05/17 18:38:31 Done.
422 }
423
424 void RuntimeAPI::OnRestartWatchdogTimeout(const std::string& extension_id) {
425 std::string error_message;
426 const bool success = delegate_->RestartDevice(&error_message);
427
428 current_watchdog_request_callback_.Run(success, error_message);
429 current_watchdog_request_callback_.Reset();
430
431 if (success) {
432 // Store |now| as the last successful restart request time.
433 StateStore* storage = ExtensionSystem::Get(browser_context_)->state_store();
434 if (storage) {
435 base::Time now = base::Time::NowFromSystemTime();
436 std::unique_ptr<base::Value> restart_time(
437 new base::FundamentalValue(now.ToDoubleT()));
438 storage->SetExtensionValue(extension_id, kPrefRestartOnWatchdogTime,
xiyuan 2016/05/16 18:25:17 We might want to make this happen before attemptin
afakhry 2016/05/17 18:38:31 Done. My concern was, I didn't want to store "now
439 std::move(restart_time));
440 }
441 }
442 }
443
328 /////////////////////////////////////////////////////////////////////////////// 444 ///////////////////////////////////////////////////////////////////////////////
329 445
330 // static 446 // static
331 void RuntimeEventRouter::DispatchOnStartupEvent( 447 void RuntimeEventRouter::DispatchOnStartupEvent(
332 content::BrowserContext* context, 448 content::BrowserContext* context,
333 const std::string& extension_id) { 449 const std::string& extension_id) {
334 DispatchOnStartupEventImpl(context, extension_id, true, NULL); 450 DispatchOnStartupEventImpl(context, extension_id, true, NULL);
335 } 451 }
336 452
337 // static 453 // static
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after
544 std::string message; 660 std::string message;
545 bool result = 661 bool result =
546 RuntimeAPI::GetFactoryInstance()->Get(browser_context())->RestartDevice( 662 RuntimeAPI::GetFactoryInstance()->Get(browser_context())->RestartDevice(
547 &message); 663 &message);
548 if (!result) { 664 if (!result) {
549 return RespondNow(Error(message)); 665 return RespondNow(Error(message));
550 } 666 }
551 return RespondNow(NoArguments()); 667 return RespondNow(NoArguments());
552 } 668 }
553 669
670 ExtensionFunction::ResponseAction RuntimeRestartOnWatchdogFunction::Run() {
671 std::unique_ptr<api::runtime::RestartOnWatchdog::Params> params(
672 api::runtime::RestartOnWatchdog::Params::Create(*args_));
673 EXTENSION_FUNCTION_VALIDATE(params.get());
674
675 // TODO(afakhry): Handle non-kiost apps.
676
677 int seconds = params->seconds;
678
679 if (seconds < -1) {
680 return RespondNow(
681 Error("Invalid argument: *.", base::IntToString(seconds)));
682 }
683
684 RuntimeAPI::GetFactoryInstance()
685 ->Get(browser_context())
686 ->RestartDeviceOnWatchdogTimeout(
687 extension()->id(), seconds,
688 base::Bind(&RuntimeRestartOnWatchdogFunction::OnWatchdogTimeout,
689 this));
690
691 return RespondLater();
xiyuan 2016/05/16 18:25:17 RestartDeviceOnWatchdogTimeout() might call Respon
afakhry 2016/05/17 18:38:31 Done! Thanks for catching that. I made RestartDevi
692 }
693
694 void RuntimeRestartOnWatchdogFunction::OnWatchdogTimeout(
695 bool success,
696 const std::string& message) {
697 if (!success)
698 WriteToConsole(content::CONSOLE_MESSAGE_LEVEL_ERROR, message);
699
700 Respond(ArgumentList(
701 api::runtime::RestartOnWatchdog::Results::Create(success, message)));
702 }
703
554 ExtensionFunction::ResponseAction RuntimeGetPlatformInfoFunction::Run() { 704 ExtensionFunction::ResponseAction RuntimeGetPlatformInfoFunction::Run() {
555 runtime::PlatformInfo info; 705 runtime::PlatformInfo info;
556 if (!RuntimeAPI::GetFactoryInstance() 706 if (!RuntimeAPI::GetFactoryInstance()
557 ->Get(browser_context()) 707 ->Get(browser_context())
558 ->GetPlatformInfo(&info)) { 708 ->GetPlatformInfo(&info)) {
559 return RespondNow(Error(kPlatformInfoUnavailable)); 709 return RespondNow(Error(kPlatformInfoUnavailable));
560 } 710 }
561 return RespondNow( 711 return RespondNow(
562 ArgumentList(runtime::GetPlatformInfo::Results::Create(info))); 712 ArgumentList(runtime::GetPlatformInfo::Results::Create(info)));
563 } 713 }
(...skipping 13 matching lines...) Expand all
577 content::ChildProcessSecurityPolicy* policy = 727 content::ChildProcessSecurityPolicy* policy =
578 content::ChildProcessSecurityPolicy::GetInstance(); 728 content::ChildProcessSecurityPolicy::GetInstance();
579 policy->GrantReadFileSystem(renderer_id, filesystem_id); 729 policy->GrantReadFileSystem(renderer_id, filesystem_id);
580 base::DictionaryValue* dict = new base::DictionaryValue(); 730 base::DictionaryValue* dict = new base::DictionaryValue();
581 dict->SetString("fileSystemId", filesystem_id); 731 dict->SetString("fileSystemId", filesystem_id);
582 dict->SetString("baseName", relative_path); 732 dict->SetString("baseName", relative_path);
583 return RespondNow(OneArgument(dict)); 733 return RespondNow(OneArgument(dict));
584 } 734 }
585 735
586 } // namespace extensions 736 } // namespace extensions
OLDNEW
« no previous file with comments | « extensions/browser/api/runtime/runtime_api.h ('k') | extensions/browser/api/runtime/runtime_apitest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698