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/ui/webui/chromeos/drive_internals_ui.h"
8 #include "base/command_line.h"
9 #include "base/file_util.h"
10 #include "base/files/file_enumerator.h"
11 #include "base/format_macros.h"
12 #include "base/memory/scoped_vector.h"
13 #include "base/memory/weak_ptr.h"
14 #include "base/path_service.h"
15 #include "base/prefs/pref_service.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/sys_info.h"
18 #include "chrome/browser/chromeos/drive/debug_info_collector.h"
19 #include "chrome/browser/chromeos/drive/drive.pb.h"
20 #include "chrome/browser/chromeos/drive/drive_integration_service.h"
21 #include "chrome/browser/chromeos/drive/file_system_util.h"
22 #include "chrome/browser/chromeos/drive/job_list.h"
23 #include "chrome/browser/chromeos/file_manager/path_util.h"
24 #include "chrome/browser/drive/drive_api_util.h"
25 #include "chrome/browser/drive/drive_notification_manager.h"
26 #include "chrome/browser/drive/drive_notification_manager_factory.h"
27 #include "chrome/browser/drive/drive_service_interface.h"
28 #include "chrome/browser/drive/event_logger.h"
29 #include "chrome/browser/profiles/profile.h"
30 #include "chrome/common/pref_names.h"
31 #include "chrome/common/url_constants.h"
32 #include "content/public/browser/browser_thread.h"
33 #include "content/public/browser/web_ui.h"
34 #include "content/public/browser/web_ui_data_source.h"
35 #include "content/public/browser/web_ui_message_handler.h"
36 #include "google_apis/drive/auth_service.h"
37 #include "google_apis/drive/drive_api_parser.h"
38 #include "google_apis/drive/gdata_errorcode.h"
39 #include "google_apis/drive/gdata_wapi_parser.h"
40 #include "google_apis/drive/time_util.h"
41 #include "grit/browser_resources.h"
43 using content::BrowserThread;
49 // Gets metadata of all files and directories in |root_path|
50 // recursively. Stores the result as a list of dictionaries like:
52 // [{ path: 'GCache/v1/tmp/<local_id>',
54 // is_directory: false,
55 // last_modified: '2005-08-09T09:57:00-08:00',
58 // The list is sorted by the path.
59 void GetGCacheContents(const base::FilePath& root_path,
60 base::ListValue* gcache_contents,
61 base::DictionaryValue* gcache_summary) {
62 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
63 DCHECK(gcache_contents);
64 DCHECK(gcache_summary);
66 // Use this map to sort the result list by the path.
67 std::map<base::FilePath, base::DictionaryValue*> files;
69 const int options = (base::FileEnumerator::FILES |
70 base::FileEnumerator::DIRECTORIES |
71 base::FileEnumerator::SHOW_SYM_LINKS);
72 base::FileEnumerator enumerator(root_path, true /* recursive */, options);
75 for (base::FilePath current = enumerator.Next(); !current.empty();
76 current = enumerator.Next()) {
77 base::FileEnumerator::FileInfo info = enumerator.GetInfo();
78 int64 size = info.GetSize();
79 const bool is_directory = info.IsDirectory();
80 const bool is_symbolic_link = base::IsLink(info.GetName());
81 const base::Time last_modified = info.GetLastModifiedTime();
83 base::DictionaryValue* entry = new base::DictionaryValue;
84 entry->SetString("path", current.value());
85 // Use double instead of integer for large files.
86 entry->SetDouble("size", size);
87 entry->SetBoolean("is_directory", is_directory);
88 entry->SetBoolean("is_symbolic_link", is_symbolic_link);
91 google_apis::util::FormatTimeAsStringLocaltime(last_modified));
92 // Print lower 9 bits in octal format.
95 base::StringPrintf("%03o", info.stat().st_mode & 0x1ff));
96 files[current] = entry;
101 // Convert |files| into |gcache_contents|.
102 for (std::map<base::FilePath, base::DictionaryValue*>::const_iterator
103 iter = files.begin(); iter != files.end(); ++iter) {
104 gcache_contents->Append(iter->second);
107 gcache_summary->SetDouble("total_size", total_size);
110 // Gets the available disk space for the path |home_path|.
111 void GetFreeDiskSpace(const base::FilePath& home_path,
112 base::DictionaryValue* local_storage_summary) {
113 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
114 DCHECK(local_storage_summary);
116 const int64 free_space = base::SysInfo::AmountOfFreeDiskSpace(home_path);
117 local_storage_summary->SetDouble("free_space", free_space);
120 // Formats |entry| into text.
121 std::string FormatEntry(const base::FilePath& path,
122 const drive::ResourceEntry& entry) {
123 DCHECK_CURRENTLY_ON(BrowserThread::UI);
125 using base::StringAppendF;
128 StringAppendF(&out, "%s\n", path.AsUTF8Unsafe().c_str());
129 StringAppendF(&out, " title: %s\n", entry.title().c_str());
130 StringAppendF(&out, " local_id: %s\n", entry.local_id().c_str());
131 StringAppendF(&out, " resource_id: %s\n", entry.resource_id().c_str());
132 StringAppendF(&out, " parent_local_id: %s\n",
133 entry.parent_local_id().c_str());
134 StringAppendF(&out, " shared: %s\n", entry.shared() ? "true" : "false");
135 StringAppendF(&out, " shared_with_me: %s\n",
136 entry.shared_with_me() ? "true" : "false");
138 const drive::PlatformFileInfoProto& file_info = entry.file_info();
139 StringAppendF(&out, " file_info\n");
140 StringAppendF(&out, " size: %" PRId64 "\n", file_info.size());
141 StringAppendF(&out, " is_directory: %d\n", file_info.is_directory());
142 StringAppendF(&out, " is_symbolic_link: %d\n",
143 file_info.is_symbolic_link());
145 const base::Time last_modified = base::Time::FromInternalValue(
146 file_info.last_modified());
147 const base::Time last_accessed = base::Time::FromInternalValue(
148 file_info.last_accessed());
149 const base::Time creation_time = base::Time::FromInternalValue(
150 file_info.creation_time());
151 StringAppendF(&out, " last_modified: %s\n",
152 google_apis::util::FormatTimeAsString(last_modified).c_str());
153 StringAppendF(&out, " last_accessed: %s\n",
154 google_apis::util::FormatTimeAsString(last_accessed).c_str());
155 StringAppendF(&out, " creation_time: %s\n",
156 google_apis::util::FormatTimeAsString(creation_time).c_str());
158 if (entry.has_file_specific_info()) {
159 const drive::FileSpecificInfo& file_specific_info =
160 entry.file_specific_info();
161 StringAppendF(&out, " alternate_url: %s\n",
162 file_specific_info.alternate_url().c_str());
163 StringAppendF(&out, " content_mime_type: %s\n",
164 file_specific_info.content_mime_type().c_str());
165 StringAppendF(&out, " file_md5: %s\n",
166 file_specific_info.md5().c_str());
167 StringAppendF(&out, " document_extension: %s\n",
168 file_specific_info.document_extension().c_str());
169 StringAppendF(&out, " is_hosted_document: %d\n",
170 file_specific_info.is_hosted_document());
173 if (entry.has_directory_specific_info()) {
174 StringAppendF(&out, " directory_info\n");
175 const drive::DirectorySpecificInfo& directory_specific_info =
176 entry.directory_specific_info();
177 StringAppendF(&out, " changestamp: %" PRId64 "\n",
178 directory_specific_info.changestamp());
184 std::string SeverityToString(logging::LogSeverity severity) {
186 case logging::LOG_INFO:
188 case logging::LOG_WARNING:
190 case logging::LOG_ERROR:
192 default: // Treat all other higher severities as ERROR.
197 // Appends {'key': key, 'value': value} dictionary to the |list|.
198 void AppendKeyValue(base::ListValue* list,
199 const std::string& key,
200 const std::string& value) {
201 base::DictionaryValue* dict = new base::DictionaryValue;
202 dict->SetString("key", key);
203 dict->SetString("value", value);
207 // Class to handle messages from chrome://drive-internals.
208 class DriveInternalsWebUIHandler : public content::WebUIMessageHandler {
210 DriveInternalsWebUIHandler()
211 : last_sent_event_id_(-1),
212 weak_ptr_factory_(this) {
215 virtual ~DriveInternalsWebUIHandler() {
219 // WebUIMessageHandler override.
220 virtual void RegisterMessages() OVERRIDE;
222 // Returns a DriveIntegrationService.
223 drive::DriveIntegrationService* GetIntegrationService();
225 // Returns a DriveService instance.
226 drive::DriveServiceInterface* GetDriveService();
228 // Returns a DebugInfoCollector instance.
229 drive::DebugInfoCollector* GetDebugInfoCollector();
231 // Called when the page is first loaded.
232 void OnPageLoaded(const base::ListValue* args);
234 // Updates respective sections.
235 void UpdateDriveRelatedPreferencesSection();
236 void UpdateConnectionStatusSection(
237 drive::DriveServiceInterface* drive_service);
238 void UpdateAboutResourceSection(
239 drive::DriveServiceInterface* drive_service);
240 void UpdateAppListSection(
241 drive::DriveServiceInterface* drive_service);
242 void UpdateLocalMetadataSection(
243 drive::DebugInfoCollector* debug_info_collector);
244 void UpdateDeltaUpdateStatusSection(
245 drive::DebugInfoCollector* debug_info_collector);
246 void UpdateInFlightOperationsSection(drive::JobListInterface* job_list);
247 void UpdateGCacheContentsSection();
248 void UpdateFileSystemContentsSection();
249 void UpdateLocalStorageUsageSection();
250 void UpdateCacheContentsSection(
251 drive::DebugInfoCollector* debug_info_collector);
252 void UpdateEventLogSection();
253 void UpdatePathConfigurationsSection();
255 // Called when GetGCacheContents() is complete.
256 void OnGetGCacheContents(base::ListValue* gcache_contents,
257 base::DictionaryValue* cache_summary);
259 // Called when GetResourceEntryByPath() is complete.
260 void OnGetResourceEntryByPath(const base::FilePath& path,
261 drive::FileError error,
262 scoped_ptr<drive::ResourceEntry> entry);
264 // Called when ReadDirectoryByPath() is complete.
265 void OnReadDirectoryByPath(const base::FilePath& parent_path,
266 drive::FileError error,
267 scoped_ptr<drive::ResourceEntryVector> entries);
269 // Called as the iterator for DebugInfoCollector::IterateFileCache().
270 void UpdateCacheEntry(const std::string& local_id,
271 const drive::FileCacheEntry& cache_entry);
273 // Called when GetFreeDiskSpace() is complete.
274 void OnGetFreeDiskSpace(base::DictionaryValue* local_storage_summary);
276 // Called when GetAboutResource() call to DriveService is complete.
277 void OnGetAboutResource(
278 google_apis::GDataErrorCode status,
279 scoped_ptr<google_apis::AboutResource> about_resource);
281 // Called when GetAppList() call to DriveService is complete.
283 google_apis::GDataErrorCode status,
284 scoped_ptr<google_apis::AppList> app_list);
286 // Callback for DebugInfoCollector::GetMetadata for local update.
287 void OnGetFilesystemMetadataForLocal(
288 const drive::FileSystemMetadata& metadata);
290 // Callback for DebugInfoCollector::GetMetadata for delta update.
291 void OnGetFilesystemMetadataForDeltaUpdate(
292 const drive::FileSystemMetadata& metadata);
294 // Called when the page requests periodic update.
295 void OnPeriodicUpdate(const base::ListValue* args);
297 // Called when the corresponding button on the page is pressed.
298 void ClearAccessToken(const base::ListValue* args);
299 void ClearRefreshToken(const base::ListValue* args);
300 void ResetDriveFileSystem(const base::ListValue* args);
301 void ListFileEntries(const base::ListValue* args);
303 // Called after file system reset for ResetDriveFileSystem is done.
304 void ResetFinished(bool success);
306 // The last event sent to the JavaScript side.
307 int last_sent_event_id_;
309 base::WeakPtrFactory<DriveInternalsWebUIHandler> weak_ptr_factory_;
310 DISALLOW_COPY_AND_ASSIGN(DriveInternalsWebUIHandler);
313 void DriveInternalsWebUIHandler::OnGetAboutResource(
314 google_apis::GDataErrorCode status,
315 scoped_ptr<google_apis::AboutResource> parsed_about_resource) {
316 DCHECK_CURRENTLY_ON(BrowserThread::UI);
318 if (status != google_apis::HTTP_SUCCESS) {
319 LOG(ERROR) << "Failed to get about resource";
322 DCHECK(parsed_about_resource);
324 base::DictionaryValue about_resource;
325 about_resource.SetDouble("account-quota-total",
326 parsed_about_resource->quota_bytes_total());
327 about_resource.SetDouble("account-quota-used",
328 parsed_about_resource->quota_bytes_used());
329 about_resource.SetDouble("account-largest-changestamp-remote",
330 parsed_about_resource->largest_change_id());
331 about_resource.SetString("root-resource-id",
332 parsed_about_resource->root_folder_id());
334 web_ui()->CallJavascriptFunction("updateAboutResource", about_resource);
337 void DriveInternalsWebUIHandler::OnGetAppList(
338 google_apis::GDataErrorCode status,
339 scoped_ptr<google_apis::AppList> parsed_app_list) {
340 DCHECK_CURRENTLY_ON(BrowserThread::UI);
342 if (status != google_apis::HTTP_SUCCESS) {
343 LOG(ERROR) << "Failed to get app list";
346 DCHECK(parsed_app_list);
348 base::DictionaryValue app_list;
349 app_list.SetString("etag", parsed_app_list->etag());
351 base::ListValue* items = new base::ListValue();
352 for (size_t i = 0; i < parsed_app_list->items().size(); ++i) {
353 const google_apis::AppResource* app = parsed_app_list->items()[i];
354 base::DictionaryValue* app_data = new base::DictionaryValue();
355 app_data->SetString("name", app->name());
356 app_data->SetString("application_id", app->application_id());
357 app_data->SetString("object_type", app->object_type());
358 app_data->SetBoolean("supports_create", app->supports_create());
360 items->Append(app_data);
362 app_list.Set("items", items);
364 web_ui()->CallJavascriptFunction("updateAppList", app_list);
367 void DriveInternalsWebUIHandler::RegisterMessages() {
368 web_ui()->RegisterMessageCallback(
370 base::Bind(&DriveInternalsWebUIHandler::OnPageLoaded,
371 weak_ptr_factory_.GetWeakPtr()));
372 web_ui()->RegisterMessageCallback(
374 base::Bind(&DriveInternalsWebUIHandler::OnPeriodicUpdate,
375 weak_ptr_factory_.GetWeakPtr()));
376 web_ui()->RegisterMessageCallback(
378 base::Bind(&DriveInternalsWebUIHandler::ClearAccessToken,
379 weak_ptr_factory_.GetWeakPtr()));
380 web_ui()->RegisterMessageCallback(
382 base::Bind(&DriveInternalsWebUIHandler::ClearRefreshToken,
383 weak_ptr_factory_.GetWeakPtr()));
384 web_ui()->RegisterMessageCallback(
385 "resetDriveFileSystem",
386 base::Bind(&DriveInternalsWebUIHandler::ResetDriveFileSystem,
387 weak_ptr_factory_.GetWeakPtr()));
388 web_ui()->RegisterMessageCallback(
390 base::Bind(&DriveInternalsWebUIHandler::ListFileEntries,
391 weak_ptr_factory_.GetWeakPtr()));
394 drive::DriveIntegrationService*
395 DriveInternalsWebUIHandler::GetIntegrationService() {
396 DCHECK_CURRENTLY_ON(BrowserThread::UI);
398 Profile* profile = Profile::FromWebUI(web_ui());
399 drive::DriveIntegrationService* service =
400 drive::DriveIntegrationServiceFactory::FindForProfile(profile);
401 if (!service || !service->is_enabled())
406 drive::DriveServiceInterface* DriveInternalsWebUIHandler::GetDriveService() {
407 DCHECK_CURRENTLY_ON(BrowserThread::UI);
409 Profile* profile = Profile::FromWebUI(web_ui());
410 return drive::util::GetDriveServiceByProfile(profile);
413 drive::DebugInfoCollector* DriveInternalsWebUIHandler::GetDebugInfoCollector() {
414 DCHECK_CURRENTLY_ON(BrowserThread::UI);
416 drive::DriveIntegrationService* integration_service = GetIntegrationService();
417 return integration_service ?
418 integration_service->debug_info_collector() : NULL;
421 void DriveInternalsWebUIHandler::OnPageLoaded(const base::ListValue* args) {
422 DCHECK_CURRENTLY_ON(BrowserThread::UI);
424 drive::DriveIntegrationService* integration_service =
425 GetIntegrationService();
426 // |integration_service| may be NULL in the guest/incognito mode.
427 if (!integration_service)
430 drive::DriveServiceInterface* drive_service =
431 integration_service->drive_service();
432 DCHECK(drive_service);
433 drive::DebugInfoCollector* debug_info_collector =
434 integration_service->debug_info_collector();
435 DCHECK(debug_info_collector);
437 UpdateDriveRelatedPreferencesSection();
438 UpdateConnectionStatusSection(drive_service);
439 UpdateAboutResourceSection(drive_service);
440 UpdateAppListSection(drive_service);
441 UpdateLocalMetadataSection(debug_info_collector);
442 UpdateDeltaUpdateStatusSection(debug_info_collector);
443 UpdateInFlightOperationsSection(integration_service->job_list());
444 UpdateGCacheContentsSection();
445 UpdateCacheContentsSection(debug_info_collector);
446 UpdateLocalStorageUsageSection();
447 UpdatePathConfigurationsSection();
449 // When the drive-internals page is reloaded by the reload key, the page
450 // content is recreated, but this WebUI object is not (instead, OnPageLoaded
451 // is called again). In that case, we have to forget the last sent ID here,
452 // and resent whole the logs to the page.
453 last_sent_event_id_ = -1;
454 UpdateEventLogSection();
457 void DriveInternalsWebUIHandler::UpdateDriveRelatedPreferencesSection() {
458 DCHECK_CURRENTLY_ON(BrowserThread::UI);
460 const char* kDriveRelatedPreferences[] = {
461 prefs::kDisableDrive,
462 prefs::kDisableDriveOverCellular,
463 prefs::kDisableDriveHostedFiles,
466 Profile* profile = Profile::FromWebUI(web_ui());
467 PrefService* pref_service = profile->GetPrefs();
469 base::ListValue preferences;
470 for (size_t i = 0; i < arraysize(kDriveRelatedPreferences); ++i) {
471 const std::string key = kDriveRelatedPreferences[i];
472 // As of now, all preferences are boolean.
473 const std::string value =
474 (pref_service->GetBoolean(key.c_str()) ? "true" : "false");
475 AppendKeyValue(&preferences, key, value);
478 web_ui()->CallJavascriptFunction("updateDriveRelatedPreferences",
482 void DriveInternalsWebUIHandler::UpdateConnectionStatusSection(
483 drive::DriveServiceInterface* drive_service) {
484 DCHECK_CURRENTLY_ON(BrowserThread::UI);
485 DCHECK(drive_service);
488 switch (drive::util::GetDriveConnectionStatus(Profile::FromWebUI(web_ui()))) {
489 case drive::util::DRIVE_DISCONNECTED_NOSERVICE:
490 status = "no service";
492 case drive::util::DRIVE_DISCONNECTED_NONETWORK:
493 status = "no network";
495 case drive::util::DRIVE_DISCONNECTED_NOTREADY:
496 status = "not ready";
498 case drive::util::DRIVE_CONNECTED_METERED:
501 case drive::util::DRIVE_CONNECTED:
502 status = "connected";
506 base::DictionaryValue connection_status;
507 connection_status.SetString("status", status);
508 connection_status.SetBoolean("has-refresh-token",
509 drive_service->HasRefreshToken());
510 connection_status.SetBoolean("has-access-token",
511 drive_service->HasAccessToken());
512 web_ui()->CallJavascriptFunction("updateConnectionStatus", connection_status);
515 void DriveInternalsWebUIHandler::UpdateAboutResourceSection(
516 drive::DriveServiceInterface* drive_service) {
517 DCHECK_CURRENTLY_ON(BrowserThread::UI);
518 DCHECK(drive_service);
520 drive_service->GetAboutResource(
521 base::Bind(&DriveInternalsWebUIHandler::OnGetAboutResource,
522 weak_ptr_factory_.GetWeakPtr()));
525 void DriveInternalsWebUIHandler::UpdateAppListSection(
526 drive::DriveServiceInterface* drive_service) {
527 DCHECK_CURRENTLY_ON(BrowserThread::UI);
528 DCHECK(drive_service);
530 drive_service->GetAppList(
531 base::Bind(&DriveInternalsWebUIHandler::OnGetAppList,
532 weak_ptr_factory_.GetWeakPtr()));
535 void DriveInternalsWebUIHandler::UpdateLocalMetadataSection(
536 drive::DebugInfoCollector* debug_info_collector) {
537 DCHECK_CURRENTLY_ON(BrowserThread::UI);
538 DCHECK(debug_info_collector);
540 debug_info_collector->GetMetadata(
541 base::Bind(&DriveInternalsWebUIHandler::OnGetFilesystemMetadataForLocal,
542 weak_ptr_factory_.GetWeakPtr()));
545 void DriveInternalsWebUIHandler::OnGetFilesystemMetadataForLocal(
546 const drive::FileSystemMetadata& metadata) {
547 DCHECK_CURRENTLY_ON(BrowserThread::UI);
549 base::DictionaryValue local_metadata;
550 local_metadata.SetDouble("account-largest-changestamp-local",
551 metadata.largest_changestamp);
552 local_metadata.SetBoolean("account-metadata-refreshing", metadata.refreshing);
553 web_ui()->CallJavascriptFunction("updateLocalMetadata", local_metadata);
556 void DriveInternalsWebUIHandler::ClearAccessToken(const base::ListValue* args) {
557 DCHECK_CURRENTLY_ON(BrowserThread::UI);
559 drive::DriveServiceInterface* drive_service = GetDriveService();
561 drive_service->ClearAccessToken();
564 void DriveInternalsWebUIHandler::ClearRefreshToken(
565 const base::ListValue* args) {
566 DCHECK_CURRENTLY_ON(BrowserThread::UI);
568 drive::DriveServiceInterface* drive_service = GetDriveService();
570 drive_service->ClearRefreshToken();
573 void DriveInternalsWebUIHandler::ResetDriveFileSystem(
574 const base::ListValue* args) {
575 DCHECK_CURRENTLY_ON(BrowserThread::UI);
577 drive::DriveIntegrationService* integration_service =
578 GetIntegrationService();
579 if (integration_service) {
580 integration_service->ClearCacheAndRemountFileSystem(
581 base::Bind(&DriveInternalsWebUIHandler::ResetFinished,
582 weak_ptr_factory_.GetWeakPtr()));
586 void DriveInternalsWebUIHandler::ResetFinished(bool success) {
587 DCHECK_CURRENTLY_ON(BrowserThread::UI);
589 web_ui()->CallJavascriptFunction("updateResetStatus",
590 base::FundamentalValue(success));
593 void DriveInternalsWebUIHandler::ListFileEntries(const base::ListValue* args) {
594 DCHECK_CURRENTLY_ON(BrowserThread::UI);
596 UpdateFileSystemContentsSection();
599 void DriveInternalsWebUIHandler::UpdateDeltaUpdateStatusSection(
600 drive::DebugInfoCollector* debug_info_collector) {
601 DCHECK_CURRENTLY_ON(BrowserThread::UI);
602 DCHECK(debug_info_collector);
604 debug_info_collector->GetMetadata(
606 &DriveInternalsWebUIHandler::OnGetFilesystemMetadataForDeltaUpdate,
607 weak_ptr_factory_.GetWeakPtr()));
610 void DriveInternalsWebUIHandler::OnGetFilesystemMetadataForDeltaUpdate(
611 const drive::FileSystemMetadata& metadata) {
612 DCHECK_CURRENTLY_ON(BrowserThread::UI);
614 Profile* profile = Profile::FromWebUI(web_ui());
615 drive::DriveNotificationManager* drive_notification_manager =
616 drive::DriveNotificationManagerFactory::FindForBrowserContext(profile);
617 if (!drive_notification_manager)
620 base::DictionaryValue delta_update_status;
621 delta_update_status.SetBoolean(
622 "push-notification-enabled",
623 drive_notification_manager->push_notification_enabled());
624 delta_update_status.SetString(
625 "last-update-check-time",
626 google_apis::util::FormatTimeAsStringLocaltime(
627 metadata.last_update_check_time));
628 delta_update_status.SetString(
629 "last-update-check-error",
630 drive::FileErrorToString(metadata.last_update_check_error));
632 web_ui()->CallJavascriptFunction("updateDeltaUpdateStatus",
633 delta_update_status);
636 void DriveInternalsWebUIHandler::UpdateInFlightOperationsSection(
637 drive::JobListInterface* job_list) {
638 DCHECK_CURRENTLY_ON(BrowserThread::UI);
641 std::vector<drive::JobInfo> info_list = job_list->GetJobInfoList();
643 base::ListValue in_flight_operations;
644 for (size_t i = 0; i < info_list.size(); ++i) {
645 const drive::JobInfo& info = info_list[i];
647 base::DictionaryValue* dict = new base::DictionaryValue;
648 dict->SetInteger("id", info.job_id);
649 dict->SetString("type", drive::JobTypeToString(info.job_type));
650 dict->SetString("file_path", info.file_path.AsUTF8Unsafe());
651 dict->SetString("state", drive::JobStateToString(info.state));
652 dict->SetDouble("progress_current", info.num_completed_bytes);
653 dict->SetDouble("progress_total", info.num_total_bytes);
654 in_flight_operations.Append(dict);
656 web_ui()->CallJavascriptFunction("updateInFlightOperations",
657 in_flight_operations);
660 void DriveInternalsWebUIHandler::UpdateGCacheContentsSection() {
661 DCHECK_CURRENTLY_ON(BrowserThread::UI);
663 // Start updating the GCache contents section.
664 Profile* profile = Profile::FromWebUI(web_ui());
665 const base::FilePath root_path = drive::util::GetCacheRootPath(profile);
666 base::ListValue* gcache_contents = new base::ListValue;
667 base::DictionaryValue* gcache_summary = new base::DictionaryValue;
668 BrowserThread::PostBlockingPoolTaskAndReply(
670 base::Bind(&GetGCacheContents,
674 base::Bind(&DriveInternalsWebUIHandler::OnGetGCacheContents,
675 weak_ptr_factory_.GetWeakPtr(),
676 base::Owned(gcache_contents),
677 base::Owned(gcache_summary)));
680 void DriveInternalsWebUIHandler::UpdateFileSystemContentsSection() {
681 DCHECK_CURRENTLY_ON(BrowserThread::UI);
683 drive::DebugInfoCollector* debug_info_collector = GetDebugInfoCollector();
684 if (!debug_info_collector)
687 // Start rendering the file system tree as text.
688 const base::FilePath root_path = drive::util::GetDriveGrandRootPath();
690 debug_info_collector->GetResourceEntry(
692 base::Bind(&DriveInternalsWebUIHandler::OnGetResourceEntryByPath,
693 weak_ptr_factory_.GetWeakPtr(),
696 debug_info_collector->ReadDirectory(
698 base::Bind(&DriveInternalsWebUIHandler::OnReadDirectoryByPath,
699 weak_ptr_factory_.GetWeakPtr(),
703 void DriveInternalsWebUIHandler::UpdateLocalStorageUsageSection() {
704 DCHECK_CURRENTLY_ON(BrowserThread::UI);
706 // Propagate the amount of local free space in bytes.
707 base::FilePath home_path;
708 if (PathService::Get(base::DIR_HOME, &home_path)) {
709 base::DictionaryValue* local_storage_summary = new base::DictionaryValue;
710 BrowserThread::PostBlockingPoolTaskAndReply(
712 base::Bind(&GetFreeDiskSpace, home_path, local_storage_summary),
713 base::Bind(&DriveInternalsWebUIHandler::OnGetFreeDiskSpace,
714 weak_ptr_factory_.GetWeakPtr(),
715 base::Owned(local_storage_summary)));
717 LOG(ERROR) << "Home directory not found";
721 void DriveInternalsWebUIHandler::UpdateCacheContentsSection(
722 drive::DebugInfoCollector* debug_info_collector) {
723 DCHECK_CURRENTLY_ON(BrowserThread::UI);
724 DCHECK(debug_info_collector);
726 debug_info_collector->IterateFileCache(
727 base::Bind(&DriveInternalsWebUIHandler::UpdateCacheEntry,
728 weak_ptr_factory_.GetWeakPtr()),
729 base::Bind(&base::DoNothing));
732 void DriveInternalsWebUIHandler::UpdateEventLogSection() {
733 DCHECK_CURRENTLY_ON(BrowserThread::UI);
735 drive::DriveIntegrationService* integration_service =
736 GetIntegrationService();
737 if (!integration_service)
740 const std::vector<drive::EventLogger::Event> log =
741 integration_service->event_logger()->GetHistory();
743 base::ListValue list;
744 for (size_t i = 0; i < log.size(); ++i) {
745 // Skip events which were already sent.
746 if (log[i].id <= last_sent_event_id_)
749 std::string severity = SeverityToString(log[i].severity);
751 base::DictionaryValue* dict = new base::DictionaryValue;
752 dict->SetString("key",
753 google_apis::util::FormatTimeAsStringLocaltime(log[i].when));
754 dict->SetString("value", "[" + severity + "] " + log[i].what);
755 dict->SetString("class", "log-" + severity);
757 last_sent_event_id_ = log[i].id;
760 web_ui()->CallJavascriptFunction("updateEventLog", list);
763 void DriveInternalsWebUIHandler::UpdatePathConfigurationsSection() {
764 DCHECK_CURRENTLY_ON(BrowserThread::UI);
766 Profile* const profile = Profile::FromWebUI(web_ui());
768 base::ListValue paths;
772 file_manager::util::GetDownloadsFolderForProfile(profile).AsUTF8Unsafe());
775 drive::util::GetDriveMountPointPath(profile).AsUTF8Unsafe());
777 const char* kPathPreferences[] = {
778 prefs::kSelectFileLastDirectory,
779 prefs::kSaveFileDefaultDirectory,
780 prefs::kDownloadDefaultDirectory,
782 for (size_t i = 0; i < arraysize(kPathPreferences); ++i) {
783 const char* const key = kPathPreferences[i];
784 AppendKeyValue(&paths, key,
785 profile->GetPrefs()->GetFilePath(key).AsUTF8Unsafe());
788 web_ui()->CallJavascriptFunction("updatePathConfigurations", paths);
791 void DriveInternalsWebUIHandler::OnGetGCacheContents(
792 base::ListValue* gcache_contents,
793 base::DictionaryValue* gcache_summary) {
794 DCHECK_CURRENTLY_ON(BrowserThread::UI);
795 DCHECK(gcache_contents);
796 DCHECK(gcache_summary);
798 web_ui()->CallJavascriptFunction("updateGCacheContents",
803 void DriveInternalsWebUIHandler::OnGetResourceEntryByPath(
804 const base::FilePath& path,
805 drive::FileError error,
806 scoped_ptr<drive::ResourceEntry> entry) {
807 DCHECK_CURRENTLY_ON(BrowserThread::UI);
809 if (error == drive::FILE_ERROR_OK) {
811 const base::StringValue value(FormatEntry(path, *entry) + "\n");
812 web_ui()->CallJavascriptFunction("updateFileSystemContents", value);
816 void DriveInternalsWebUIHandler::OnReadDirectoryByPath(
817 const base::FilePath& parent_path,
818 drive::FileError error,
819 scoped_ptr<drive::ResourceEntryVector> entries) {
820 DCHECK_CURRENTLY_ON(BrowserThread::UI);
822 if (error == drive::FILE_ERROR_OK) {
823 DCHECK(entries.get());
825 drive::DebugInfoCollector* debug_info_collector = GetDebugInfoCollector();
826 std::string file_system_as_text;
827 for (size_t i = 0; i < entries->size(); ++i) {
828 const drive::ResourceEntry& entry = (*entries)[i];
829 const base::FilePath current_path = parent_path.Append(
830 base::FilePath::FromUTF8Unsafe(entry.base_name()));
832 file_system_as_text.append(FormatEntry(current_path, entry) + "\n");
834 if (entry.file_info().is_directory()) {
835 debug_info_collector->ReadDirectory(
837 base::Bind(&DriveInternalsWebUIHandler::OnReadDirectoryByPath,
838 weak_ptr_factory_.GetWeakPtr(),
843 // There may be pending ReadDirectoryByPath() calls, but we can update
844 // the page with what we have now. This results in progressive
845 // updates, which is good for a large file system.
846 const base::StringValue value(file_system_as_text);
847 web_ui()->CallJavascriptFunction("updateFileSystemContents", value);
851 void DriveInternalsWebUIHandler::UpdateCacheEntry(
852 const std::string& local_id,
853 const drive::FileCacheEntry& cache_entry) {
854 DCHECK_CURRENTLY_ON(BrowserThread::UI);
856 // Convert |cache_entry| into a dictionary.
857 base::DictionaryValue value;
858 value.SetString("local_id", local_id);
859 value.SetString("md5", cache_entry.md5());
860 value.SetBoolean("is_present", cache_entry.is_present());
861 value.SetBoolean("is_pinned", cache_entry.is_pinned());
862 value.SetBoolean("is_dirty", cache_entry.is_dirty());
864 web_ui()->CallJavascriptFunction("updateCacheContents", value);
867 void DriveInternalsWebUIHandler::OnGetFreeDiskSpace(
868 base::DictionaryValue* local_storage_summary) {
869 DCHECK_CURRENTLY_ON(BrowserThread::UI);
870 DCHECK(local_storage_summary);
872 web_ui()->CallJavascriptFunction(
873 "updateLocalStorageUsage", *local_storage_summary);
876 void DriveInternalsWebUIHandler::OnPeriodicUpdate(const base::ListValue* args) {
877 DCHECK_CURRENTLY_ON(BrowserThread::UI);
879 drive::DriveIntegrationService* integration_service =
880 GetIntegrationService();
881 // |integration_service| may be NULL in the guest/incognito mode.
882 if (!integration_service)
885 UpdateInFlightOperationsSection(integration_service->job_list());
886 UpdateEventLogSection();
891 DriveInternalsUI::DriveInternalsUI(content::WebUI* web_ui)
892 : WebUIController(web_ui) {
893 web_ui->AddMessageHandler(new DriveInternalsWebUIHandler());
895 content::WebUIDataSource* source =
896 content::WebUIDataSource::Create(chrome::kChromeUIDriveInternalsHost);
897 source->AddResourcePath("drive_internals.css", IDR_DRIVE_INTERNALS_CSS);
898 source->AddResourcePath("drive_internals.js", IDR_DRIVE_INTERNALS_JS);
899 source->SetDefaultResource(IDR_DRIVE_INTERNALS_HTML);
901 Profile* profile = Profile::FromWebUI(web_ui);
902 content::WebUIDataSource::Add(profile, source);
905 } // namespace chromeos