OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 "chrome/browser/chromeos/customization_document.h" | 5 #include "chrome/browser/chromeos/customization_document.h" |
6 | 6 |
| 7 #include "base/file_path.h" |
7 #include "base/file_util.h" | 8 #include "base/file_util.h" |
8 #include "base/json/json_reader.h" | 9 #include "base/json/json_reader.h" |
9 #include "base/logging.h" | 10 #include "base/logging.h" |
10 #include "base/string_tokenizer.h" | 11 #include "base/string_tokenizer.h" |
11 #include "base/string_util.h" | 12 #include "base/string_util.h" |
| 13 #include "chrome/browser/browser_process.h" |
| 14 #include "chrome/browser/chromeos/cros/cros_library.h" |
| 15 #include "chrome/browser/chromeos/cros/network_library.h" |
| 16 #include "chrome/browser/chromeos/system_access.h" |
| 17 #include "chrome/browser/prefs/pref_service.h" |
| 18 #include "chrome/browser/profiles/profile_manager.h" |
| 19 #include "content/browser/browser_thread.h" |
12 | 20 |
13 // Manifest attributes names. | 21 // Manifest attributes names. |
14 | 22 |
15 namespace { | 23 namespace { |
16 | 24 |
17 const char kVersionAttr[] = "version"; | 25 const char kVersionAttr[] = "version"; |
18 const char kDefaultAttr[] = "default"; | 26 const char kDefaultAttr[] = "default"; |
19 const char kInitialLocaleAttr[] = "initial_locale"; | 27 const char kInitialLocaleAttr[] = "initial_locale"; |
20 const char kInitialTimezoneAttr[] = "initial_timezone"; | 28 const char kInitialTimezoneAttr[] = "initial_timezone"; |
21 const char kKeyboardLayoutAttr[] = "keyboard_layout"; | 29 const char kKeyboardLayoutAttr[] = "keyboard_layout"; |
22 const char kRegistrationUrlAttr[] = "registration_url"; | 30 const char kRegistrationUrlAttr[] = "registration_url"; |
23 const char kHwidMapAttr[] = "hwid_map"; | 31 const char kHwidMapAttr[] = "hwid_map"; |
24 const char kHwidMaskAttr[] = "hwid_mask"; | 32 const char kHwidMaskAttr[] = "hwid_mask"; |
25 const char kSetupContentAttr[] = "setup_content"; | 33 const char kSetupContentAttr[] = "setup_content"; |
26 const char kHelpPageAttr[] = "help_page"; | 34 const char kHelpPageAttr[] = "help_page"; |
27 const char kEulaPageAttr[] = "eula_page"; | 35 const char kEulaPageAttr[] = "eula_page"; |
28 const char kAppContentAttr[] = "app_content"; | 36 const char kAppContentAttr[] = "app_content"; |
29 const char kInitialStartPageAttr[] = "initial_start_page"; | 37 const char kInitialStartPageAttr[] = "initial_start_page"; |
30 const char kSupportPageAttr[] = "support_page"; | 38 const char kSupportPageAttr[] = "support_page"; |
31 | 39 |
32 const char kAcceptedManifestVersion[] = "1.0"; | 40 const char kAcceptedManifestVersion[] = "1.0"; |
33 | 41 |
34 const char kHWIDPath[] = "/sys/devices/platform/chromeos_acpi/HWID"; | 42 const char kHwid[] = "hwid"; |
35 const char kVPDPath[] = "/var/log/vpd_2.0.txt"; | 43 |
| 44 // Path to OEM partner startup customization manifest. |
| 45 const char kStartupCustomizationManifestPath[] = |
| 46 "/opt/oem/etc/startup_manifest.json"; |
| 47 |
| 48 // URL where to fetch OEM services customization manifest from. |
| 49 const char kServicesCustomizationManifestUrl[] = |
| 50 "file:///opt/oem/etc/services_manifest.json"; |
| 51 |
| 52 // Name of local state option that tracks if services customization has been |
| 53 // applied. |
| 54 const char kServicesCustomizationAppliedPref[] = "ServicesCustomizationApplied"; |
| 55 |
| 56 // Maximum number of retries to fetch file if network is not available. |
| 57 const int kMaxFetchRetries = 3; |
| 58 |
| 59 // Delay between file fetch retries if network is not available. |
| 60 const int kRetriesDelayInSec = 2; |
36 | 61 |
37 } // anonymous namespace | 62 } // anonymous namespace |
38 | 63 |
| 64 DISABLE_RUNNABLE_METHOD_REFCOUNT(chromeos::ServicesCustomizationDocument); |
| 65 |
39 namespace chromeos { | 66 namespace chromeos { |
40 | 67 |
41 // CustomizationDocument implementation. | 68 // CustomizationDocument implementation. --------------------------------------- |
| 69 |
42 bool CustomizationDocument::LoadManifestFromFile( | 70 bool CustomizationDocument::LoadManifestFromFile( |
43 const FilePath& manifest_path) { | 71 const FilePath& manifest_path) { |
44 std::string manifest; | 72 std::string manifest; |
45 if (!file_util::ReadFileToString(manifest_path, &manifest)) | 73 if (!file_util::ReadFileToString(manifest_path, &manifest)) |
46 return false; | 74 return false; |
47 return LoadManifestFromString(manifest); | 75 return LoadManifestFromString(manifest); |
48 } | 76 } |
49 | 77 |
50 bool CustomizationDocument::LoadManifestFromString( | 78 bool CustomizationDocument::LoadManifestFromString( |
51 const std::string& manifest) { | 79 const std::string& manifest) { |
(...skipping 13 matching lines...) Expand all Loading... |
65 root_.reset(NULL); | 93 root_.reset(NULL); |
66 } | 94 } |
67 return false; | 95 return false; |
68 } | 96 } |
69 | 97 |
70 std::string CustomizationDocument::GetLocaleSpecificString( | 98 std::string CustomizationDocument::GetLocaleSpecificString( |
71 const std::string& locale, | 99 const std::string& locale, |
72 const std::string& dictionary_name, | 100 const std::string& dictionary_name, |
73 const std::string& entry_name) const { | 101 const std::string& entry_name) const { |
74 DictionaryValue* dictionary_content = NULL; | 102 DictionaryValue* dictionary_content = NULL; |
75 if (!root_->GetDictionary(dictionary_name, &dictionary_content)) | 103 if (!root_.get() || |
| 104 !root_->GetDictionary(dictionary_name, &dictionary_content)) |
76 return std::string(); | 105 return std::string(); |
77 | 106 |
78 DictionaryValue* locale_dictionary = NULL; | 107 DictionaryValue* locale_dictionary = NULL; |
79 if (dictionary_content->GetDictionary(locale, &locale_dictionary)) { | 108 if (dictionary_content->GetDictionary(locale, &locale_dictionary)) { |
80 std::string result; | 109 std::string result; |
81 if (locale_dictionary->GetString(entry_name, &result)) | 110 if (locale_dictionary->GetString(entry_name, &result)) |
82 return result; | 111 return result; |
83 } | 112 } |
84 | 113 |
85 DictionaryValue* default_dictionary = NULL; | 114 DictionaryValue* default_dictionary = NULL; |
86 if (dictionary_content->GetDictionary(kDefaultAttr, &default_dictionary)) { | 115 if (dictionary_content->GetDictionary(kDefaultAttr, &default_dictionary)) { |
87 std::string result; | 116 std::string result; |
88 if (default_dictionary->GetString(entry_name, &result)) | 117 if (default_dictionary->GetString(entry_name, &result)) |
89 return result; | 118 return result; |
90 } | 119 } |
91 | 120 |
92 return std::string(); | 121 return std::string(); |
93 } | 122 } |
94 | 123 |
95 // StartupCustomizationDocument implementation. | 124 // StartupCustomizationDocument implementation. -------------------------------- |
96 bool StartupCustomizationDocument::LoadManifestFromString( | 125 |
97 const std::string& manifest) { | 126 StartupCustomizationDocument::StartupCustomizationDocument() { |
98 if (!CustomizationDocument::LoadManifestFromString(manifest)) { | 127 { |
99 return false; | 128 // Loading manifest causes us to do blocking IO on UI thread. |
| 129 // Temporarily allow it until we fix http://crosbug.com/11103 |
| 130 base::ThreadRestrictions::ScopedAllowIO allow_io; |
| 131 LoadManifestFromFile(FilePath(kStartupCustomizationManifestPath)); |
100 } | 132 } |
| 133 Init(SystemAccess::GetInstance()); |
| 134 } |
| 135 |
| 136 StartupCustomizationDocument::StartupCustomizationDocument( |
| 137 SystemAccess* system_access, const std::string& manifest) { |
| 138 LoadManifestFromString(manifest); |
| 139 Init(system_access); |
| 140 } |
| 141 |
| 142 StartupCustomizationDocument* StartupCustomizationDocument::GetInstance() { |
| 143 return Singleton<StartupCustomizationDocument, |
| 144 DefaultSingletonTraits<StartupCustomizationDocument> >::get(); |
| 145 } |
| 146 |
| 147 void StartupCustomizationDocument::Init(SystemAccess* system_access) { |
| 148 if (!IsReady()) |
| 149 return; |
101 | 150 |
102 root_->GetString(kInitialLocaleAttr, &initial_locale_); | 151 root_->GetString(kInitialLocaleAttr, &initial_locale_); |
103 root_->GetString(kInitialTimezoneAttr, &initial_timezone_); | 152 root_->GetString(kInitialTimezoneAttr, &initial_timezone_); |
104 root_->GetString(kKeyboardLayoutAttr, &keyboard_layout_); | 153 root_->GetString(kKeyboardLayoutAttr, &keyboard_layout_); |
105 root_->GetString(kRegistrationUrlAttr, ®istration_url_); | 154 root_->GetString(kRegistrationUrlAttr, ®istration_url_); |
106 | 155 |
107 std::string hwid = GetHWID(); | 156 std::string hwid; |
108 if (!hwid.empty()) { | 157 if (system_access->GetMachineStatistic(kHwid, &hwid)) { |
109 ListValue* hwid_list = NULL; | 158 ListValue* hwid_list = NULL; |
110 if (root_->GetList(kHwidMapAttr, &hwid_list)) { | 159 if (root_->GetList(kHwidMapAttr, &hwid_list)) { |
111 for (size_t i = 0; i < hwid_list->GetSize(); ++i) { | 160 for (size_t i = 0; i < hwid_list->GetSize(); ++i) { |
112 DictionaryValue* hwid_dictionary = NULL; | 161 DictionaryValue* hwid_dictionary = NULL; |
113 std::string hwid_mask; | 162 std::string hwid_mask; |
114 if (hwid_list->GetDictionary(i, &hwid_dictionary) && | 163 if (hwid_list->GetDictionary(i, &hwid_dictionary) && |
115 hwid_dictionary->GetString(kHwidMaskAttr, &hwid_mask)) { | 164 hwid_dictionary->GetString(kHwidMaskAttr, &hwid_mask)) { |
116 if (MatchPattern(hwid, hwid_mask)) { | 165 if (MatchPattern(hwid, hwid_mask)) { |
117 // If HWID for this machine matches some mask, use HWID specific | 166 // If HWID for this machine matches some mask, use HWID specific |
118 // settings. | 167 // settings. |
119 std::string result; | 168 std::string result; |
120 if (hwid_dictionary->GetString(kInitialLocaleAttr, &result)) | 169 if (hwid_dictionary->GetString(kInitialLocaleAttr, &result)) |
121 initial_locale_ = result; | 170 initial_locale_ = result; |
122 | 171 |
123 if (hwid_dictionary->GetString(kInitialTimezoneAttr, &result)) | 172 if (hwid_dictionary->GetString(kInitialTimezoneAttr, &result)) |
124 initial_timezone_ = result; | 173 initial_timezone_ = result; |
125 | 174 |
126 if (hwid_dictionary->GetString(kKeyboardLayoutAttr, &result)) | 175 if (hwid_dictionary->GetString(kKeyboardLayoutAttr, &result)) |
127 keyboard_layout_ = result; | 176 keyboard_layout_ = result; |
128 } | 177 } |
129 // Don't break here to allow other entires to be applied if match. | 178 // Don't break here to allow other entires to be applied if match. |
130 } else { | 179 } else { |
131 LOG(ERROR) << "Syntax error in customization manifest"; | 180 LOG(ERROR) << "Syntax error in customization manifest"; |
132 } | 181 } |
133 } | 182 } |
134 } | 183 } |
135 } else { | 184 } else { |
136 LOG(ERROR) << "Can't read HWID from " << kHWIDPath; | 185 LOG(ERROR) << "HWID is missing in machine statistics"; |
137 } | 186 } |
138 | 187 |
139 VPDMap vpd_map; | 188 system_access->GetMachineStatistic(kInitialLocaleAttr, &initial_locale_); |
140 if (ParseVPD(GetVPD(), &vpd_map)) { | 189 system_access->GetMachineStatistic(kInitialTimezoneAttr, &initial_timezone_); |
141 InitFromVPD(vpd_map, kInitialLocaleAttr, &initial_locale_); | 190 system_access->GetMachineStatistic(kKeyboardLayoutAttr, &keyboard_layout_); |
142 InitFromVPD(vpd_map, kInitialTimezoneAttr, &initial_timezone_); | |
143 InitFromVPD(vpd_map, kKeyboardLayoutAttr, &keyboard_layout_); | |
144 } | |
145 | |
146 return true; | |
147 } | |
148 | |
149 std::string StartupCustomizationDocument::GetHWID() const { | |
150 // TODO(dpolukhin): move to SystemLibrary to be reusable. | |
151 std::string hwid; | |
152 FilePath hwid_file_path(kHWIDPath); | |
153 if (!file_util::ReadFileToString(hwid_file_path, &hwid)) | |
154 LOG(ERROR) << "Can't read HWID from " << kHWIDPath; | |
155 return hwid; | |
156 } | |
157 | |
158 std::string StartupCustomizationDocument::GetVPD() const { | |
159 // TODO(dpolukhin): move to SystemLibrary to be reusable. | |
160 std::string vpd; | |
161 FilePath vpd_file_path(kVPDPath); | |
162 if (!file_util::ReadFileToString(vpd_file_path, &vpd)) | |
163 LOG(ERROR) << "Can't read VPD from " << kVPDPath; | |
164 return vpd; | |
165 } | |
166 | |
167 bool StartupCustomizationDocument::ParseVPD(const std::string& vpd_string, | |
168 VPDMap* vpd_map) { | |
169 // TODO(dpolukhin): move to SystemLibrary to be reusable. | |
170 const char kDelimiterChars[] = "= \n"; | |
171 const char kQuotaChars[] = "\"\'"; | |
172 | |
173 StringTokenizer tok(vpd_string, kDelimiterChars); | |
174 tok.set_quote_chars(kQuotaChars); | |
175 tok.set_options(StringTokenizer::RETURN_DELIMS); | |
176 bool next_is_equal = false; | |
177 bool next_is_value = false; | |
178 std::string name; | |
179 std::string value; | |
180 while (tok.GetNext()) { | |
181 // Skip all delimiters that are not '='. | |
182 if (tok.token_is_delim() && tok.token() != "=") | |
183 continue; | |
184 | |
185 if (next_is_equal) { | |
186 if (tok.token() != "=") | |
187 break; | |
188 | |
189 next_is_equal = false; | |
190 next_is_value = true; | |
191 } else if (next_is_value) { | |
192 TrimString(tok.token(), kQuotaChars, &value); | |
193 next_is_value = false; | |
194 | |
195 if (!vpd_map->insert(VPDMap::value_type(name, value)).second) { | |
196 LOG(ERROR) << "Identical keys in VPD " << name; | |
197 return false; | |
198 } | |
199 } else { | |
200 TrimString(tok.token(), kQuotaChars, &name); | |
201 next_is_equal = true; | |
202 } | |
203 } | |
204 | |
205 if (next_is_equal || next_is_value) { | |
206 LOG(ERROR) << "Syntax error in VPD " << vpd_string; | |
207 return false; | |
208 } | |
209 | |
210 return true; | |
211 } | |
212 | |
213 void StartupCustomizationDocument::InitFromVPD( | |
214 const VPDMap& vpd_map, const char* attr, std::string* value) { | |
215 VPDMap::const_iterator it = vpd_map.find(attr); | |
216 if (it != vpd_map.end()) | |
217 *value = it->second; | |
218 } | 191 } |
219 | 192 |
220 std::string StartupCustomizationDocument::GetHelpPage( | 193 std::string StartupCustomizationDocument::GetHelpPage( |
221 const std::string& locale) const { | 194 const std::string& locale) const { |
222 return GetLocaleSpecificString(locale, kSetupContentAttr, kHelpPageAttr); | 195 return GetLocaleSpecificString(locale, kSetupContentAttr, kHelpPageAttr); |
223 } | 196 } |
224 | 197 |
225 std::string StartupCustomizationDocument::GetEULAPage( | 198 std::string StartupCustomizationDocument::GetEULAPage( |
226 const std::string& locale) const { | 199 const std::string& locale) const { |
227 return GetLocaleSpecificString(locale, kSetupContentAttr, kEulaPageAttr); | 200 return GetLocaleSpecificString(locale, kSetupContentAttr, kEulaPageAttr); |
228 } | 201 } |
229 | 202 |
230 // ServicesCustomizationDocument implementation. | 203 // ServicesCustomizationDocument implementation. ------------------------------- |
| 204 |
| 205 ServicesCustomizationDocument::ServicesCustomizationDocument() |
| 206 : url_(kServicesCustomizationManifestUrl) { |
| 207 } |
| 208 |
| 209 ServicesCustomizationDocument::ServicesCustomizationDocument( |
| 210 const std::string& manifest) { |
| 211 LoadManifestFromString(manifest); |
| 212 } |
| 213 |
| 214 // static |
| 215 ServicesCustomizationDocument* ServicesCustomizationDocument::GetInstance() { |
| 216 return Singleton<ServicesCustomizationDocument, |
| 217 DefaultSingletonTraits<ServicesCustomizationDocument> >::get(); |
| 218 } |
| 219 |
| 220 // static |
| 221 void ServicesCustomizationDocument::RegisterPrefs(PrefService* local_state) { |
| 222 local_state->RegisterBooleanPref(kServicesCustomizationAppliedPref, false); |
| 223 } |
| 224 |
| 225 // static |
| 226 bool ServicesCustomizationDocument::WasApplied() { |
| 227 PrefService* prefs = g_browser_process->local_state(); |
| 228 return prefs->GetBoolean(kServicesCustomizationAppliedPref); |
| 229 } |
| 230 |
| 231 // static |
| 232 void ServicesCustomizationDocument::SetApplied(bool val) { |
| 233 PrefService* prefs = g_browser_process->local_state(); |
| 234 prefs->SetBoolean(kServicesCustomizationAppliedPref, val); |
| 235 } |
| 236 |
| 237 void ServicesCustomizationDocument::StartFetching() { |
| 238 if (url_.SchemeIsFile()) { |
| 239 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, |
| 240 NewRunnableMethod(this, |
| 241 &ServicesCustomizationDocument::ReadFileInBackground, |
| 242 FilePath(url_.path()))); |
| 243 } else { |
| 244 StartFileFetch(); |
| 245 } |
| 246 } |
| 247 |
| 248 void ServicesCustomizationDocument::ReadFileInBackground(const FilePath& file) { |
| 249 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 250 |
| 251 std::string manifest; |
| 252 if (file_util::ReadFileToString(file, &manifest)) { |
| 253 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| 254 NewRunnableMethod( |
| 255 this, |
| 256 &ServicesCustomizationDocument::LoadManifestFromString, |
| 257 manifest)); |
| 258 } else { |
| 259 VLOG(1) << "Failed to load services customization manifest from: " |
| 260 << file.value(); |
| 261 } |
| 262 } |
| 263 |
| 264 void ServicesCustomizationDocument::StartFileFetch() { |
| 265 DCHECK(url_.is_valid()); |
| 266 url_fetcher_.reset(new URLFetcher(url_, URLFetcher::GET, this)); |
| 267 url_fetcher_->set_request_context( |
| 268 ProfileManager::GetDefaultProfile()->GetRequestContext()); |
| 269 url_fetcher_->Start(); |
| 270 } |
| 271 |
| 272 void ServicesCustomizationDocument::OnURLFetchComplete( |
| 273 const URLFetcher* source, |
| 274 const GURL& url, |
| 275 const net::URLRequestStatus& status, |
| 276 int response_code, |
| 277 const ResponseCookies& cookies, |
| 278 const std::string& data) { |
| 279 if (response_code == 200) { |
| 280 LoadManifestFromString(data); |
| 281 } else { |
| 282 NetworkLibrary* network = CrosLibrary::Get()->GetNetworkLibrary(); |
| 283 if (!network->Connected() && num_retries_ < kMaxFetchRetries) { |
| 284 num_retries_++; |
| 285 retry_timer_.Start(base::TimeDelta::FromSeconds(kRetriesDelayInSec), |
| 286 this, &ServicesCustomizationDocument::StartFileFetch); |
| 287 return; |
| 288 } |
| 289 LOG(ERROR) << "URL fetch for services customization failed:" |
| 290 << " response code = " << response_code |
| 291 << " URL = " << url.spec(); |
| 292 } |
| 293 } |
| 294 |
| 295 bool ServicesCustomizationDocument::ApplyCustomization() { |
| 296 // TODO(dpolukhin): apply customized apps, exts and support page. |
| 297 SetApplied(true); |
| 298 return true; |
| 299 } |
| 300 |
231 std::string ServicesCustomizationDocument::GetInitialStartPage( | 301 std::string ServicesCustomizationDocument::GetInitialStartPage( |
232 const std::string& locale) const { | 302 const std::string& locale) const { |
233 return GetLocaleSpecificString( | 303 return GetLocaleSpecificString( |
234 locale, kAppContentAttr, kInitialStartPageAttr); | 304 locale, kAppContentAttr, kInitialStartPageAttr); |
235 } | 305 } |
236 | 306 |
237 std::string ServicesCustomizationDocument::GetSupportPage( | 307 std::string ServicesCustomizationDocument::GetSupportPage( |
238 const std::string& locale) const { | 308 const std::string& locale) const { |
239 return GetLocaleSpecificString( | 309 return GetLocaleSpecificString( |
240 locale, kAppContentAttr, kSupportPageAttr); | 310 locale, kAppContentAttr, kSupportPageAttr); |
241 } | 311 } |
242 | 312 |
243 } // namespace chromeos | 313 } // namespace chromeos |
OLD | NEW |