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

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

Issue 2070753003: Revert "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: Created 4 years, 6 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/location.h" 11 #include "base/location.h"
12 #include "base/logging.h" 12 #include "base/logging.h"
13 #include "base/memory/ptr_util.h" 13 #include "base/memory/ptr_util.h"
14 #include "base/metrics/histogram.h" 14 #include "base/metrics/histogram.h"
15 #include "base/single_thread_task_runner.h" 15 #include "base/single_thread_task_runner.h"
16 #include "base/strings/string_number_conversions.h"
17 #include "base/threading/thread_task_runner_handle.h" 16 #include "base/threading/thread_task_runner_handle.h"
18 #include "base/values.h" 17 #include "base/values.h"
19 #include "base/version.h" 18 #include "base/version.h"
20 #include "components/prefs/pref_registry_simple.h"
21 #include "components/prefs/pref_service.h"
22 #include "content/public/browser/browser_context.h" 19 #include "content/public/browser/browser_context.h"
23 #include "content/public/browser/child_process_security_policy.h" 20 #include "content/public/browser/child_process_security_policy.h"
24 #include "content/public/browser/notification_service.h" 21 #include "content/public/browser/notification_service.h"
25 #include "content/public/browser/render_frame_host.h" 22 #include "content/public/browser/render_frame_host.h"
26 #include "content/public/browser/render_process_host.h" 23 #include "content/public/browser/render_process_host.h"
27 #include "extensions/browser/api/runtime/runtime_api_delegate.h" 24 #include "extensions/browser/api/runtime/runtime_api_delegate.h"
28 #include "extensions/browser/event_router.h" 25 #include "extensions/browser/event_router.h"
29 #include "extensions/browser/extension_host.h" 26 #include "extensions/browser/extension_host.h"
30 #include "extensions/browser/extension_prefs.h" 27 #include "extensions/browser/extension_prefs.h"
31 #include "extensions/browser/extension_registry.h" 28 #include "extensions/browser/extension_registry.h"
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
76 "pending_on_installed_event_dispatch_info"; 73 "pending_on_installed_event_dispatch_info";
77 74
78 // Previously installed version number. 75 // Previously installed version number.
79 const char kPrefPreviousVersion[] = "previous_version"; 76 const char kPrefPreviousVersion[] = "previous_version";
80 77
81 // The name of the directory to be returned by getPackageDirectoryEntry. This 78 // The name of the directory to be returned by getPackageDirectoryEntry. This
82 // particular value does not matter to user code, but is chosen for consistency 79 // particular value does not matter to user code, but is chosen for consistency
83 // with the equivalent Pepper API. 80 // with the equivalent Pepper API.
84 const char kPackageDirectoryPath[] = "crxfs"; 81 const char kPackageDirectoryPath[] = "crxfs";
85 82
86 // Preference key for storing the last successful restart due to a call to
87 // chrome.runtime.restartAfterDelay().
88 constexpr char kPrefLastRestartAfterDelayTime[] =
89 "last_restart_after_delay_time";
90 // Preference key for storing whether the most recent restart was due to a
91 // successful call to chrome.runtime.restartAfterDelay().
92 constexpr char kPrefLastRestartWasDueToDelayedRestartApi[] =
93 "last_restart_was_due_to_delayed_restart_api";
94
95 // Error and status messages strings for the restartAfterDelay() API.
96 constexpr char kErrorInvalidArgument[] = "Invalid argument: *.";
97 constexpr char kErrorOnlyKioskModeAllowed[] =
98 "API available only for ChromeOS kiosk mode.";
99 constexpr char kErrorOnlyFirstExtensionAllowed[] =
100 "Not the first extension to call this API.";
101 constexpr char kErrorInvalidStatus[] = "Invalid restart request status.";
102 constexpr char kErrorRequestedTooSoon[] =
103 "Restart was requested too soon. It was throttled instead.";
104
105 constexpr int kMinDurationBetweenSuccessiveRestartsHours = 3;
106
107 // This is used for unit tests, so that we can test the restartAfterDelay
108 // API without a kiosk app.
109 bool allow_non_kiosk_apps_restart_api_for_test = false;
110
111 void DispatchOnStartupEventImpl(BrowserContext* browser_context, 83 void DispatchOnStartupEventImpl(BrowserContext* browser_context,
112 const std::string& extension_id, 84 const std::string& extension_id,
113 bool first_call, 85 bool first_call,
114 ExtensionHost* host) { 86 ExtensionHost* host) {
115 // A NULL host from the LazyBackgroundTaskQueue means the page failed to 87 // A NULL host from the LazyBackgroundTaskQueue means the page failed to
116 // load. Give up. 88 // load. Give up.
117 if (!host && !first_call) 89 if (!host && !first_call)
118 return; 90 return;
119 91
120 // Don't send onStartup events to incognito browser contexts. 92 // Don't send onStartup events to incognito browser contexts.
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
172 /////////////////////////////////////////////////////////////////////////////// 144 ///////////////////////////////////////////////////////////////////////////////
173 145
174 static base::LazyInstance<BrowserContextKeyedAPIFactory<RuntimeAPI> > 146 static base::LazyInstance<BrowserContextKeyedAPIFactory<RuntimeAPI> >
175 g_factory = LAZY_INSTANCE_INITIALIZER; 147 g_factory = LAZY_INSTANCE_INITIALIZER;
176 148
177 // static 149 // static
178 BrowserContextKeyedAPIFactory<RuntimeAPI>* RuntimeAPI::GetFactoryInstance() { 150 BrowserContextKeyedAPIFactory<RuntimeAPI>* RuntimeAPI::GetFactoryInstance() {
179 return g_factory.Pointer(); 151 return g_factory.Pointer();
180 } 152 }
181 153
182 // static
183 void RuntimeAPI::RegisterPrefs(PrefRegistrySimple* registry) {
184 registry->RegisterBooleanPref(kPrefLastRestartWasDueToDelayedRestartApi,
185 false);
186 registry->RegisterDoublePref(kPrefLastRestartAfterDelayTime, 0.0);
187 }
188
189 template <> 154 template <>
190 void BrowserContextKeyedAPIFactory<RuntimeAPI>::DeclareFactoryDependencies() { 155 void BrowserContextKeyedAPIFactory<RuntimeAPI>::DeclareFactoryDependencies() {
191 DependsOn(ProcessManagerFactory::GetInstance()); 156 DependsOn(ProcessManagerFactory::GetInstance());
192 } 157 }
193 158
194 RuntimeAPI::RuntimeAPI(content::BrowserContext* context) 159 RuntimeAPI::RuntimeAPI(content::BrowserContext* context)
195 : browser_context_(context), 160 : browser_context_(context),
161 dispatch_chrome_updated_event_(false),
196 extension_registry_observer_(this), 162 extension_registry_observer_(this),
197 process_manager_observer_(this), 163 process_manager_observer_(this) {
198 minimum_duration_between_restarts_(base::TimeDelta::FromHours(
199 kMinDurationBetweenSuccessiveRestartsHours)),
200 dispatch_chrome_updated_event_(false),
201 did_read_delayed_restart_preferences_(false),
202 was_last_restart_due_to_delayed_restart_api_(false),
203 weak_ptr_factory_(this) {
204 // RuntimeAPI is redirected in incognito, so |browser_context_| is never 164 // RuntimeAPI is redirected in incognito, so |browser_context_| is never
205 // incognito. 165 // incognito.
206 DCHECK(!browser_context_->IsOffTheRecord()); 166 DCHECK(!browser_context_->IsOffTheRecord());
207 167
208 registrar_.Add(this, 168 registrar_.Add(this,
209 extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED, 169 extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED,
210 content::Source<BrowserContext>(context)); 170 content::Source<BrowserContext>(context));
211 extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_)); 171 extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_));
212 process_manager_observer_.Add(ProcessManager::Get(browser_context_)); 172 process_manager_observer_.Add(ProcessManager::Get(browser_context_));
213 173
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after
352 312
353 void RuntimeAPI::OpenURL(const GURL& update_url) { 313 void RuntimeAPI::OpenURL(const GURL& update_url) {
354 delegate_->OpenURL(update_url); 314 delegate_->OpenURL(update_url);
355 } 315 }
356 316
357 bool RuntimeAPI::GetPlatformInfo(runtime::PlatformInfo* info) { 317 bool RuntimeAPI::GetPlatformInfo(runtime::PlatformInfo* info) {
358 return delegate_->GetPlatformInfo(info); 318 return delegate_->GetPlatformInfo(info);
359 } 319 }
360 320
361 bool RuntimeAPI::RestartDevice(std::string* error_message) { 321 bool RuntimeAPI::RestartDevice(std::string* error_message) {
362 if (was_last_restart_due_to_delayed_restart_api_ &&
363 (ExtensionsBrowserClient::Get()->IsRunningInForcedAppMode() ||
364 allow_non_kiosk_apps_restart_api_for_test)) {
365 // We don't allow an app by calling chrome.runtime.restart() to clear the
366 // throttle enforced on it when calling chrome.runtime.restartAfterDelay(),
367 // i.e. the app can't unthrottle itself.
368 // When running in forced kiosk app mode, we assume the following restart
369 // request will succeed.
370 PrefService* pref_service =
371 ExtensionsBrowserClient::Get()->GetPrefServiceForContext(
372 browser_context_);
373 DCHECK(pref_service);
374 pref_service->SetBoolean(kPrefLastRestartWasDueToDelayedRestartApi, true);
375 }
376 return delegate_->RestartDevice(error_message); 322 return delegate_->RestartDevice(error_message);
377 } 323 }
378 324
379 RuntimeAPI::RestartAfterDelayStatus RuntimeAPI::RestartDeviceAfterDelay(
380 const std::string& extension_id,
381 int seconds_from_now) {
382 // To achieve as much accuracy as possible, record the time of the call as
383 // |now| here.
384 const base::Time now = base::Time::NowFromSystemTime();
385
386 if (schedule_restart_first_extension_id_.empty()) {
387 schedule_restart_first_extension_id_ = extension_id;
388 } else if (extension_id != schedule_restart_first_extension_id_) {
389 // We only allow the first extension to call this API to call it repeatedly.
390 // Any other extension will fail.
391 return RestartAfterDelayStatus::FAILED_NOT_FIRST_EXTENSION;
392 }
393
394 MaybeCancelRunningDelayedRestartTimer();
395
396 if (seconds_from_now == -1) {
397 // We already stopped the running timer (if any).
398 return RestartAfterDelayStatus::SUCCESS_RESTART_CANCELED;
399 }
400
401 if (!did_read_delayed_restart_preferences_) {
402 // Try to read any previous successful restart attempt time resulting from
403 // this API.
404 PrefService* pref_service =
405 ExtensionsBrowserClient::Get()->GetPrefServiceForContext(
406 browser_context_);
407 DCHECK(pref_service);
408
409 was_last_restart_due_to_delayed_restart_api_ =
410 pref_service->GetBoolean(kPrefLastRestartWasDueToDelayedRestartApi);
411 if (was_last_restart_due_to_delayed_restart_api_) {
412 // We clear this bit if the previous restart was due to this API, so that
413 // we don't throttle restart requests coming after other restarts or
414 // shutdowns not caused by the runtime API.
415 pref_service->SetBoolean(kPrefLastRestartWasDueToDelayedRestartApi,
416 false);
417 }
418
419 last_delayed_restart_time_ = base::Time::FromDoubleT(
420 pref_service->GetDouble(kPrefLastRestartAfterDelayTime));
421
422 if (!allow_non_kiosk_apps_restart_api_for_test) {
423 // Don't read every time unless in tests.
424 did_read_delayed_restart_preferences_ = true;
425 }
426 }
427
428 return ScheduleDelayedRestart(now, seconds_from_now);
429 }
430
431 bool RuntimeAPI::OpenOptionsPage(const Extension* extension) { 325 bool RuntimeAPI::OpenOptionsPage(const Extension* extension) {
432 return delegate_->OpenOptionsPage(extension); 326 return delegate_->OpenOptionsPage(extension);
433 } 327 }
434 328
435 void RuntimeAPI::MaybeCancelRunningDelayedRestartTimer() {
436 if (restart_after_delay_timer_.IsRunning())
437 restart_after_delay_timer_.Stop();
438 }
439
440 RuntimeAPI::RestartAfterDelayStatus RuntimeAPI::ScheduleDelayedRestart(
441 const base::Time& now,
442 int seconds_from_now) {
443 base::TimeDelta delay_till_restart =
444 base::TimeDelta::FromSeconds(seconds_from_now);
445
446 // Throttle restart requests that are received too soon successively, only if
447 // the previous restart was due to this API.
448 bool was_throttled = false;
449 if (was_last_restart_due_to_delayed_restart_api_) {
450 base::Time future_restart_time = now + delay_till_restart;
451 base::TimeDelta delta_since_last_restart =
452 future_restart_time > last_delayed_restart_time_
453 ? future_restart_time - last_delayed_restart_time_
454 : base::TimeDelta::Max();
455 if (delta_since_last_restart < minimum_duration_between_restarts_) {
456 // Schedule the restart after |minimum_duration_between_restarts_| has
457 // passed.
458 delay_till_restart = minimum_duration_between_restarts_ -
459 (now - last_delayed_restart_time_);
460 was_throttled = true;
461 }
462 }
463
464 restart_after_delay_timer_.Start(
465 FROM_HERE, delay_till_restart,
466 base::Bind(&RuntimeAPI::OnDelayedRestartTimerTimeout,
467 weak_ptr_factory_.GetWeakPtr()));
468
469 return was_throttled ? RestartAfterDelayStatus::FAILED_THROTTLED
470 : RestartAfterDelayStatus::SUCCESS_RESTART_SCHEDULED;
471 }
472
473 void RuntimeAPI::OnDelayedRestartTimerTimeout() {
474 // We can persist "now" as the last successful restart time, assuming that the
475 // following restart request will succeed, since it can only fail if requested
476 // by non kiosk apps, and we prevent that from the beginning (unless in
477 // unit tests).
478 // This assumption is important, since once restart is requested, we might not
479 // have enough time to persist the data to disk.
480 double now = base::Time::NowFromSystemTime().ToDoubleT();
481 PrefService* pref_service =
482 ExtensionsBrowserClient::Get()->GetPrefServiceForContext(
483 browser_context_);
484 DCHECK(pref_service);
485 pref_service->SetDouble(kPrefLastRestartAfterDelayTime, now);
486 pref_service->SetBoolean(kPrefLastRestartWasDueToDelayedRestartApi, true);
487
488 std::string error_message;
489 const bool success = delegate_->RestartDevice(&error_message);
490
491 // Make sure our above assumption is maintained.
492 DCHECK(success || allow_non_kiosk_apps_restart_api_for_test);
493 }
494
495 void RuntimeAPI::AllowNonKioskAppsInRestartAfterDelayForTesting() {
496 allow_non_kiosk_apps_restart_api_for_test = true;
497 }
498
499 /////////////////////////////////////////////////////////////////////////////// 329 ///////////////////////////////////////////////////////////////////////////////
500 330
501 // static 331 // static
502 void RuntimeEventRouter::DispatchOnStartupEvent( 332 void RuntimeEventRouter::DispatchOnStartupEvent(
503 content::BrowserContext* context, 333 content::BrowserContext* context,
504 const std::string& extension_id) { 334 const std::string& extension_id) {
505 DispatchOnStartupEventImpl(context, extension_id, true, NULL); 335 DispatchOnStartupEventImpl(context, extension_id, true, NULL);
506 } 336 }
507 337
508 // static 338 // static
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after
716 std::string message; 546 std::string message;
717 bool result = 547 bool result =
718 RuntimeAPI::GetFactoryInstance()->Get(browser_context())->RestartDevice( 548 RuntimeAPI::GetFactoryInstance()->Get(browser_context())->RestartDevice(
719 &message); 549 &message);
720 if (!result) { 550 if (!result) {
721 return RespondNow(Error(message)); 551 return RespondNow(Error(message));
722 } 552 }
723 return RespondNow(NoArguments()); 553 return RespondNow(NoArguments());
724 } 554 }
725 555
726 ExtensionFunction::ResponseAction RuntimeRestartAfterDelayFunction::Run() {
727 if (!allow_non_kiosk_apps_restart_api_for_test &&
728 !ExtensionsBrowserClient::Get()->IsRunningInForcedAppMode()) {
729 return RespondNow(Error(kErrorOnlyKioskModeAllowed));
730 }
731
732 std::unique_ptr<api::runtime::RestartAfterDelay::Params> params(
733 api::runtime::RestartAfterDelay::Params::Create(*args_));
734 EXTENSION_FUNCTION_VALIDATE(params.get());
735 int seconds = params->seconds;
736
737 if (seconds <= 0 && seconds != -1)
738 return RespondNow(Error(kErrorInvalidArgument, base::IntToString(seconds)));
739
740 RuntimeAPI::RestartAfterDelayStatus request_status =
741 RuntimeAPI::GetFactoryInstance()
742 ->Get(browser_context())
743 ->RestartDeviceAfterDelay(extension()->id(), seconds);
744
745 switch (request_status) {
746 case RuntimeAPI::RestartAfterDelayStatus::FAILED_NOT_FIRST_EXTENSION:
747 return RespondNow(Error(kErrorOnlyFirstExtensionAllowed));
748
749 case RuntimeAPI::RestartAfterDelayStatus::FAILED_THROTTLED:
750 return RespondNow(Error(kErrorRequestedTooSoon));
751
752 case RuntimeAPI::RestartAfterDelayStatus::SUCCESS_RESTART_CANCELED:
753 case RuntimeAPI::RestartAfterDelayStatus::SUCCESS_RESTART_SCHEDULED:
754 return RespondNow(NoArguments());
755 }
756
757 NOTREACHED();
758 return RespondNow(Error(kErrorInvalidStatus));
759 }
760
761 ExtensionFunction::ResponseAction RuntimeGetPlatformInfoFunction::Run() { 556 ExtensionFunction::ResponseAction RuntimeGetPlatformInfoFunction::Run() {
762 runtime::PlatformInfo info; 557 runtime::PlatformInfo info;
763 if (!RuntimeAPI::GetFactoryInstance() 558 if (!RuntimeAPI::GetFactoryInstance()
764 ->Get(browser_context()) 559 ->Get(browser_context())
765 ->GetPlatformInfo(&info)) { 560 ->GetPlatformInfo(&info)) {
766 return RespondNow(Error(kPlatformInfoUnavailable)); 561 return RespondNow(Error(kPlatformInfoUnavailable));
767 } 562 }
768 return RespondNow( 563 return RespondNow(
769 ArgumentList(runtime::GetPlatformInfo::Results::Create(info))); 564 ArgumentList(runtime::GetPlatformInfo::Results::Create(info)));
770 } 565 }
(...skipping 13 matching lines...) Expand all
784 content::ChildProcessSecurityPolicy* policy = 579 content::ChildProcessSecurityPolicy* policy =
785 content::ChildProcessSecurityPolicy::GetInstance(); 580 content::ChildProcessSecurityPolicy::GetInstance();
786 policy->GrantReadFileSystem(renderer_id, filesystem_id); 581 policy->GrantReadFileSystem(renderer_id, filesystem_id);
787 std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); 582 std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
788 dict->SetString("fileSystemId", filesystem_id); 583 dict->SetString("fileSystemId", filesystem_id);
789 dict->SetString("baseName", relative_path); 584 dict->SetString("baseName", relative_path);
790 return RespondNow(OneArgument(std::move(dict))); 585 return RespondNow(OneArgument(std::move(dict)));
791 } 586 }
792 587
793 } // namespace extensions 588 } // namespace extensions
OLDNEW
« no previous file with comments | « extensions/browser/api/runtime/runtime_api.h ('k') | extensions/browser/extension_function_histogram_value.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698