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_interface.h"
22 #include "chrome/browser/chromeos/drive/file_system_util.h"
23 #include "chrome/browser/chromeos/drive/job_list.h"
24 #include "chrome/browser/chromeos/drive/logging.h"
25 #include "chrome/browser/drive/drive_api_util.h"
26 #include "chrome/browser/drive/drive_notification_manager.h"
27 #include "chrome/browser/drive/drive_notification_manager_factory.h"
28 #include "chrome/browser/drive/drive_service_interface.h"
29 #include "chrome/browser/drive/drive_switches.h"
30 #include "chrome/browser/drive/event_logger.h"
31 #include "chrome/browser/google_apis/auth_service.h"
32 #include "chrome/browser/google_apis/drive_api_parser.h"
33 #include "chrome/browser/google_apis/gdata_errorcode.h"
34 #include "chrome/browser/google_apis/gdata_wapi_parser.h"
35 #include "chrome/browser/google_apis/time_util.h"
36 #include "chrome/browser/profiles/profile.h"
37 #include "chrome/common/pref_names.h"
38 #include "chrome/common/url_constants.h"
39 #include "chromeos/chromeos_switches.h"
40 #include "content/public/browser/browser_thread.h"
41 #include "content/public/browser/web_ui.h"
42 #include "content/public/browser/web_ui_data_source.h"
43 #include "content/public/browser/web_ui_message_handler.h"
44 #include "grit/browser_resources.h"
46 using content::BrowserThread;
52 // Gets metadata of all files and directories in |root_path|
53 // recursively. Stores the result as a list of dictionaries like:
55 // [{ path: 'GCache/v1/tmp/<local_id>',
57 // is_directory: false,
58 // last_modified: '2005-08-09T09:57:00-08:00',
61 // The list is sorted by the path.
62 void GetGCacheContents(const base::FilePath& root_path,
63 base::ListValue* gcache_contents,
64 base::DictionaryValue* gcache_summary) {
65 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
66 DCHECK(gcache_contents);
67 DCHECK(gcache_summary);
69 // Use this map to sort the result list by the path.
70 std::map<base::FilePath, DictionaryValue*> files;
72 const int options = (base::FileEnumerator::FILES |
73 base::FileEnumerator::DIRECTORIES |
74 base::FileEnumerator::SHOW_SYM_LINKS);
75 base::FileEnumerator enumerator(root_path, true /* recursive */, options);
78 for (base::FilePath current = enumerator.Next(); !current.empty();
79 current = enumerator.Next()) {
80 base::FileEnumerator::FileInfo info = enumerator.GetInfo();
81 int64 size = info.GetSize();
82 const bool is_directory = info.IsDirectory();
83 const bool is_symbolic_link = file_util::IsLink(info.GetName());
84 const base::Time last_modified = info.GetLastModifiedTime();
86 base::DictionaryValue* entry = new base::DictionaryValue;
87 entry->SetString("path", current.value());
88 // Use double instead of integer for large files.
89 entry->SetDouble("size", size);
90 entry->SetBoolean("is_directory", is_directory);
91 entry->SetBoolean("is_symbolic_link", is_symbolic_link);
94 google_apis::util::FormatTimeAsStringLocaltime(last_modified));
95 // Print lower 9 bits in octal format.
98 base::StringPrintf("%03o", info.stat().st_mode & 0x1ff));
99 files[current] = entry;
104 // Convert |files| into |gcache_contents|.
105 for (std::map<base::FilePath, DictionaryValue*>::const_iterator
106 iter = files.begin(); iter != files.end(); ++iter) {
107 gcache_contents->Append(iter->second);
110 gcache_summary->SetDouble("total_size", total_size);
113 // Gets the available disk space for the path |home_path|.
114 void GetFreeDiskSpace(const base::FilePath& home_path,
115 base::DictionaryValue* local_storage_summary) {
116 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
117 DCHECK(local_storage_summary);
119 const int64 free_space = base::SysInfo::AmountOfFreeDiskSpace(home_path);
120 local_storage_summary->SetDouble("free_space", free_space);
123 // Formats |entry| into text.
124 std::string FormatEntry(const base::FilePath& path,
125 const drive::ResourceEntry& entry) {
126 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
128 using base::StringAppendF;
131 StringAppendF(&out, "%s\n", path.AsUTF8Unsafe().c_str());
132 StringAppendF(&out, " title: %s\n", entry.title().c_str());
133 StringAppendF(&out, " local_id: %s\n", entry.local_id().c_str());
134 StringAppendF(&out, " resource_id: %s\n", entry.resource_id().c_str());
135 StringAppendF(&out, " parent_local_id: %s\n",
136 entry.parent_local_id().c_str());
137 StringAppendF(&out, " shared_with_me: %s\n",
138 entry.shared_with_me() ? "true" : "false");
140 const drive::PlatformFileInfoProto& file_info = entry.file_info();
141 StringAppendF(&out, " file_info\n");
142 StringAppendF(&out, " size: %" PRId64 "\n", file_info.size());
143 StringAppendF(&out, " is_directory: %d\n", file_info.is_directory());
144 StringAppendF(&out, " is_symbolic_link: %d\n",
145 file_info.is_symbolic_link());
147 const base::Time last_modified = base::Time::FromInternalValue(
148 file_info.last_modified());
149 const base::Time last_accessed = base::Time::FromInternalValue(
150 file_info.last_accessed());
151 const base::Time creation_time = base::Time::FromInternalValue(
152 file_info.creation_time());
153 StringAppendF(&out, " last_modified: %s\n",
154 google_apis::util::FormatTimeAsString(last_modified).c_str());
155 StringAppendF(&out, " last_accessed: %s\n",
156 google_apis::util::FormatTimeAsString(last_accessed).c_str());
157 StringAppendF(&out, " creation_time: %s\n",
158 google_apis::util::FormatTimeAsString(creation_time).c_str());
160 if (entry.has_file_specific_info()) {
161 const drive::FileSpecificInfo& file_specific_info =
162 entry.file_specific_info();
163 StringAppendF(&out, " alternate_url: %s\n",
164 file_specific_info.alternate_url().c_str());
165 StringAppendF(&out, " content_mime_type: %s\n",
166 file_specific_info.content_mime_type().c_str());
167 StringAppendF(&out, " file_md5: %s\n",
168 file_specific_info.md5().c_str());
169 StringAppendF(&out, " document_extension: %s\n",
170 file_specific_info.document_extension().c_str());
171 StringAppendF(&out, " is_hosted_document: %d\n",
172 file_specific_info.is_hosted_document());
175 if (entry.has_directory_specific_info()) {
176 StringAppendF(&out, " directory_info\n");
177 const drive::DirectorySpecificInfo& directory_specific_info =
178 entry.directory_specific_info();
179 StringAppendF(&out, " changestamp: %" PRId64 "\n",
180 directory_specific_info.changestamp());
186 std::string SeverityToString(logging::LogSeverity severity) {
188 case logging::LOG_INFO:
190 case logging::LOG_WARNING:
192 case logging::LOG_ERROR:
194 default: // Treat all other higher severities as ERROR.
199 // Class to handle messages from chrome://drive-internals.
200 class DriveInternalsWebUIHandler : public content::WebUIMessageHandler {
202 DriveInternalsWebUIHandler()
203 : last_sent_event_id_(-1),
204 weak_ptr_factory_(this) {
207 virtual ~DriveInternalsWebUIHandler() {
211 // WebUIMessageHandler override.
212 virtual void RegisterMessages() OVERRIDE;
214 // Returns a DriveIntegrationService.
215 drive::DriveIntegrationService* GetIntegrationService();
217 // Returns a DriveService instance.
218 drive::DriveServiceInterface* GetDriveService();
220 // Returns a FileSystem instance.
221 drive::FileSystemInterface* GetFileSystem();
223 // Called when the page is first loaded.
224 void OnPageLoaded(const base::ListValue* args);
226 // Updates respective sections.
227 void UpdateDriveRelatedFlagsSection();
228 void UpdateDriveRelatedPreferencesSection();
229 void UpdateAuthStatusSection(
230 drive::DriveServiceInterface* drive_service);
231 void UpdateAboutResourceSection(
232 drive::DriveServiceInterface* drive_service);
233 void UpdateAppListSection(
234 drive::DriveServiceInterface* drive_service);
235 void UpdateLocalMetadataSection(
236 drive::DebugInfoCollector* debug_info_collector);
237 void UpdateDeltaUpdateStatusSection(
238 drive::DebugInfoCollector* debug_info_collector);
239 void UpdateInFlightOperationsSection(drive::JobListInterface* job_list);
240 void UpdateGCacheContentsSection();
241 void UpdateFileSystemContentsSection();
242 void UpdateLocalStorageUsageSection();
243 void UpdateCacheContentsSection(
244 drive::DebugInfoCollector* debug_info_collector);
245 void UpdateEventLogSection();
247 // Called when GetGCacheContents() is complete.
248 void OnGetGCacheContents(base::ListValue* gcache_contents,
249 base::DictionaryValue* cache_summary);
251 // Called when GetResourceEntryByPath() is complete.
252 void OnGetResourceEntryByPath(const base::FilePath& path,
253 drive::FileError error,
254 scoped_ptr<drive::ResourceEntry> entry);
256 // Called when ReadDirectoryByPath() is complete.
257 void OnReadDirectoryByPath(const base::FilePath& parent_path,
258 drive::FileError error,
259 scoped_ptr<drive::ResourceEntryVector> entries);
261 // Called as the iterator for DebugInfoCollector::IterateFileCache().
262 void UpdateCacheEntry(const std::string& local_id,
263 const drive::FileCacheEntry& cache_entry);
265 // Called when GetFreeDiskSpace() is complete.
266 void OnGetFreeDiskSpace(base::DictionaryValue* local_storage_summary);
268 // Called when GetAboutResource() call to DriveService is complete.
269 void OnGetAboutResource(
270 google_apis::GDataErrorCode status,
271 scoped_ptr<google_apis::AboutResource> about_resource);
273 // Called when GetAppList() call to DriveService is complete.
275 google_apis::GDataErrorCode status,
276 scoped_ptr<google_apis::AppList> app_list);
278 // Callback for DebugInfoCollector::GetMetadata for local update.
279 void OnGetFilesystemMetadataForLocal(
280 const drive::FileSystemMetadata& metadata);
282 // Callback for DebugInfoCollector::GetMetadata for delta update.
283 void OnGetFilesystemMetadataForDeltaUpdate(
284 const drive::FileSystemMetadata& metadata);
286 // Called when the page requests periodic update.
287 void OnPeriodicUpdate(const base::ListValue* args);
289 void ClearAccessToken(const base::ListValue* args);
290 void ClearRefreshToken(const base::ListValue* args);
292 void ListFileEntries(const base::ListValue* args);
294 // The last event sent to the JavaScript side.
295 int last_sent_event_id_;
297 base::WeakPtrFactory<DriveInternalsWebUIHandler> weak_ptr_factory_;
298 DISALLOW_COPY_AND_ASSIGN(DriveInternalsWebUIHandler);
301 void DriveInternalsWebUIHandler::OnGetAboutResource(
302 google_apis::GDataErrorCode status,
303 scoped_ptr<google_apis::AboutResource> parsed_about_resource) {
304 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
306 if (status != google_apis::HTTP_SUCCESS) {
307 LOG(ERROR) << "Failed to get about resource";
310 DCHECK(parsed_about_resource);
312 base::DictionaryValue about_resource;
313 about_resource.SetDouble("account-quota-total",
314 parsed_about_resource->quota_bytes_total());
315 about_resource.SetDouble("account-quota-used",
316 parsed_about_resource->quota_bytes_used());
317 about_resource.SetDouble("account-largest-changestamp-remote",
318 parsed_about_resource->largest_change_id());
319 about_resource.SetString("root-resource-id",
320 parsed_about_resource->root_folder_id());
322 web_ui()->CallJavascriptFunction("updateAboutResource", about_resource);
325 void DriveInternalsWebUIHandler::OnGetAppList(
326 google_apis::GDataErrorCode status,
327 scoped_ptr<google_apis::AppList> parsed_app_list) {
328 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
330 if (status != google_apis::HTTP_SUCCESS) {
331 LOG(ERROR) << "Failed to get app list";
334 DCHECK(parsed_app_list);
336 base::DictionaryValue app_list;
337 app_list.SetString("etag", parsed_app_list->etag());
339 base::ListValue* items = new base::ListValue();
340 for (size_t i = 0; i < parsed_app_list->items().size(); ++i) {
341 const google_apis::AppResource* app = parsed_app_list->items()[i];
342 base::DictionaryValue* app_data = new base::DictionaryValue();
343 app_data->SetString("name", app->name());
344 app_data->SetString("application_id", app->application_id());
345 app_data->SetString("object_type", app->object_type());
346 app_data->SetBoolean("supports_create", app->supports_create());
348 items->Append(app_data);
350 app_list.Set("items", items);
352 web_ui()->CallJavascriptFunction("updateAppList", app_list);
355 void DriveInternalsWebUIHandler::RegisterMessages() {
356 web_ui()->RegisterMessageCallback(
358 base::Bind(&DriveInternalsWebUIHandler::OnPageLoaded,
359 weak_ptr_factory_.GetWeakPtr()));
360 web_ui()->RegisterMessageCallback(
362 base::Bind(&DriveInternalsWebUIHandler::OnPeriodicUpdate,
363 weak_ptr_factory_.GetWeakPtr()));
364 web_ui()->RegisterMessageCallback(
366 base::Bind(&DriveInternalsWebUIHandler::ClearAccessToken,
367 weak_ptr_factory_.GetWeakPtr()));
368 web_ui()->RegisterMessageCallback(
370 base::Bind(&DriveInternalsWebUIHandler::ClearRefreshToken,
371 weak_ptr_factory_.GetWeakPtr()));
372 web_ui()->RegisterMessageCallback(
374 base::Bind(&DriveInternalsWebUIHandler::ListFileEntries,
375 weak_ptr_factory_.GetWeakPtr()));
378 drive::DriveIntegrationService*
379 DriveInternalsWebUIHandler::GetIntegrationService() {
380 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
382 Profile* profile = Profile::FromWebUI(web_ui());
383 drive::DriveIntegrationService* service =
384 drive::DriveIntegrationServiceFactory::FindForProfile(profile);
385 if (!service || !service->is_enabled())
390 drive::DriveServiceInterface* DriveInternalsWebUIHandler::GetDriveService() {
391 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
393 Profile* profile = Profile::FromWebUI(web_ui());
394 return drive::util::GetDriveServiceByProfile(profile);
397 drive::FileSystemInterface* DriveInternalsWebUIHandler::GetFileSystem() {
398 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
400 Profile* profile = Profile::FromWebUI(web_ui());
401 return drive::util::GetFileSystemByProfile(profile);
404 void DriveInternalsWebUIHandler::OnPageLoaded(const base::ListValue* args) {
405 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
407 drive::DriveIntegrationService* integration_service =
408 GetIntegrationService();
409 // |integration_service| may be NULL in the guest/incognito mode.
410 if (!integration_service)
413 drive::DriveServiceInterface* drive_service =
414 integration_service->drive_service();
415 DCHECK(drive_service);
416 drive::DebugInfoCollector* debug_info_collector =
417 integration_service->debug_info_collector();
418 DCHECK(debug_info_collector);
420 UpdateDriveRelatedFlagsSection();
421 UpdateDriveRelatedPreferencesSection();
422 UpdateAuthStatusSection(drive_service);
423 UpdateAboutResourceSection(drive_service);
424 UpdateAppListSection(drive_service);
425 UpdateLocalMetadataSection(debug_info_collector);
426 UpdateDeltaUpdateStatusSection(debug_info_collector);
427 UpdateInFlightOperationsSection(integration_service->job_list());
428 UpdateGCacheContentsSection();
429 UpdateCacheContentsSection(debug_info_collector);
430 UpdateLocalStorageUsageSection();
432 // When the drive-internals page is reloaded by the reload key, the page
433 // content is recreated, but this WebUI object is not (instead, OnPageLoaded
434 // is called again). In that case, we have to forget the last sent ID here,
435 // and resent whole the logs to the page.
436 last_sent_event_id_ = -1;
437 UpdateEventLogSection();
440 void DriveInternalsWebUIHandler::UpdateDriveRelatedFlagsSection() {
441 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
443 const char* kDriveRelatedFlags[] = {
444 drive::switches::kEnableDriveV2Api,
445 chromeos::switches::kDisableDrive,
448 base::ListValue flags;
449 for (size_t i = 0; i < arraysize(kDriveRelatedFlags); ++i) {
450 const std::string key = kDriveRelatedFlags[i];
451 std::string value = "(not set)";
452 if (CommandLine::ForCurrentProcess()->HasSwitch(key))
453 value = CommandLine::ForCurrentProcess()->GetSwitchValueASCII(key);
454 base::DictionaryValue* flag = new DictionaryValue;
455 flag->SetString("key", key);
456 flag->SetString("value", value.empty() ? "(set)" : value);
460 web_ui()->CallJavascriptFunction("updateDriveRelatedFlags", flags);
463 void DriveInternalsWebUIHandler::UpdateDriveRelatedPreferencesSection() {
464 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
466 const char* kDriveRelatedPreferences[] = {
467 prefs::kDisableDrive,
468 prefs::kDisableDriveOverCellular,
469 prefs::kDisableDriveHostedFiles,
472 Profile* profile = Profile::FromWebUI(web_ui());
473 PrefService* pref_service = profile->GetPrefs();
475 base::ListValue preferences;
476 for (size_t i = 0; i < arraysize(kDriveRelatedPreferences); ++i) {
477 const std::string key = kDriveRelatedPreferences[i];
478 // As of now, all preferences are boolean.
479 const std::string value =
480 (pref_service->GetBoolean(key.c_str()) ? "true" : "false");
481 base::DictionaryValue* preference = new DictionaryValue;
482 preference->SetString("key", key);
483 preference->SetString("value", value);
484 preferences.Append(preference);
487 web_ui()->CallJavascriptFunction("updateDriveRelatedPreferences",
491 void DriveInternalsWebUIHandler::UpdateAuthStatusSection(
492 drive::DriveServiceInterface* drive_service) {
493 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
494 DCHECK(drive_service);
496 base::DictionaryValue auth_status;
497 auth_status.SetBoolean("has-refresh-token",
498 drive_service->HasRefreshToken());
499 auth_status.SetBoolean("has-access-token",
500 drive_service->HasAccessToken());
501 web_ui()->CallJavascriptFunction("updateAuthStatus", auth_status);
504 void DriveInternalsWebUIHandler::UpdateAboutResourceSection(
505 drive::DriveServiceInterface* drive_service) {
506 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
507 DCHECK(drive_service);
509 drive_service->GetAboutResource(
510 base::Bind(&DriveInternalsWebUIHandler::OnGetAboutResource,
511 weak_ptr_factory_.GetWeakPtr()));
514 void DriveInternalsWebUIHandler::UpdateAppListSection(
515 drive::DriveServiceInterface* drive_service) {
516 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
517 DCHECK(drive_service);
519 drive_service->GetAppList(
520 base::Bind(&DriveInternalsWebUIHandler::OnGetAppList,
521 weak_ptr_factory_.GetWeakPtr()));
524 void DriveInternalsWebUIHandler::UpdateLocalMetadataSection(
525 drive::DebugInfoCollector* debug_info_collector) {
526 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
527 DCHECK(debug_info_collector);
529 debug_info_collector->GetMetadata(
530 base::Bind(&DriveInternalsWebUIHandler::OnGetFilesystemMetadataForLocal,
531 weak_ptr_factory_.GetWeakPtr()));
534 void DriveInternalsWebUIHandler::OnGetFilesystemMetadataForLocal(
535 const drive::FileSystemMetadata& metadata) {
536 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
538 base::DictionaryValue local_metadata;
539 local_metadata.SetDouble("account-largest-changestamp-local",
540 metadata.largest_changestamp);
541 local_metadata.SetBoolean("account-metadata-refreshing", metadata.refreshing);
542 web_ui()->CallJavascriptFunction("updateLocalMetadata", local_metadata);
545 void DriveInternalsWebUIHandler::ClearAccessToken(const base::ListValue* args) {
546 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
548 drive::DriveServiceInterface* drive_service = GetDriveService();
550 drive_service->ClearAccessToken();
553 void DriveInternalsWebUIHandler::ClearRefreshToken(
554 const base::ListValue* args) {
555 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
557 drive::DriveServiceInterface* drive_service = GetDriveService();
559 drive_service->ClearRefreshToken();
562 void DriveInternalsWebUIHandler::ListFileEntries(const base::ListValue* args) {
563 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
565 UpdateFileSystemContentsSection();
568 void DriveInternalsWebUIHandler::UpdateDeltaUpdateStatusSection(
569 drive::DebugInfoCollector* debug_info_collector) {
570 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
571 DCHECK(debug_info_collector);
573 debug_info_collector->GetMetadata(
575 &DriveInternalsWebUIHandler::OnGetFilesystemMetadataForDeltaUpdate,
576 weak_ptr_factory_.GetWeakPtr()));
579 void DriveInternalsWebUIHandler::OnGetFilesystemMetadataForDeltaUpdate(
580 const drive::FileSystemMetadata& metadata) {
581 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
583 Profile* profile = Profile::FromWebUI(web_ui());
584 drive::DriveNotificationManager* drive_notification_manager =
585 drive::DriveNotificationManagerFactory::GetForBrowserContext(profile);
586 if (!drive_notification_manager)
589 base::DictionaryValue delta_update_status;
590 delta_update_status.SetBoolean(
591 "push-notification-enabled",
592 drive_notification_manager->push_notification_enabled());
593 delta_update_status.SetString(
594 "last-update-check-time",
595 google_apis::util::FormatTimeAsStringLocaltime(
596 metadata.last_update_check_time));
597 delta_update_status.SetString(
598 "last-update-check-error",
599 drive::FileErrorToString(metadata.last_update_check_error));
601 web_ui()->CallJavascriptFunction("updateDeltaUpdateStatus",
602 delta_update_status);
605 void DriveInternalsWebUIHandler::UpdateInFlightOperationsSection(
606 drive::JobListInterface* job_list) {
607 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
610 std::vector<drive::JobInfo> info_list = job_list->GetJobInfoList();
612 base::ListValue in_flight_operations;
613 for (size_t i = 0; i < info_list.size(); ++i) {
614 const drive::JobInfo& info = info_list[i];
616 base::DictionaryValue* dict = new DictionaryValue;
617 dict->SetInteger("id", info.job_id);
618 dict->SetString("type", drive::JobTypeToString(info.job_type));
619 dict->SetString("file_path", info.file_path.AsUTF8Unsafe());
620 dict->SetString("state", drive::JobStateToString(info.state));
621 dict->SetDouble("progress_current", info.num_completed_bytes);
622 dict->SetDouble("progress_total", info.num_total_bytes);
623 in_flight_operations.Append(dict);
625 web_ui()->CallJavascriptFunction("updateInFlightOperations",
626 in_flight_operations);
629 void DriveInternalsWebUIHandler::UpdateGCacheContentsSection() {
630 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
632 // Start updating the GCache contents section.
633 Profile* profile = Profile::FromWebUI(web_ui());
634 const base::FilePath root_path = drive::util::GetCacheRootPath(profile);
635 base::ListValue* gcache_contents = new ListValue;
636 base::DictionaryValue* gcache_summary = new DictionaryValue;
637 BrowserThread::PostBlockingPoolTaskAndReply(
639 base::Bind(&GetGCacheContents,
643 base::Bind(&DriveInternalsWebUIHandler::OnGetGCacheContents,
644 weak_ptr_factory_.GetWeakPtr(),
645 base::Owned(gcache_contents),
646 base::Owned(gcache_summary)));
649 void DriveInternalsWebUIHandler::UpdateFileSystemContentsSection() {
650 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
652 drive::DriveServiceInterface* drive_service = GetDriveService();
653 drive::FileSystemInterface* file_system = GetFileSystem();
654 if (!drive_service || !file_system)
657 // Start updating the file system tree section, if we have access token.
658 if (!drive_service->HasAccessToken())
661 // Start rendering the file system tree as text.
662 const base::FilePath root_path = drive::util::GetDriveGrandRootPath();
664 file_system->GetResourceEntryByPath(
666 base::Bind(&DriveInternalsWebUIHandler::OnGetResourceEntryByPath,
667 weak_ptr_factory_.GetWeakPtr(),
670 file_system->ReadDirectoryByPath(
672 base::Bind(&DriveInternalsWebUIHandler::OnReadDirectoryByPath,
673 weak_ptr_factory_.GetWeakPtr(),
677 void DriveInternalsWebUIHandler::UpdateLocalStorageUsageSection() {
678 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
680 // Propagate the amount of local free space in bytes.
681 base::FilePath home_path;
682 if (PathService::Get(base::DIR_HOME, &home_path)) {
683 base::DictionaryValue* local_storage_summary = new DictionaryValue;
684 BrowserThread::PostBlockingPoolTaskAndReply(
686 base::Bind(&GetFreeDiskSpace, home_path, local_storage_summary),
687 base::Bind(&DriveInternalsWebUIHandler::OnGetFreeDiskSpace,
688 weak_ptr_factory_.GetWeakPtr(),
689 base::Owned(local_storage_summary)));
691 LOG(ERROR) << "Home directory not found";
695 void DriveInternalsWebUIHandler::UpdateCacheContentsSection(
696 drive::DebugInfoCollector* debug_info_collector) {
697 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
698 DCHECK(debug_info_collector);
700 debug_info_collector->IterateFileCache(
701 base::Bind(&DriveInternalsWebUIHandler::UpdateCacheEntry,
702 weak_ptr_factory_.GetWeakPtr()),
703 base::Bind(&base::DoNothing));
706 void DriveInternalsWebUIHandler::UpdateEventLogSection() {
707 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
709 const std::vector<drive::EventLogger::Event> log =
710 drive::util::GetLogHistory();
712 base::ListValue list;
713 for (size_t i = 0; i < log.size(); ++i) {
714 // Skip events which were already sent.
715 if (log[i].id <= last_sent_event_id_)
718 std::string severity = SeverityToString(log[i].severity);
720 base::DictionaryValue* dict = new DictionaryValue;
721 dict->SetString("key",
722 google_apis::util::FormatTimeAsStringLocaltime(log[i].when));
723 dict->SetString("value", "[" + severity + "] " + log[i].what);
724 dict->SetString("class", "log-" + severity);
726 last_sent_event_id_ = log[i].id;
729 web_ui()->CallJavascriptFunction("updateEventLog", list);
732 void DriveInternalsWebUIHandler::OnGetGCacheContents(
733 base::ListValue* gcache_contents,
734 base::DictionaryValue* gcache_summary) {
735 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
736 DCHECK(gcache_contents);
737 DCHECK(gcache_summary);
739 web_ui()->CallJavascriptFunction("updateGCacheContents",
744 void DriveInternalsWebUIHandler::OnGetResourceEntryByPath(
745 const base::FilePath& path,
746 drive::FileError error,
747 scoped_ptr<drive::ResourceEntry> entry) {
748 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
750 if (error == drive::FILE_ERROR_OK) {
752 const base::StringValue value(FormatEntry(path, *entry) + "\n");
753 web_ui()->CallJavascriptFunction("updateFileSystemContents", value);
757 void DriveInternalsWebUIHandler::OnReadDirectoryByPath(
758 const base::FilePath& parent_path,
759 drive::FileError error,
760 scoped_ptr<drive::ResourceEntryVector> entries) {
761 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
763 if (error == drive::FILE_ERROR_OK) {
764 DCHECK(entries.get());
766 drive::FileSystemInterface* file_system = GetFileSystem();
767 std::string file_system_as_text;
768 for (size_t i = 0; i < entries->size(); ++i) {
769 const drive::ResourceEntry& entry = (*entries)[i];
770 const base::FilePath current_path = parent_path.Append(
771 base::FilePath::FromUTF8Unsafe(entry.base_name()));
773 file_system_as_text.append(FormatEntry(current_path, entry) + "\n");
775 if (entry.file_info().is_directory()) {
776 file_system->ReadDirectoryByPath(
778 base::Bind(&DriveInternalsWebUIHandler::OnReadDirectoryByPath,
779 weak_ptr_factory_.GetWeakPtr(),
784 // There may be pending ReadDirectoryByPath() calls, but we can update
785 // the page with what we have now. This results in progressive
786 // updates, which is good for a large file system.
787 const base::StringValue value(file_system_as_text);
788 web_ui()->CallJavascriptFunction("updateFileSystemContents", value);
792 void DriveInternalsWebUIHandler::UpdateCacheEntry(
793 const std::string& local_id,
794 const drive::FileCacheEntry& cache_entry) {
795 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
797 // Convert |cache_entry| into a dictionary.
798 base::DictionaryValue value;
799 value.SetString("local_id", local_id);
800 value.SetString("md5", cache_entry.md5());
801 value.SetBoolean("is_present", cache_entry.is_present());
802 value.SetBoolean("is_pinned", cache_entry.is_pinned());
803 value.SetBoolean("is_dirty", cache_entry.is_dirty());
805 web_ui()->CallJavascriptFunction("updateCacheContents", value);
808 void DriveInternalsWebUIHandler::OnGetFreeDiskSpace(
809 base::DictionaryValue* local_storage_summary) {
810 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
811 DCHECK(local_storage_summary);
813 web_ui()->CallJavascriptFunction(
814 "updateLocalStorageUsage", *local_storage_summary);
817 void DriveInternalsWebUIHandler::OnPeriodicUpdate(const base::ListValue* args) {
818 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
820 drive::DriveIntegrationService* integration_service =
821 GetIntegrationService();
822 // |integration_service| may be NULL in the guest/incognito mode.
823 if (!integration_service)
826 UpdateInFlightOperationsSection(integration_service->job_list());
827 UpdateEventLogSection();
832 DriveInternalsUI::DriveInternalsUI(content::WebUI* web_ui)
833 : WebUIController(web_ui) {
834 web_ui->AddMessageHandler(new DriveInternalsWebUIHandler());
836 content::WebUIDataSource* source =
837 content::WebUIDataSource::Create(chrome::kChromeUIDriveInternalsHost);
838 source->AddResourcePath("drive_internals.css", IDR_DRIVE_INTERNALS_CSS);
839 source->AddResourcePath("drive_internals.js", IDR_DRIVE_INTERNALS_JS);
840 source->SetDefaultResource(IDR_DRIVE_INTERNALS_HTML);
842 Profile* profile = Profile::FromWebUI(web_ui);
843 content::WebUIDataSource::Add(profile, source);
846 } // namespace chromeos