Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / chromeos / customization_document.cc
blobf61cc8655bc738e42d2419573a8f2014c579891f
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.
5 #include "chrome/browser/chromeos/customization_document.h"
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/file_util.h"
10 #include "base/files/file_path.h"
11 #include "base/json/json_reader.h"
12 #include "base/logging.h"
13 #include "base/prefs/pref_registry_simple.h"
14 #include "base/prefs/pref_service.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/time/time.h"
18 #include "chrome/browser/browser_process.h"
19 #include "chrome/browser/chromeos/login/wizard_controller.h"
20 #include "chromeos/network/network_state.h"
21 #include "chromeos/network/network_state_handler.h"
22 #include "chromeos/system/statistics_provider.h"
23 #include "content/public/browser/browser_thread.h"
24 #include "net/url_request/url_fetcher.h"
26 using content::BrowserThread;
28 // Manifest attributes names.
30 namespace {
32 const char kVersionAttr[] = "version";
33 const char kDefaultAttr[] = "default";
34 const char kInitialLocaleAttr[] = "initial_locale";
35 const char kInitialTimezoneAttr[] = "initial_timezone";
36 const char kKeyboardLayoutAttr[] = "keyboard_layout";
37 const char kRegistrationUrlAttr[] = "registration_url";
38 const char kHwidMapAttr[] = "hwid_map";
39 const char kHwidMaskAttr[] = "hwid_mask";
40 const char kSetupContentAttr[] = "setup_content";
41 const char kHelpPageAttr[] = "help_page";
42 const char kEulaPageAttr[] = "eula_page";
43 const char kAppContentAttr[] = "app_content";
44 const char kInitialStartPageAttr[] = "initial_start_page";
45 const char kSupportPageAttr[] = "support_page";
47 const char kAcceptedManifestVersion[] = "1.0";
49 // Path to OEM partner startup customization manifest.
50 const char kStartupCustomizationManifestPath[] =
51 "/opt/oem/etc/startup_manifest.json";
53 // URL where to fetch OEM services customization manifest from.
54 const char kServicesCustomizationManifestUrl[] =
55 "file:///opt/oem/etc/services_manifest.json";
57 // Name of local state option that tracks if services customization has been
58 // applied.
59 const char kServicesCustomizationAppliedPref[] = "ServicesCustomizationApplied";
61 // Maximum number of retries to fetch file if network is not available.
62 const int kMaxFetchRetries = 3;
64 // Delay between file fetch retries if network is not available.
65 const int kRetriesDelayInSec = 2;
67 } // anonymous namespace
69 namespace chromeos {
71 // CustomizationDocument implementation. ---------------------------------------
73 CustomizationDocument::CustomizationDocument(
74 const std::string& accepted_version)
75 : accepted_version_(accepted_version) {}
77 CustomizationDocument::~CustomizationDocument() {}
79 bool CustomizationDocument::LoadManifestFromFile(
80 const base::FilePath& manifest_path) {
81 std::string manifest;
82 if (!base::ReadFileToString(manifest_path, &manifest))
83 return false;
84 return LoadManifestFromString(manifest);
87 bool CustomizationDocument::LoadManifestFromString(
88 const std::string& manifest) {
89 int error_code = 0;
90 std::string error;
91 scoped_ptr<base::Value> root(base::JSONReader::ReadAndReturnError(manifest,
92 base::JSON_ALLOW_TRAILING_COMMAS, &error_code, &error));
93 if (error_code != base::JSONReader::JSON_NO_ERROR)
94 LOG(ERROR) << error;
95 DCHECK(root.get() != NULL);
96 if (root.get() == NULL)
97 return false;
98 DCHECK(root->GetType() == base::Value::TYPE_DICTIONARY);
99 if (root->GetType() == base::Value::TYPE_DICTIONARY) {
100 root_.reset(static_cast<base::DictionaryValue*>(root.release()));
101 std::string result;
102 if (root_->GetString(kVersionAttr, &result) &&
103 result == accepted_version_)
104 return true;
106 LOG(ERROR) << "Wrong customization manifest version";
107 root_.reset(NULL);
109 return false;
112 std::string CustomizationDocument::GetLocaleSpecificString(
113 const std::string& locale,
114 const std::string& dictionary_name,
115 const std::string& entry_name) const {
116 base::DictionaryValue* dictionary_content = NULL;
117 if (!root_.get() ||
118 !root_->GetDictionary(dictionary_name, &dictionary_content))
119 return std::string();
121 base::DictionaryValue* locale_dictionary = NULL;
122 if (dictionary_content->GetDictionary(locale, &locale_dictionary)) {
123 std::string result;
124 if (locale_dictionary->GetString(entry_name, &result))
125 return result;
128 base::DictionaryValue* default_dictionary = NULL;
129 if (dictionary_content->GetDictionary(kDefaultAttr, &default_dictionary)) {
130 std::string result;
131 if (default_dictionary->GetString(entry_name, &result))
132 return result;
135 return std::string();
138 // StartupCustomizationDocument implementation. --------------------------------
140 StartupCustomizationDocument::StartupCustomizationDocument()
141 : CustomizationDocument(kAcceptedManifestVersion) {
143 // Loading manifest causes us to do blocking IO on UI thread.
144 // Temporarily allow it until we fix http://crosbug.com/11103
145 base::ThreadRestrictions::ScopedAllowIO allow_io;
146 LoadManifestFromFile(base::FilePath(kStartupCustomizationManifestPath));
148 Init(chromeos::system::StatisticsProvider::GetInstance());
151 StartupCustomizationDocument::StartupCustomizationDocument(
152 chromeos::system::StatisticsProvider* statistics_provider,
153 const std::string& manifest)
154 : CustomizationDocument(kAcceptedManifestVersion) {
155 LoadManifestFromString(manifest);
156 Init(statistics_provider);
159 StartupCustomizationDocument::~StartupCustomizationDocument() {}
161 StartupCustomizationDocument* StartupCustomizationDocument::GetInstance() {
162 return Singleton<StartupCustomizationDocument,
163 DefaultSingletonTraits<StartupCustomizationDocument> >::get();
166 void StartupCustomizationDocument::Init(
167 chromeos::system::StatisticsProvider* statistics_provider) {
168 if (IsReady()) {
169 root_->GetString(kInitialLocaleAttr, &initial_locale_);
170 root_->GetString(kInitialTimezoneAttr, &initial_timezone_);
171 root_->GetString(kKeyboardLayoutAttr, &keyboard_layout_);
172 root_->GetString(kRegistrationUrlAttr, &registration_url_);
174 std::string hwid;
175 if (statistics_provider->GetMachineStatistic(
176 chromeos::system::kHardwareClassKey, &hwid)) {
177 base::ListValue* hwid_list = NULL;
178 if (root_->GetList(kHwidMapAttr, &hwid_list)) {
179 for (size_t i = 0; i < hwid_list->GetSize(); ++i) {
180 base::DictionaryValue* hwid_dictionary = NULL;
181 std::string hwid_mask;
182 if (hwid_list->GetDictionary(i, &hwid_dictionary) &&
183 hwid_dictionary->GetString(kHwidMaskAttr, &hwid_mask)) {
184 if (MatchPattern(hwid, hwid_mask)) {
185 // If HWID for this machine matches some mask, use HWID specific
186 // settings.
187 std::string result;
188 if (hwid_dictionary->GetString(kInitialLocaleAttr, &result))
189 initial_locale_ = result;
191 if (hwid_dictionary->GetString(kInitialTimezoneAttr, &result))
192 initial_timezone_ = result;
194 if (hwid_dictionary->GetString(kKeyboardLayoutAttr, &result))
195 keyboard_layout_ = result;
197 // Don't break here to allow other entires to be applied if match.
198 } else {
199 LOG(ERROR) << "Syntax error in customization manifest";
203 } else {
204 LOG(ERROR) << "HWID is missing in machine statistics";
208 // If manifest doesn't exist still apply values from VPD.
209 statistics_provider->GetMachineStatistic(kInitialLocaleAttr,
210 &initial_locale_);
211 statistics_provider->GetMachineStatistic(kInitialTimezoneAttr,
212 &initial_timezone_);
213 statistics_provider->GetMachineStatistic(kKeyboardLayoutAttr,
214 &keyboard_layout_);
217 std::string StartupCustomizationDocument::GetHelpPage(
218 const std::string& locale) const {
219 return GetLocaleSpecificString(locale, kSetupContentAttr, kHelpPageAttr);
222 std::string StartupCustomizationDocument::GetEULAPage(
223 const std::string& locale) const {
224 return GetLocaleSpecificString(locale, kSetupContentAttr, kEulaPageAttr);
227 // ServicesCustomizationDocument implementation. -------------------------------
229 ServicesCustomizationDocument::ServicesCustomizationDocument()
230 : CustomizationDocument(kAcceptedManifestVersion),
231 url_(kServicesCustomizationManifestUrl) {
234 ServicesCustomizationDocument::ServicesCustomizationDocument(
235 const std::string& manifest)
236 : CustomizationDocument(kAcceptedManifestVersion) {
237 LoadManifestFromString(manifest);
240 ServicesCustomizationDocument::~ServicesCustomizationDocument() {}
242 // static
243 ServicesCustomizationDocument* ServicesCustomizationDocument::GetInstance() {
244 return Singleton<ServicesCustomizationDocument,
245 DefaultSingletonTraits<ServicesCustomizationDocument> >::get();
248 // static
249 void ServicesCustomizationDocument::RegisterPrefs(
250 PrefRegistrySimple* registry) {
251 registry->RegisterBooleanPref(kServicesCustomizationAppliedPref, false);
254 // static
255 bool ServicesCustomizationDocument::WasApplied() {
256 PrefService* prefs = g_browser_process->local_state();
257 return prefs->GetBoolean(kServicesCustomizationAppliedPref);
260 // static
261 void ServicesCustomizationDocument::SetApplied(bool val) {
262 PrefService* prefs = g_browser_process->local_state();
263 prefs->SetBoolean(kServicesCustomizationAppliedPref, val);
266 void ServicesCustomizationDocument::StartFetching() {
267 if (url_.SchemeIsFile()) {
268 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
269 base::Bind(&ServicesCustomizationDocument::ReadFileInBackground,
270 base::Unretained(this), // this class is a singleton.
271 base::FilePath(url_.path())));
272 } else {
273 StartFileFetch();
277 void ServicesCustomizationDocument::ReadFileInBackground(
278 const base::FilePath& file) {
279 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
281 std::string manifest;
282 if (base::ReadFileToString(file, &manifest)) {
283 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
284 base::Bind(
285 base::IgnoreResult(
286 &ServicesCustomizationDocument::LoadManifestFromString),
287 base::Unretained(this), // this class is a singleton.
288 manifest));
289 } else {
290 VLOG(1) << "Failed to load services customization manifest from: "
291 << file.value();
295 void ServicesCustomizationDocument::StartFileFetch() {
296 DCHECK(url_.is_valid());
297 url_fetcher_.reset(net::URLFetcher::Create(
298 url_, net::URLFetcher::GET, this));
299 url_fetcher_->SetRequestContext(g_browser_process->system_request_context());
300 url_fetcher_->Start();
303 void ServicesCustomizationDocument::OnURLFetchComplete(
304 const net::URLFetcher* source) {
305 if (source->GetResponseCode() == 200) {
306 std::string data;
307 source->GetResponseAsString(&data);
308 LoadManifestFromString(data);
309 } else {
310 const NetworkState* default_network =
311 NetworkHandler::Get()->network_state_handler()->DefaultNetwork();
312 if (default_network && default_network->IsConnectedState() &&
313 num_retries_ < kMaxFetchRetries) {
314 num_retries_++;
315 retry_timer_.Start(FROM_HERE,
316 base::TimeDelta::FromSeconds(kRetriesDelayInSec),
317 this, &ServicesCustomizationDocument::StartFileFetch);
318 return;
320 LOG(ERROR) << "URL fetch for services customization failed:"
321 << " response code = " << source->GetResponseCode()
322 << " URL = " << source->GetURL().spec();
326 bool ServicesCustomizationDocument::ApplyCustomization() {
327 // TODO(dpolukhin): apply customized apps, exts and support page.
328 SetApplied(true);
329 return true;
332 std::string ServicesCustomizationDocument::GetInitialStartPage(
333 const std::string& locale) const {
334 return GetLocaleSpecificString(
335 locale, kAppContentAttr, kInitialStartPageAttr);
338 std::string ServicesCustomizationDocument::GetSupportPage(
339 const std::string& locale) const {
340 return GetLocaleSpecificString(
341 locale, kAppContentAttr, kSupportPageAttr);
344 } // namespace chromeos