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

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: Nits 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;
xiyuan 2016/05/17 21:23:55 nit: const -> constexpr and maybe update the other
afakhry 2016/05/17 23:59:44 Done.
85
86 // This is used for browsertests, so that we can test the restartOnWatchdog
87 // API without a kiost app.
88 bool g_allow_non_kiost_apps_restart_api = false;
xiyuan 2016/05/17 21:23:55 nit: remove "g_" prefix since it is not really a g
afakhry 2016/05/17 23:59:45 Done.
89
79 void DispatchOnStartupEventImpl(BrowserContext* browser_context, 90 void DispatchOnStartupEventImpl(BrowserContext* browser_context,
80 const std::string& extension_id, 91 const std::string& extension_id,
81 bool first_call, 92 bool first_call,
82 ExtensionHost* host) { 93 ExtensionHost* host) {
83 // A NULL host from the LazyBackgroundTaskQueue means the page failed to 94 // A NULL host from the LazyBackgroundTaskQueue means the page failed to
84 // load. Give up. 95 // load. Give up.
85 if (!host && !first_call) 96 if (!host && !first_call)
86 return; 97 return;
87 98
88 // Don't send onStartup events to incognito browser contexts. 99 // Don't send onStartup events to incognito browser contexts.
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
149 160
150 template <> 161 template <>
151 void BrowserContextKeyedAPIFactory<RuntimeAPI>::DeclareFactoryDependencies() { 162 void BrowserContextKeyedAPIFactory<RuntimeAPI>::DeclareFactoryDependencies() {
152 DependsOn(ProcessManagerFactory::GetInstance()); 163 DependsOn(ProcessManagerFactory::GetInstance());
153 } 164 }
154 165
155 RuntimeAPI::RuntimeAPI(content::BrowserContext* context) 166 RuntimeAPI::RuntimeAPI(content::BrowserContext* context)
156 : browser_context_(context), 167 : browser_context_(context),
157 dispatch_chrome_updated_event_(false), 168 dispatch_chrome_updated_event_(false),
158 extension_registry_observer_(this), 169 extension_registry_observer_(this),
159 process_manager_observer_(this) { 170 process_manager_observer_(this),
171 minimum_duration_between_restarts_(base::TimeDelta::FromHours(
172 kMinDurationBetweenSuccessiveRestartsHours)),
173 weak_ptr_factory_(this) {
160 // RuntimeAPI is redirected in incognito, so |browser_context_| is never 174 // RuntimeAPI is redirected in incognito, so |browser_context_| is never
161 // incognito. 175 // incognito.
162 DCHECK(!browser_context_->IsOffTheRecord()); 176 DCHECK(!browser_context_->IsOffTheRecord());
163 177
164 registrar_.Add(this, 178 registrar_.Add(this,
165 extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED, 179 extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED,
166 content::Source<BrowserContext>(context)); 180 content::Source<BrowserContext>(context));
167 extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_)); 181 extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_));
168 process_manager_observer_.Add(ProcessManager::Get(browser_context_)); 182 process_manager_observer_.Add(ProcessManager::Get(browser_context_));
169 183
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
314 } 328 }
315 329
316 bool RuntimeAPI::GetPlatformInfo(runtime::PlatformInfo* info) { 330 bool RuntimeAPI::GetPlatformInfo(runtime::PlatformInfo* info) {
317 return delegate_->GetPlatformInfo(info); 331 return delegate_->GetPlatformInfo(info);
318 } 332 }
319 333
320 bool RuntimeAPI::RestartDevice(std::string* error_message) { 334 bool RuntimeAPI::RestartDevice(std::string* error_message) {
321 return delegate_->RestartDevice(error_message); 335 return delegate_->RestartDevice(error_message);
322 } 336 }
323 337
338 RuntimeAPI::RestartOnWatchdogStatus RuntimeAPI::RestartDeviceOnWatchdogTimeout(
339 const std::string& extension_id,
340 int seconds_from_now,
341 const OnWatchdogTimeoutCallback& callback) {
342 // To achieve as much accuracy as possible, record the time of the call as
343 // |now| here.
344 const base::Time now = base::Time::NowFromSystemTime();
345
346 if (schedule_restart_first_extension_id_.empty()) {
347 schedule_restart_first_extension_id_ = extension_id;
348 } else if (extension_id != schedule_restart_first_extension_id_) {
349 // We only allow the first extension to call this API to call it repeatedly.
350 // Any other extension will fail.
351 return RestartOnWatchdogStatus::FAILED_NOT_FIRST_EXTENSION;
352 }
353
354 if (seconds_from_now == -1) {
355 MaybeCancelRunningWatchdogTimer();
356 return RestartOnWatchdogStatus::SUCCESS_RESTART_CANCELLED;
357 }
358
359 // Try to read any previously recorded restart request time.
360 StateStore* storage = ExtensionSystem::Get(browser_context_)->state_store();
361 if (storage) {
362 storage->GetExtensionValue(
363 extension_id, kPrefRestartOnWatchdogTime,
364 base::Bind(&RuntimeAPI::ScheduleDelayedRestart,
365 weak_ptr_factory_.GetWeakPtr(), extension_id, now,
366 seconds_from_now, callback));
367 } else {
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
374 return RestartOnWatchdogStatus::SUCCESS_RESTART_SCHEDULED;
375 }
376
324 bool RuntimeAPI::OpenOptionsPage(const Extension* extension) { 377 bool RuntimeAPI::OpenOptionsPage(const Extension* extension) {
325 return delegate_->OpenOptionsPage(extension); 378 return delegate_->OpenOptionsPage(extension);
326 } 379 }
327 380
381 void RuntimeAPI::MaybeCancelRunningWatchdogTimer() {
382 if (!watchdog_timer_.IsRunning())
383 return;
384
385 if (!current_watchdog_request_callback_.is_null()) {
386 current_watchdog_request_callback_.Run(false,
387 "Restart request was cancelled.");
388 current_watchdog_request_callback_.Reset();
389 }
390 }
391
392 void RuntimeAPI::ScheduleDelayedRestart(
393 const std::string& extension_id,
394 const base::Time& now,
395 int seconds_from_now,
396 const OnWatchdogTimeoutCallback& callback,
397 std::unique_ptr<base::Value> stored_last_restart) {
398 base::TimeDelta delay_till_restart =
399 base::TimeDelta::FromSeconds(seconds_from_now);
400
401 // Read the last restart time, and throttle restart requests that are
402 // received too soon successively.
403 double last_restart_time_double = 0.0;
404 if (stored_last_restart &&
405 stored_last_restart->GetAsDouble(&last_restart_time_double)) {
406 base::Time last_restart_time =
407 base::Time::FromDoubleT(last_restart_time_double);
408
409 base::Time future_restart_time = now + delay_till_restart;
410 base::TimeDelta future_time_since_last_restart =
411 future_restart_time > last_restart_time
412 ? future_restart_time - last_restart_time
413 : base::TimeDelta();
414 if (future_time_since_last_restart < minimum_duration_between_restarts_) {
415 // Schedule the restart after |minimum_duration_between_restarts_| has
416 // passed.
417 delay_till_restart =
418 minimum_duration_between_restarts_ - (now - last_restart_time);
419 }
420 }
421
422 MaybeCancelRunningWatchdogTimer();
423 current_watchdog_request_callback_ = callback;
424 watchdog_timer_.Start(
425 FROM_HERE, delay_till_restart,
426 base::Bind(&RuntimeAPI::OnRestartWatchdogTimeout,
427 weak_ptr_factory_.GetWeakPtr(), extension_id));
428 }
429
430 void RuntimeAPI::OnRestartWatchdogTimeout(const std::string& extension_id) {
431 // We can persist "now" as the last successful restart time, assuming that the
432 // following restart request will succeed, since it can only fail if requested
433 // by non kiost apps, and we prevent that from the beginning (unless in
xiyuan 2016/05/17 21:23:55 kiost -> kiosk
afakhry 2016/05/17 23:59:45 Done.
434 // browsertests).
435 // This assumption is important, since once restart is requested, we might not
436 // have enough time to persist the data to disk.
437 StateStore* storage = ExtensionSystem::Get(browser_context_)->state_store();
438 if (storage) {
439 base::Time now = base::Time::NowFromSystemTime();
440 std::unique_ptr<base::Value> restart_time(
441 new base::FundamentalValue(now.ToDoubleT()));
442 storage->SetExtensionValue(extension_id, kPrefRestartOnWatchdogTime,
443 std::move(restart_time));
444 }
445
446 std::string error_message;
447 const bool success = delegate_->RestartDevice(&error_message);
448
449 current_watchdog_request_callback_.Run(success, error_message);
450 current_watchdog_request_callback_.Reset();
451
452 if (!success && !g_allow_non_kiost_apps_restart_api) {
453 // This is breaking our above assumption and should never be reached.
454 NOTREACHED();
455 }
456 }
457
458 void RuntimeAPI::AllowNonKiostAppsInRestartOnWatchdogForTesting() {
459 g_allow_non_kiost_apps_restart_api = true;
460 }
461
328 /////////////////////////////////////////////////////////////////////////////// 462 ///////////////////////////////////////////////////////////////////////////////
329 463
330 // static 464 // static
331 void RuntimeEventRouter::DispatchOnStartupEvent( 465 void RuntimeEventRouter::DispatchOnStartupEvent(
332 content::BrowserContext* context, 466 content::BrowserContext* context,
333 const std::string& extension_id) { 467 const std::string& extension_id) {
334 DispatchOnStartupEventImpl(context, extension_id, true, NULL); 468 DispatchOnStartupEventImpl(context, extension_id, true, NULL);
335 } 469 }
336 470
337 // static 471 // static
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after
544 std::string message; 678 std::string message;
545 bool result = 679 bool result =
546 RuntimeAPI::GetFactoryInstance()->Get(browser_context())->RestartDevice( 680 RuntimeAPI::GetFactoryInstance()->Get(browser_context())->RestartDevice(
547 &message); 681 &message);
548 if (!result) { 682 if (!result) {
549 return RespondNow(Error(message)); 683 return RespondNow(Error(message));
550 } 684 }
551 return RespondNow(NoArguments()); 685 return RespondNow(NoArguments());
552 } 686 }
553 687
688 ExtensionFunction::ResponseAction RuntimeRestartOnWatchdogFunction::Run() {
689 if (!g_allow_non_kiost_apps_restart_api &&
690 !ExtensionsBrowserClient::Get()->IsRunningInForcedAppMode()) {
691 return RespondNow(Error("API available only for ChromeOS kiosk mode."));
692 }
693
694 std::unique_ptr<api::runtime::RestartOnWatchdog::Params> params(
695 api::runtime::RestartOnWatchdog::Params::Create(*args_));
696 EXTENSION_FUNCTION_VALIDATE(params.get());
697 int seconds = params->seconds;
698
699 if (seconds < -1) {
700 return RespondNow(
701 Error("Invalid argument: *.", base::IntToString(seconds)));
702 }
703
704 RuntimeAPI::RestartOnWatchdogStatus request_status =
705 RuntimeAPI::GetFactoryInstance()
706 ->Get(browser_context())
707 ->RestartDeviceOnWatchdogTimeout(
708 extension()->id(), seconds,
709 base::Bind(&RuntimeRestartOnWatchdogFunction::OnWatchdogTimeout,
710 this));
711
712 switch (request_status) {
713 case RuntimeAPI::RestartOnWatchdogStatus::FAILED_NOT_FIRST_EXTENSION:
714 return RespondNow(Error("Not the first extension to call this API."));
xiyuan 2016/05/17 21:23:55 nit: Use a kErrorXXX for error string literals, he
afakhry 2016/05/17 23:59:45 Done.
715
716 case RuntimeAPI::RestartOnWatchdogStatus::SUCCESS_RESTART_CANCELLED:
717 return RespondNow(
718 ArgumentList(api::runtime::RestartOnWatchdog::Results::Create(
719 true, "No more restarts are scheduled.")));
720 ;
xiyuan 2016/05/17 21:23:55 nit: remove?
afakhry 2016/05/17 23:59:44 Done. Not sure where that came from!
721
722 case RuntimeAPI::RestartOnWatchdogStatus::SUCCESS_RESTART_SCHEDULED:
723 return RespondLater();
724 }
725
726 NOTREACHED();
727 return RespondLater();
xiyuan 2016/05/17 21:23:55 nit: RespondNow with an error.
afakhry 2016/05/17 23:59:44 Done.
728 }
729
730 void RuntimeRestartOnWatchdogFunction::OnWatchdogTimeout(
731 bool success,
732 const std::string& message) {
733 if (!success)
734 WriteToConsole(content::CONSOLE_MESSAGE_LEVEL_ERROR, message);
735
736 Respond(ArgumentList(
737 api::runtime::RestartOnWatchdog::Results::Create(success, message)));
738 }
739
554 ExtensionFunction::ResponseAction RuntimeGetPlatformInfoFunction::Run() { 740 ExtensionFunction::ResponseAction RuntimeGetPlatformInfoFunction::Run() {
555 runtime::PlatformInfo info; 741 runtime::PlatformInfo info;
556 if (!RuntimeAPI::GetFactoryInstance() 742 if (!RuntimeAPI::GetFactoryInstance()
557 ->Get(browser_context()) 743 ->Get(browser_context())
558 ->GetPlatformInfo(&info)) { 744 ->GetPlatformInfo(&info)) {
559 return RespondNow(Error(kPlatformInfoUnavailable)); 745 return RespondNow(Error(kPlatformInfoUnavailable));
560 } 746 }
561 return RespondNow( 747 return RespondNow(
562 ArgumentList(runtime::GetPlatformInfo::Results::Create(info))); 748 ArgumentList(runtime::GetPlatformInfo::Results::Create(info)));
563 } 749 }
(...skipping 13 matching lines...) Expand all
577 content::ChildProcessSecurityPolicy* policy = 763 content::ChildProcessSecurityPolicy* policy =
578 content::ChildProcessSecurityPolicy::GetInstance(); 764 content::ChildProcessSecurityPolicy::GetInstance();
579 policy->GrantReadFileSystem(renderer_id, filesystem_id); 765 policy->GrantReadFileSystem(renderer_id, filesystem_id);
580 base::DictionaryValue* dict = new base::DictionaryValue(); 766 base::DictionaryValue* dict = new base::DictionaryValue();
581 dict->SetString("fileSystemId", filesystem_id); 767 dict->SetString("fileSystemId", filesystem_id);
582 dict->SetString("baseName", relative_path); 768 dict->SetString("baseName", relative_path);
583 return RespondNow(OneArgument(dict)); 769 return RespondNow(OneArgument(dict));
584 } 770 }
585 771
586 } // namespace extensions 772 } // 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