1 // Copyright (c) 2012 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 #include "chrome/browser/ui/webui/help/help_handler.h" 6 7 #include <string> 8 9 #include "base/basictypes.h" 10 #include "base/bind.h" 11 #include "base/bind_helpers.h" 12 #include "base/command_line.h" 13 #include "base/strings/string16.h" 14 #include "base/strings/utf_string_conversions.h" 15 #include "base/values.h" 16 #include "chrome/browser/browser_process.h" 17 #include "chrome/browser/chrome_notification_types.h" 18 #include "chrome/browser/google/google_util.h" 19 #include "chrome/browser/policy/browser_policy_connector.h" 20 #include "chrome/browser/ui/browser.h" 21 #include "chrome/browser/ui/browser_commands.h" 22 #include "chrome/browser/ui/browser_finder.h" 23 #include "chrome/browser/ui/chrome_pages.h" 24 #include "chrome/browser/ui/send_feedback_experiment.h" 25 #include "chrome/common/chrome_version_info.h" 26 #include "chrome/common/pref_names.h" 27 #include "chrome/common/url_constants.h" 28 #include "content/public/browser/browser_thread.h" 29 #include "content/public/browser/notification_service.h" 30 #include "content/public/browser/web_ui.h" 31 #include "content/public/browser/web_ui_data_source.h" 32 #include "content/public/common/content_client.h" 33 #include "grit/chromium_strings.h" 34 #include "grit/generated_resources.h" 35 #include "grit/google_chrome_strings.h" 36 #include "ui/base/l10n/l10n_util.h" 37 #include "ui/base/resource/resource_bundle.h" 38 #include "v8/include/v8.h" 39 #include "webkit/common/user_agent/user_agent_util.h" 40 41 #if defined(OS_CHROMEOS) 42 #include "base/files/file_util_proxy.h" 43 #include "base/i18n/time_formatting.h" 44 #include "base/prefs/pref_service.h" 45 #include "base/sys_info.h" 46 #include "chrome/browser/chromeos/login/user_manager.h" 47 #include "chrome/browser/chromeos/settings/cros_settings.h" 48 #include "chrome/browser/profiles/profile.h" 49 #include "chrome/browser/ui/webui/help/help_utils_chromeos.h" 50 #include "chromeos/chromeos_switches.h" 51 #include "chromeos/dbus/dbus_thread_manager.h" 52 #include "chromeos/dbus/power_manager_client.h" 53 #include "content/public/browser/browser_thread.h" 54 #endif 55 56 using base::ListValue; 57 using content::BrowserThread; 58 59 namespace { 60 61 const char kResourceReportIssue[] = "reportAnIssue"; 62 63 // Returns the browser version as a string. 64 string16 BuildBrowserVersionString() { 65 chrome::VersionInfo version_info; 66 DCHECK(version_info.is_valid()); 67 68 std::string browser_version = version_info.Version(); 69 std::string version_modifier = 70 chrome::VersionInfo::GetVersionStringModifier(); 71 if (!version_modifier.empty()) 72 browser_version += " " + version_modifier; 73 74 #if !defined(GOOGLE_CHROME_BUILD) 75 browser_version += " ("; 76 browser_version += version_info.LastChange(); 77 browser_version += ")"; 78 #endif 79 80 return UTF8ToUTF16(browser_version); 81 } 82 83 #if defined(OS_CHROMEOS) 84 85 // Returns message that informs user that for update it's better to 86 // connect to a network of one of the allowed types. 87 string16 GetAllowedConnectionTypesMessage() { 88 if (help_utils_chromeos::IsUpdateOverCellularAllowed()) { 89 return l10n_util::GetStringUTF16(IDS_UPGRADE_NETWORK_LIST_CELLULAR_ALLOWED); 90 } else { 91 return l10n_util::GetStringUTF16( 92 IDS_UPGRADE_NETWORK_LIST_CELLULAR_DISALLOWED); 93 } 94 } 95 96 // Returns true if the device is enterprise managed, false otherwise. 97 bool IsEnterpriseManaged() { 98 return g_browser_process->browser_policy_connector()->IsEnterpriseManaged(); 99 } 100 101 // Returns true if current user can change channel, false otherwise. 102 bool CanChangeChannel() { 103 bool value = false; 104 chromeos::CrosSettings::Get()->GetBoolean(chromeos::kReleaseChannelDelegated, 105 &value); 106 107 // On a managed machine we delegate this setting to the users of the same 108 // domain only if the policy value is "domain". 109 if (IsEnterpriseManaged()) { 110 if (!value) 111 return false; 112 // Get the currently logged in user and strip the domain part only. 113 std::string domain = ""; 114 std::string user = chromeos::UserManager::Get()->GetLoggedInUser()->email(); 115 size_t at_pos = user.find('@'); 116 if (at_pos != std::string::npos && at_pos + 1 < user.length()) 117 domain = user.substr(user.find('@') + 1); 118 return domain == g_browser_process->browser_policy_connector()-> 119 GetEnterpriseDomain(); 120 } else if (chromeos::UserManager::Get()->IsCurrentUserOwner()) { 121 // On non managed machines we have local owner who is the only one to change 122 // anything. Ensure that ReleaseChannelDelegated is false. 123 return !value; 124 } 125 return false; 126 } 127 128 // Pointer to a |StringValue| holding the date of the build date to Chromium 129 // OS. Because this value is obtained by reading a file, it is cached here to 130 // prevent the need to read from the file system multiple times unnecessarily. 131 Value* g_build_date_string = NULL; 132 133 #endif // defined(OS_CHROMEOS) 134 135 } // namespace 136 137 HelpHandler::HelpHandler() 138 : version_updater_(VersionUpdater::Create()), 139 weak_factory_(this) { 140 } 141 142 HelpHandler::~HelpHandler() { 143 } 144 145 void HelpHandler::GetLocalizedValues(content::WebUIDataSource* source) { 146 struct L10nResources { 147 const char* name; 148 int ids; 149 }; 150 151 static L10nResources resources[] = { 152 { "helpTitle", IDS_HELP_TITLE }, 153 { "aboutTitle", IDS_ABOUT_TAB_TITLE }, 154 #if defined(OS_CHROMEOS) 155 { "aboutProductTitle", IDS_PRODUCT_OS_NAME }, 156 #else 157 { "aboutProductTitle", IDS_PRODUCT_NAME }, 158 #endif 159 { "aboutProductDescription", IDS_ABOUT_PRODUCT_DESCRIPTION }, 160 { "relaunch", IDS_RELAUNCH_BUTTON }, 161 { "relaunch", IDS_RELAUNCH_BUTTON }, 162 #if defined(OS_CHROMEOS) 163 { "relaunchAndPowerwash", IDS_RELAUNCH_AND_POWERWASH_BUTTON }, 164 #endif 165 { "productName", IDS_PRODUCT_NAME }, 166 { "productCopyright", IDS_ABOUT_VERSION_COPYRIGHT }, 167 { "updateCheckStarted", IDS_UPGRADE_CHECK_STARTED }, 168 { "upToDate", IDS_UPGRADE_UP_TO_DATE }, 169 { "updating", IDS_UPGRADE_UPDATING }, 170 #if defined(OS_CHROMEOS) 171 { "updatingChannelSwitch", IDS_UPGRADE_UPDATING_CHANNEL_SWITCH }, 172 #endif 173 { "updateAlmostDone", IDS_UPGRADE_SUCCESSFUL_RELAUNCH }, 174 #if defined(OS_CHROMEOS) 175 { "successfulChannelSwitch", IDS_UPGRADE_SUCCESSFUL_CHANNEL_SWITCH }, 176 #endif 177 { "getHelpWithChrome", IDS_GET_HELP_USING_CHROME }, 178 { kResourceReportIssue, IDS_REPORT_AN_ISSUE }, 179 #if defined(OS_CHROMEOS) 180 { "platform", IDS_PLATFORM_LABEL }, 181 { "firmware", IDS_ABOUT_PAGE_FIRMWARE }, 182 { "showMoreInfo", IDS_SHOW_MORE_INFO }, 183 { "hideMoreInfo", IDS_HIDE_MORE_INFO }, 184 { "channel", IDS_ABOUT_PAGE_CHANNEL }, 185 { "stable", IDS_ABOUT_PAGE_CHANNEL_STABLE }, 186 { "beta", IDS_ABOUT_PAGE_CHANNEL_BETA }, 187 { "dev", IDS_ABOUT_PAGE_CHANNEL_DEVELOPMENT }, 188 { "channel-changed", IDS_ABOUT_PAGE_CHANNEL_CHANGED }, 189 { "currentChannelStable", IDS_ABOUT_PAGE_CURRENT_CHANNEL_STABLE }, 190 { "currentChannelBeta", IDS_ABOUT_PAGE_CURRENT_CHANNEL_BETA }, 191 { "currentChannelDev", IDS_ABOUT_PAGE_CURRENT_CHANNEL_DEV }, 192 { "currentChannel", IDS_ABOUT_PAGE_CURRENT_CHANNEL }, 193 { "channelChangeButton", IDS_ABOUT_PAGE_CHANNEL_CHANGE_BUTTON }, 194 { "channelChangeDisallowedMessage", 195 IDS_ABOUT_PAGE_CHANNEL_CHANGE_DISALLOWED_MESSAGE }, 196 { "channelChangePageTitle", IDS_ABOUT_PAGE_CHANNEL_CHANGE_PAGE_TITLE }, 197 { "channelChangePagePowerwashTitle", 198 IDS_ABOUT_PAGE_CHANNEL_CHANGE_PAGE_POWERWASH_TITLE }, 199 { "channelChangePagePowerwashMessage", 200 IDS_ABOUT_PAGE_CHANNEL_CHANGE_PAGE_POWERWASH_MESSAGE }, 201 { "channelChangePageDelayedChangeTitle", 202 IDS_ABOUT_PAGE_CHANNEL_CHANGE_PAGE_DELAYED_CHANGE_TITLE }, 203 { "channelChangePageUnstableTitle", 204 IDS_ABOUT_PAGE_CHANNEL_CHANGE_PAGE_UNSTABLE_TITLE }, 205 { "channelChangePagePowerwashButton", 206 IDS_ABOUT_PAGE_CHANNEL_CHANGE_PAGE_POWERWASH_BUTTON }, 207 { "channelChangePageChangeButton", 208 IDS_ABOUT_PAGE_CHANNEL_CHANGE_PAGE_CHANGE_BUTTON }, 209 { "channelChangePageCancelButton", 210 IDS_ABOUT_PAGE_CHANNEL_CHANGE_PAGE_CANCEL_BUTTON }, 211 { "webkit", IDS_WEBKIT }, 212 { "userAgent", IDS_ABOUT_VERSION_USER_AGENT }, 213 { "commandLine", IDS_ABOUT_VERSION_COMMAND_LINE }, 214 { "buildDate", IDS_ABOUT_VERSION_BUILD_DATE }, 215 #endif 216 #if defined(OS_MACOSX) 217 { "promote", IDS_ABOUT_CHROME_PROMOTE_UPDATER }, 218 { "learnMore", IDS_LEARN_MORE }, 219 #endif 220 }; 221 222 if (chrome::UseAlternateSendFeedbackText()) { 223 // Field trial to substitute "Report an Issue" with "Send Feedback". 224 // (crbug.com/169339) 225 std::string report_issue_key(kResourceReportIssue); 226 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(resources); ++i) { 227 if (report_issue_key == resources[i].name) 228 resources[i].ids = IDS_SEND_FEEDBACK; 229 } 230 } 231 232 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(resources); ++i) { 233 source->AddString(resources[i].name, 234 l10n_util::GetStringUTF16(resources[i].ids)); 235 } 236 237 source->AddString( 238 "browserVersion", 239 l10n_util::GetStringFUTF16(IDS_ABOUT_PRODUCT_VERSION, 240 BuildBrowserVersionString())); 241 242 string16 license = l10n_util::GetStringFUTF16( 243 IDS_ABOUT_VERSION_LICENSE, 244 ASCIIToUTF16(chrome::kChromiumProjectURL), 245 ASCIIToUTF16(chrome::kChromeUICreditsURL)); 246 source->AddString("productLicense", license); 247 248 #if defined(OS_CHROMEOS) 249 string16 os_license = l10n_util::GetStringFUTF16( 250 IDS_ABOUT_CROS_VERSION_LICENSE, 251 ASCIIToUTF16(chrome::kChromeUIOSCreditsURL)); 252 source->AddString("productOsLicense", os_license); 253 254 string16 product_name = l10n_util::GetStringUTF16(IDS_PRODUCT_OS_NAME); 255 source->AddString( 256 "channelChangePageDelayedChangeMessage", 257 l10n_util::GetStringFUTF16( 258 IDS_ABOUT_PAGE_CHANNEL_CHANGE_PAGE_DELAYED_CHANGE_MESSAGE, 259 product_name)); 260 source->AddString( 261 "channelChangePageUnstableMessage", 262 l10n_util::GetStringFUTF16( 263 IDS_ABOUT_PAGE_CHANNEL_CHANGE_PAGE_UNSTABLE_MESSAGE, 264 product_name)); 265 266 if (CommandLine::ForCurrentProcess()-> 267 HasSwitch(chromeos::switches::kDisableNewChannelSwitcherUI)) { 268 source->AddBoolean("disableNewChannelSwitcherUI", true); 269 } 270 #endif 271 272 string16 tos = l10n_util::GetStringFUTF16( 273 IDS_ABOUT_TERMS_OF_SERVICE, UTF8ToUTF16(chrome::kChromeUITermsURL)); 274 source->AddString("productTOS", tos); 275 276 source->AddString("webkitVersion", webkit_glue::GetWebKitVersion()); 277 278 source->AddString("jsEngine", "V8"); 279 source->AddString("jsEngineVersion", v8::V8::GetVersion()); 280 281 source->AddString("userAgentInfo", content::GetUserAgent(GURL())); 282 283 CommandLine::StringType command_line = 284 CommandLine::ForCurrentProcess()->GetCommandLineString(); 285 source->AddString("commandLineInfo", command_line); 286 } 287 288 void HelpHandler::RegisterMessages() { 289 registrar_.Add(this, chrome::NOTIFICATION_UPGRADE_RECOMMENDED, 290 content::NotificationService::AllSources()); 291 292 web_ui()->RegisterMessageCallback("onPageLoaded", 293 base::Bind(&HelpHandler::OnPageLoaded, base::Unretained(this))); 294 web_ui()->RegisterMessageCallback("relaunchNow", 295 base::Bind(&HelpHandler::RelaunchNow, base::Unretained(this))); 296 web_ui()->RegisterMessageCallback("openFeedbackDialog", 297 base::Bind(&HelpHandler::OpenFeedbackDialog, base::Unretained(this))); 298 web_ui()->RegisterMessageCallback("openHelpPage", 299 base::Bind(&HelpHandler::OpenHelpPage, base::Unretained(this))); 300 #if defined(OS_CHROMEOS) 301 web_ui()->RegisterMessageCallback("setChannel", 302 base::Bind(&HelpHandler::SetChannel, base::Unretained(this))); 303 web_ui()->RegisterMessageCallback("relaunchAndPowerwash", 304 base::Bind(&HelpHandler::RelaunchAndPowerwash, base::Unretained(this))); 305 #endif 306 #if defined(OS_MACOSX) 307 web_ui()->RegisterMessageCallback("promoteUpdater", 308 base::Bind(&HelpHandler::PromoteUpdater, base::Unretained(this))); 309 #endif 310 } 311 312 void HelpHandler::Observe(int type, const content::NotificationSource& source, 313 const content::NotificationDetails& details) { 314 switch (type) { 315 case chrome::NOTIFICATION_UPGRADE_RECOMMENDED: { 316 // A version update is installed and ready to go. Refresh the UI so the 317 // correct state will be shown. 318 version_updater_->CheckForUpdate( 319 base::Bind(&HelpHandler::SetUpdateStatus, base::Unretained(this)) 320 #if defined(OS_MACOSX) 321 , base::Bind(&HelpHandler::SetPromotionState, base::Unretained(this)) 322 #endif 323 ); 324 break; 325 } 326 default: 327 NOTREACHED(); 328 } 329 } 330 331 void HelpHandler::OnPageLoaded(const ListValue* args) { 332 #if defined(OS_CHROMEOS) 333 // Version information is loaded from a callback 334 loader_.GetVersion( 335 chromeos::VersionLoader::VERSION_FULL, 336 base::Bind(&HelpHandler::OnOSVersion, base::Unretained(this)), 337 &tracker_); 338 loader_.GetFirmware( 339 base::Bind(&HelpHandler::OnOSFirmware, base::Unretained(this)), 340 &tracker_); 341 342 web_ui()->CallJavascriptFunction( 343 "help.HelpPage.updateEnableReleaseChannel", 344 base::FundamentalValue(CanChangeChannel())); 345 346 if (g_build_date_string == NULL) { 347 // If |g_build_date_string| is |NULL|, the date has not yet been assigned. 348 // Get the date of the last lsb-release file modification. 349 base::FileUtilProxy::GetFileInfo( 350 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE).get(), 351 base::SysInfo::GetLsbReleaseFilePath(), 352 base::Bind(&HelpHandler::ProcessLsbFileInfo, 353 weak_factory_.GetWeakPtr())); 354 } else { 355 web_ui()->CallJavascriptFunction("help.HelpPage.setBuildDate", 356 *g_build_date_string); 357 } 358 #endif // defined(OS_CHROMEOS) 359 360 version_updater_->CheckForUpdate( 361 base::Bind(&HelpHandler::SetUpdateStatus, base::Unretained(this)) 362 #if defined(OS_MACOSX) 363 , base::Bind(&HelpHandler::SetPromotionState, base::Unretained(this)) 364 #endif 365 ); 366 367 #if defined(OS_CHROMEOS) 368 web_ui()->CallJavascriptFunction( 369 "help.HelpPage.updateIsEnterpriseManaged", 370 base::FundamentalValue(IsEnterpriseManaged())); 371 // First argument to GetChannel() is a flag that indicates whether 372 // current channel should be returned (if true) or target channel 373 // (otherwise). 374 version_updater_->GetChannel(true, 375 base::Bind(&HelpHandler::OnCurrentChannel, weak_factory_.GetWeakPtr())); 376 version_updater_->GetChannel(false, 377 base::Bind(&HelpHandler::OnTargetChannel, weak_factory_.GetWeakPtr())); 378 #endif 379 } 380 381 #if defined(OS_MACOSX) 382 void HelpHandler::PromoteUpdater(const ListValue* args) { 383 version_updater_->PromoteUpdater(); 384 } 385 #endif 386 387 void HelpHandler::RelaunchNow(const ListValue* args) { 388 DCHECK(args->empty()); 389 version_updater_->RelaunchBrowser(); 390 } 391 392 void HelpHandler::OpenFeedbackDialog(const ListValue* args) { 393 DCHECK(args->empty()); 394 Browser* browser = chrome::FindBrowserWithWebContents( 395 web_ui()->GetWebContents()); 396 chrome::OpenFeedbackDialog(browser); 397 } 398 399 void HelpHandler::OpenHelpPage(const base::ListValue* args) { 400 DCHECK(args->empty()); 401 Browser* browser = chrome::FindBrowserWithWebContents( 402 web_ui()->GetWebContents()); 403 chrome::ShowHelp(browser, chrome::HELP_SOURCE_WEBUI); 404 } 405 406 #if defined(OS_CHROMEOS) 407 408 void HelpHandler::SetChannel(const ListValue* args) { 409 DCHECK(args->GetSize() == 2); 410 411 if (!CanChangeChannel()) { 412 LOG(WARNING) << "Non-owner tried to change release track."; 413 return; 414 } 415 416 base::string16 channel; 417 bool is_powerwash_allowed; 418 if (!args->GetString(0, &channel) || 419 !args->GetBoolean(1, &is_powerwash_allowed)) { 420 LOG(ERROR) << "Can't parse SetChannel() args"; 421 return; 422 } 423 424 version_updater_->SetChannel(UTF16ToUTF8(channel), is_powerwash_allowed); 425 if (chromeos::UserManager::Get()->IsCurrentUserOwner()) { 426 // Check for update after switching release channel. 427 version_updater_->CheckForUpdate(base::Bind(&HelpHandler::SetUpdateStatus, 428 base::Unretained(this))); 429 } 430 } 431 432 void HelpHandler::RelaunchAndPowerwash(const ListValue* args) { 433 DCHECK(args->empty()); 434 435 if (IsEnterpriseManaged()) 436 return; 437 438 PrefService* prefs = g_browser_process->local_state(); 439 prefs->SetBoolean(prefs::kFactoryResetRequested, true); 440 prefs->CommitPendingWrite(); 441 442 // Perform sign out. Current chrome process will then terminate, new one will 443 // be launched (as if it was a restart). 444 chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->RequestRestart(); 445 } 446 447 #endif // defined(OS_CHROMEOS) 448 449 void HelpHandler::SetUpdateStatus(VersionUpdater::Status status, 450 int progress, const string16& message) { 451 // Only UPDATING state should have progress set. 452 DCHECK(status == VersionUpdater::UPDATING || progress == 0); 453 454 std::string status_str; 455 switch (status) { 456 case VersionUpdater::CHECKING: 457 status_str = "checking"; 458 break; 459 case VersionUpdater::UPDATING: 460 status_str = "updating"; 461 break; 462 case VersionUpdater::NEARLY_UPDATED: 463 status_str = "nearly_updated"; 464 break; 465 case VersionUpdater::UPDATED: 466 status_str = "updated"; 467 break; 468 case VersionUpdater::FAILED: 469 case VersionUpdater::FAILED_OFFLINE: 470 case VersionUpdater::FAILED_CONNECTION_TYPE_DISALLOWED: 471 status_str = "failed"; 472 break; 473 case VersionUpdater::DISABLED: 474 status_str = "disabled"; 475 break; 476 } 477 478 web_ui()->CallJavascriptFunction("help.HelpPage.setUpdateStatus", 479 base::StringValue(status_str), 480 base::StringValue(message)); 481 482 if (status == VersionUpdater::UPDATING) { 483 web_ui()->CallJavascriptFunction("help.HelpPage.setProgress", 484 base::FundamentalValue(progress)); 485 } 486 487 #if defined(OS_CHROMEOS) 488 if (status == VersionUpdater::FAILED_OFFLINE || 489 status == VersionUpdater::FAILED_CONNECTION_TYPE_DISALLOWED) { 490 string16 types_msg = GetAllowedConnectionTypesMessage(); 491 if (!types_msg.empty()) { 492 web_ui()->CallJavascriptFunction( 493 "help.HelpPage.setAndShowAllowedConnectionTypesMsg", 494 base::StringValue(types_msg)); 495 } else { 496 web_ui()->CallJavascriptFunction( 497 "help.HelpPage.showAllowedConnectionTypesMsg", 498 base::FundamentalValue(false)); 499 } 500 } else { 501 web_ui()->CallJavascriptFunction( 502 "help.HelpPage.showAllowedConnectionTypesMsg", 503 base::FundamentalValue(false)); 504 } 505 #endif // defined(OS_CHROMEOS) 506 } 507 508 #if defined(OS_MACOSX) 509 void HelpHandler::SetPromotionState(VersionUpdater::PromotionState state) { 510 std::string state_str; 511 switch (state) { 512 case VersionUpdater::PROMOTE_HIDDEN: 513 state_str = "hidden"; 514 break; 515 case VersionUpdater::PROMOTE_ENABLED: 516 state_str = "enabled"; 517 break; 518 case VersionUpdater::PROMOTE_DISABLED: 519 state_str = "disabled"; 520 break; 521 } 522 523 web_ui()->CallJavascriptFunction("help.HelpPage.setPromotionState", 524 base::StringValue(state_str)); 525 } 526 #endif // defined(OS_MACOSX) 527 528 #if defined(OS_CHROMEOS) 529 void HelpHandler::OnOSVersion(const std::string& version) { 530 web_ui()->CallJavascriptFunction("help.HelpPage.setOSVersion", 531 base::StringValue(version)); 532 } 533 534 void HelpHandler::OnOSFirmware(const std::string& firmware) { 535 web_ui()->CallJavascriptFunction("help.HelpPage.setOSFirmware", 536 base::StringValue(firmware)); 537 } 538 539 void HelpHandler::OnCurrentChannel(const std::string& channel) { 540 web_ui()->CallJavascriptFunction( 541 "help.HelpPage.updateCurrentChannel", base::StringValue(channel)); 542 } 543 544 void HelpHandler::OnTargetChannel(const std::string& channel) { 545 web_ui()->CallJavascriptFunction( 546 "help.HelpPage.updateTargetChannel", base::StringValue(channel)); 547 } 548 549 void HelpHandler::ProcessLsbFileInfo( 550 base::PlatformFileError error, const base::PlatformFileInfo& file_info) { 551 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 552 553 // If |g_build_date_string| is not |NULL|, then the file's information has 554 // already been retrieved by another tab. 555 if (g_build_date_string == NULL) { 556 base::Time time; 557 if (error == base::PLATFORM_FILE_OK) { 558 // Retrieves the time at which the Chrome OS build was created. 559 // Each time a new build is created, /etc/lsb-release is modified with the 560 // new version numbers of the release. 561 time = file_info.last_modified; 562 } else { 563 // If the time of the build cannot be retrieved, return and do not 564 // display the "Build Date" section. 565 return; 566 } 567 568 // Note that this string will be internationalized. 569 string16 build_date = base::TimeFormatFriendlyDate(time); 570 g_build_date_string = Value::CreateStringValue(build_date); 571 } 572 573 web_ui()->CallJavascriptFunction("help.HelpPage.setBuildDate", 574 *g_build_date_string); 575 } 576 #endif // defined(OS_CHROMEOS) 577