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/files/file_enumerator.h"
9 #include "base/files/file_util.h"
10 #include "base/format_macros.h"
11 #include "base/memory/weak_ptr.h"
12 #include "base/path_service.h"
13 #include "base/prefs/pref_service.h"
14 #include "base/strings/stringprintf.h"
15 #include "base/sys_info.h"
16 #include "chrome/browser/chromeos/drive/debug_info_collector.h"
17 #include "chrome/browser/chromeos/drive/drive_integration_service.h"
18 #include "chrome/browser/chromeos/drive/file_system_util.h"
19 #include "chrome/browser/chromeos/file_manager/path_util.h"
20 #include "chrome/browser/drive/drive_notification_manager_factory.h"
21 #include "chrome/browser/profiles/profile.h"
22 #include "chrome/common/pref_names.h"
23 #include "chrome/common/url_constants.h"
24 #include "components/drive/drive.pb.h"
25 #include "components/drive/drive_api_util.h"
26 #include "components/drive/drive_notification_manager.h"
27 #include "components/drive/drive_pref_names.h"
28 #include "components/drive/event_logger.h"
29 #include "components/drive/job_list.h"
30 #include "components/drive/service/drive_service_interface.h"
31 #include "content/public/browser/browser_thread.h"
32 #include "content/public/browser/web_ui.h"
33 #include "content/public/browser/web_ui_data_source.h"
34 #include "content/public/browser/web_ui_message_handler.h"
35 #include "google_apis/drive/auth_service.h"
36 #include "google_apis/drive/drive_api_error_codes.h"
37 #include "google_apis/drive/drive_api_parser.h"
38 #include "google_apis/drive/time_util.h"
39 #include "grit/browser_resources.h"
41 using content::BrowserThread
;
47 // Gets metadata of all files and directories in |root_path|
48 // recursively. Stores the result as a list of dictionaries like:
50 // [{ path: 'GCache/v1/tmp/<local_id>',
52 // is_directory: false,
53 // last_modified: '2005-08-09T09:57:00-08:00',
56 // The list is sorted by the path.
57 void GetGCacheContents(const base::FilePath
& root_path
,
58 base::ListValue
* gcache_contents
,
59 base::DictionaryValue
* gcache_summary
) {
60 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI
));
61 DCHECK(gcache_contents
);
62 DCHECK(gcache_summary
);
64 // Use this map to sort the result list by the path.
65 std::map
<base::FilePath
, base::DictionaryValue
*> files
;
67 const int options
= (base::FileEnumerator::FILES
|
68 base::FileEnumerator::DIRECTORIES
|
69 base::FileEnumerator::SHOW_SYM_LINKS
);
70 base::FileEnumerator
enumerator(root_path
, true /* recursive */, options
);
73 for (base::FilePath current
= enumerator
.Next(); !current
.empty();
74 current
= enumerator
.Next()) {
75 base::FileEnumerator::FileInfo info
= enumerator
.GetInfo();
76 int64 size
= info
.GetSize();
77 const bool is_directory
= info
.IsDirectory();
78 const bool is_symbolic_link
= base::IsLink(info
.GetName());
79 const base::Time last_modified
= info
.GetLastModifiedTime();
81 base::DictionaryValue
* entry
= new base::DictionaryValue
;
82 entry
->SetString("path", current
.value());
83 // Use double instead of integer for large files.
84 entry
->SetDouble("size", size
);
85 entry
->SetBoolean("is_directory", is_directory
);
86 entry
->SetBoolean("is_symbolic_link", is_symbolic_link
);
89 google_apis::util::FormatTimeAsStringLocaltime(last_modified
));
90 // Print lower 9 bits in octal format.
93 base::StringPrintf("%03o", info
.stat().st_mode
& 0x1ff));
94 files
[current
] = entry
;
99 // Convert |files| into |gcache_contents|.
100 for (std::map
<base::FilePath
, base::DictionaryValue
*>::const_iterator
101 iter
= files
.begin(); iter
!= files
.end(); ++iter
) {
102 gcache_contents
->Append(iter
->second
);
105 gcache_summary
->SetDouble("total_size", total_size
);
108 // Gets the available disk space for the path |home_path|.
109 void GetFreeDiskSpace(const base::FilePath
& home_path
,
110 base::DictionaryValue
* local_storage_summary
) {
111 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI
));
112 DCHECK(local_storage_summary
);
114 const int64 free_space
= base::SysInfo::AmountOfFreeDiskSpace(home_path
);
115 local_storage_summary
->SetDouble("free_space", free_space
);
118 // Formats |entry| into text.
119 std::string
FormatEntry(const base::FilePath
& path
,
120 const drive::ResourceEntry
& entry
) {
121 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
123 using base::StringAppendF
;
126 StringAppendF(&out
, "%s\n", path
.AsUTF8Unsafe().c_str());
127 StringAppendF(&out
, " title: %s\n", entry
.title().c_str());
128 StringAppendF(&out
, " local_id: %s\n", entry
.local_id().c_str());
129 StringAppendF(&out
, " resource_id: %s\n", entry
.resource_id().c_str());
130 StringAppendF(&out
, " parent_local_id: %s\n",
131 entry
.parent_local_id().c_str());
132 StringAppendF(&out
, " shared: %s\n", entry
.shared() ? "true" : "false");
133 StringAppendF(&out
, " shared_with_me: %s\n",
134 entry
.shared_with_me() ? "true" : "false");
136 const drive::PlatformFileInfoProto
& file_info
= entry
.file_info();
137 StringAppendF(&out
, " file_info\n");
138 StringAppendF(&out
, " size: %" PRId64
"\n", file_info
.size());
139 StringAppendF(&out
, " is_directory: %d\n", file_info
.is_directory());
140 StringAppendF(&out
, " is_symbolic_link: %d\n",
141 file_info
.is_symbolic_link());
143 const base::Time last_modified
= base::Time::FromInternalValue(
144 file_info
.last_modified());
145 const base::Time last_accessed
= base::Time::FromInternalValue(
146 file_info
.last_accessed());
147 const base::Time creation_time
= base::Time::FromInternalValue(
148 file_info
.creation_time());
149 StringAppendF(&out
, " last_modified: %s\n",
150 google_apis::util::FormatTimeAsString(last_modified
).c_str());
151 StringAppendF(&out
, " last_accessed: %s\n",
152 google_apis::util::FormatTimeAsString(last_accessed
).c_str());
153 StringAppendF(&out
, " creation_time: %s\n",
154 google_apis::util::FormatTimeAsString(creation_time
).c_str());
156 if (entry
.has_file_specific_info()) {
157 const drive::FileSpecificInfo
& file_specific_info
=
158 entry
.file_specific_info();
159 StringAppendF(&out
, " alternate_url: %s\n",
160 file_specific_info
.alternate_url().c_str());
161 StringAppendF(&out
, " content_mime_type: %s\n",
162 file_specific_info
.content_mime_type().c_str());
163 StringAppendF(&out
, " file_md5: %s\n",
164 file_specific_info
.md5().c_str());
165 StringAppendF(&out
, " document_extension: %s\n",
166 file_specific_info
.document_extension().c_str());
167 StringAppendF(&out
, " is_hosted_document: %d\n",
168 file_specific_info
.is_hosted_document());
171 if (entry
.has_directory_specific_info()) {
172 StringAppendF(&out
, " directory_info\n");
173 const drive::DirectorySpecificInfo
& directory_specific_info
=
174 entry
.directory_specific_info();
175 StringAppendF(&out
, " changestamp: %" PRId64
"\n",
176 directory_specific_info
.changestamp());
182 std::string
SeverityToString(logging::LogSeverity severity
) {
184 case logging::LOG_INFO
:
186 case logging::LOG_WARNING
:
188 case logging::LOG_ERROR
:
190 default: // Treat all other higher severities as ERROR.
195 // Appends {'key': key, 'value': value} dictionary to the |list|.
196 void AppendKeyValue(base::ListValue
* list
,
197 const std::string
& key
,
198 const std::string
& value
) {
199 base::DictionaryValue
* dict
= new base::DictionaryValue
;
200 dict
->SetString("key", key
);
201 dict
->SetString("value", value
);
205 // Class to handle messages from chrome://drive-internals.
206 class DriveInternalsWebUIHandler
: public content::WebUIMessageHandler
{
208 DriveInternalsWebUIHandler()
209 : last_sent_event_id_(-1),
210 weak_ptr_factory_(this) {
213 ~DriveInternalsWebUIHandler() override
{}
216 // WebUIMessageHandler override.
217 void RegisterMessages() override
;
219 // Returns a DriveIntegrationService.
220 drive::DriveIntegrationService
* GetIntegrationService();
222 // Returns a DriveService instance.
223 drive::DriveServiceInterface
* GetDriveService();
225 // Returns a DebugInfoCollector instance.
226 drive::DebugInfoCollector
* GetDebugInfoCollector();
228 // Called when the page is first loaded.
229 void OnPageLoaded(const base::ListValue
* args
);
231 // Updates respective sections.
232 void UpdateDriveRelatedPreferencesSection();
233 void UpdateConnectionStatusSection(
234 drive::DriveServiceInterface
* drive_service
);
235 void UpdateAboutResourceSection(
236 drive::DriveServiceInterface
* drive_service
);
237 void UpdateAppListSection(
238 drive::DriveServiceInterface
* drive_service
);
239 void UpdateLocalMetadataSection(
240 drive::DebugInfoCollector
* debug_info_collector
);
241 void UpdateDeltaUpdateStatusSection(
242 drive::DebugInfoCollector
* debug_info_collector
);
243 void UpdateInFlightOperationsSection(drive::JobListInterface
* job_list
);
244 void UpdateGCacheContentsSection();
245 void UpdateFileSystemContentsSection();
246 void UpdateLocalStorageUsageSection();
247 void UpdateCacheContentsSection(
248 drive::DebugInfoCollector
* debug_info_collector
);
249 void UpdateEventLogSection();
250 void UpdatePathConfigurationsSection();
252 // Called when GetGCacheContents() is complete.
253 void OnGetGCacheContents(base::ListValue
* gcache_contents
,
254 base::DictionaryValue
* cache_summary
);
256 // Called when GetResourceEntryByPath() is complete.
257 void OnGetResourceEntryByPath(const base::FilePath
& path
,
258 drive::FileError error
,
259 scoped_ptr
<drive::ResourceEntry
> entry
);
261 // Called when ReadDirectoryByPath() is complete.
262 void OnReadDirectoryByPath(const base::FilePath
& parent_path
,
263 drive::FileError error
,
264 scoped_ptr
<drive::ResourceEntryVector
> entries
);
266 // Called as the iterator for DebugInfoCollector::IterateFileCache().
267 void UpdateCacheEntry(const std::string
& local_id
,
268 const drive::FileCacheEntry
& cache_entry
);
270 // Called when GetFreeDiskSpace() is complete.
271 void OnGetFreeDiskSpace(base::DictionaryValue
* local_storage_summary
);
273 // Called when GetAboutResource() call to DriveService is complete.
274 void OnGetAboutResource(
275 google_apis::DriveApiErrorCode status
,
276 scoped_ptr
<google_apis::AboutResource
> about_resource
);
278 // Called when GetAppList() call to DriveService is complete.
280 google_apis::DriveApiErrorCode status
,
281 scoped_ptr
<google_apis::AppList
> app_list
);
283 // Callback for DebugInfoCollector::GetMetadata for local update.
284 void OnGetFilesystemMetadataForLocal(
285 const drive::FileSystemMetadata
& metadata
);
287 // Callback for DebugInfoCollector::GetMetadata for delta update.
288 void OnGetFilesystemMetadataForDeltaUpdate(
289 const drive::FileSystemMetadata
& metadata
);
291 // Called when the page requests periodic update.
292 void OnPeriodicUpdate(const base::ListValue
* args
);
294 // Called when the corresponding button on the page is pressed.
295 void ClearAccessToken(const base::ListValue
* args
);
296 void ClearRefreshToken(const base::ListValue
* args
);
297 void ResetDriveFileSystem(const base::ListValue
* args
);
298 void ListFileEntries(const base::ListValue
* args
);
300 // Called after file system reset for ResetDriveFileSystem is done.
301 void ResetFinished(bool success
);
303 // The last event sent to the JavaScript side.
304 int last_sent_event_id_
;
306 base::WeakPtrFactory
<DriveInternalsWebUIHandler
> weak_ptr_factory_
;
307 DISALLOW_COPY_AND_ASSIGN(DriveInternalsWebUIHandler
);
310 void DriveInternalsWebUIHandler::OnGetAboutResource(
311 google_apis::DriveApiErrorCode status
,
312 scoped_ptr
<google_apis::AboutResource
> parsed_about_resource
) {
313 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
315 if (status
!= google_apis::HTTP_SUCCESS
) {
316 LOG(ERROR
) << "Failed to get about resource";
319 DCHECK(parsed_about_resource
);
321 base::DictionaryValue about_resource
;
322 about_resource
.SetDouble("account-quota-total",
323 parsed_about_resource
->quota_bytes_total());
324 about_resource
.SetDouble("account-quota-used",
325 parsed_about_resource
->quota_bytes_used_aggregate());
326 about_resource
.SetDouble("account-largest-changestamp-remote",
327 parsed_about_resource
->largest_change_id());
328 about_resource
.SetString("root-resource-id",
329 parsed_about_resource
->root_folder_id());
331 web_ui()->CallJavascriptFunction("updateAboutResource", about_resource
);
334 void DriveInternalsWebUIHandler::OnGetAppList(
335 google_apis::DriveApiErrorCode status
,
336 scoped_ptr
<google_apis::AppList
> parsed_app_list
) {
337 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
339 if (status
!= google_apis::HTTP_SUCCESS
) {
340 LOG(ERROR
) << "Failed to get app list";
343 DCHECK(parsed_app_list
);
345 base::DictionaryValue app_list
;
346 app_list
.SetString("etag", parsed_app_list
->etag());
348 base::ListValue
* items
= new base::ListValue();
349 for (size_t i
= 0; i
< parsed_app_list
->items().size(); ++i
) {
350 const google_apis::AppResource
* app
= parsed_app_list
->items()[i
];
351 base::DictionaryValue
* app_data
= new base::DictionaryValue();
352 app_data
->SetString("name", app
->name());
353 app_data
->SetString("application_id", app
->application_id());
354 app_data
->SetString("object_type", app
->object_type());
355 app_data
->SetBoolean("supports_create", app
->supports_create());
357 items
->Append(app_data
);
359 app_list
.Set("items", items
);
361 web_ui()->CallJavascriptFunction("updateAppList", app_list
);
364 void DriveInternalsWebUIHandler::RegisterMessages() {
365 web_ui()->RegisterMessageCallback(
367 base::Bind(&DriveInternalsWebUIHandler::OnPageLoaded
,
368 weak_ptr_factory_
.GetWeakPtr()));
369 web_ui()->RegisterMessageCallback(
371 base::Bind(&DriveInternalsWebUIHandler::OnPeriodicUpdate
,
372 weak_ptr_factory_
.GetWeakPtr()));
373 web_ui()->RegisterMessageCallback(
375 base::Bind(&DriveInternalsWebUIHandler::ClearAccessToken
,
376 weak_ptr_factory_
.GetWeakPtr()));
377 web_ui()->RegisterMessageCallback(
379 base::Bind(&DriveInternalsWebUIHandler::ClearRefreshToken
,
380 weak_ptr_factory_
.GetWeakPtr()));
381 web_ui()->RegisterMessageCallback(
382 "resetDriveFileSystem",
383 base::Bind(&DriveInternalsWebUIHandler::ResetDriveFileSystem
,
384 weak_ptr_factory_
.GetWeakPtr()));
385 web_ui()->RegisterMessageCallback(
387 base::Bind(&DriveInternalsWebUIHandler::ListFileEntries
,
388 weak_ptr_factory_
.GetWeakPtr()));
391 drive::DriveIntegrationService
*
392 DriveInternalsWebUIHandler::GetIntegrationService() {
393 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
395 Profile
* profile
= Profile::FromWebUI(web_ui());
396 drive::DriveIntegrationService
* service
=
397 drive::DriveIntegrationServiceFactory::FindForProfile(profile
);
398 if (!service
|| !service
->is_enabled())
403 drive::DriveServiceInterface
* DriveInternalsWebUIHandler::GetDriveService() {
404 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
406 Profile
* profile
= Profile::FromWebUI(web_ui());
407 return drive::util::GetDriveServiceByProfile(profile
);
410 drive::DebugInfoCollector
* DriveInternalsWebUIHandler::GetDebugInfoCollector() {
411 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
413 drive::DriveIntegrationService
* integration_service
= GetIntegrationService();
414 return integration_service
?
415 integration_service
->debug_info_collector() : NULL
;
418 void DriveInternalsWebUIHandler::OnPageLoaded(const base::ListValue
* args
) {
419 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
421 drive::DriveIntegrationService
* integration_service
=
422 GetIntegrationService();
423 // |integration_service| may be NULL in the guest/incognito mode.
424 if (!integration_service
)
427 drive::DriveServiceInterface
* drive_service
=
428 integration_service
->drive_service();
429 DCHECK(drive_service
);
430 drive::DebugInfoCollector
* debug_info_collector
=
431 integration_service
->debug_info_collector();
432 DCHECK(debug_info_collector
);
434 UpdateDriveRelatedPreferencesSection();
435 UpdateConnectionStatusSection(drive_service
);
436 UpdateAboutResourceSection(drive_service
);
437 UpdateAppListSection(drive_service
);
438 UpdateLocalMetadataSection(debug_info_collector
);
439 UpdateDeltaUpdateStatusSection(debug_info_collector
);
440 UpdateInFlightOperationsSection(integration_service
->job_list());
441 UpdateGCacheContentsSection();
442 UpdateCacheContentsSection(debug_info_collector
);
443 UpdateLocalStorageUsageSection();
444 UpdatePathConfigurationsSection();
446 // When the drive-internals page is reloaded by the reload key, the page
447 // content is recreated, but this WebUI object is not (instead, OnPageLoaded
448 // is called again). In that case, we have to forget the last sent ID here,
449 // and resent whole the logs to the page.
450 last_sent_event_id_
= -1;
451 UpdateEventLogSection();
454 void DriveInternalsWebUIHandler::UpdateDriveRelatedPreferencesSection() {
455 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
457 const char* kDriveRelatedPreferences
[] = {
458 drive::prefs::kDisableDrive
,
459 drive::prefs::kDisableDriveOverCellular
,
460 drive::prefs::kDisableDriveHostedFiles
,
463 Profile
* profile
= Profile::FromWebUI(web_ui());
464 PrefService
* pref_service
= profile
->GetPrefs();
466 base::ListValue preferences
;
467 for (size_t i
= 0; i
< arraysize(kDriveRelatedPreferences
); ++i
) {
468 const std::string key
= kDriveRelatedPreferences
[i
];
469 // As of now, all preferences are boolean.
470 const std::string value
=
471 (pref_service
->GetBoolean(key
.c_str()) ? "true" : "false");
472 AppendKeyValue(&preferences
, key
, value
);
475 web_ui()->CallJavascriptFunction("updateDriveRelatedPreferences",
479 void DriveInternalsWebUIHandler::UpdateConnectionStatusSection(
480 drive::DriveServiceInterface
* drive_service
) {
481 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
482 DCHECK(drive_service
);
485 switch (drive::util::GetDriveConnectionStatus(Profile::FromWebUI(web_ui()))) {
486 case drive::util::DRIVE_DISCONNECTED_NOSERVICE
:
487 status
= "no service";
489 case drive::util::DRIVE_DISCONNECTED_NONETWORK
:
490 status
= "no network";
492 case drive::util::DRIVE_DISCONNECTED_NOTREADY
:
493 status
= "not ready";
495 case drive::util::DRIVE_CONNECTED_METERED
:
498 case drive::util::DRIVE_CONNECTED
:
499 status
= "connected";
503 base::DictionaryValue connection_status
;
504 connection_status
.SetString("status", status
);
505 connection_status
.SetBoolean("has-refresh-token",
506 drive_service
->HasRefreshToken());
507 connection_status
.SetBoolean("has-access-token",
508 drive_service
->HasAccessToken());
509 web_ui()->CallJavascriptFunction("updateConnectionStatus", connection_status
);
512 void DriveInternalsWebUIHandler::UpdateAboutResourceSection(
513 drive::DriveServiceInterface
* drive_service
) {
514 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
515 DCHECK(drive_service
);
517 drive_service
->GetAboutResource(
518 base::Bind(&DriveInternalsWebUIHandler::OnGetAboutResource
,
519 weak_ptr_factory_
.GetWeakPtr()));
522 void DriveInternalsWebUIHandler::UpdateAppListSection(
523 drive::DriveServiceInterface
* drive_service
) {
524 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
525 DCHECK(drive_service
);
527 drive_service
->GetAppList(
528 base::Bind(&DriveInternalsWebUIHandler::OnGetAppList
,
529 weak_ptr_factory_
.GetWeakPtr()));
532 void DriveInternalsWebUIHandler::UpdateLocalMetadataSection(
533 drive::DebugInfoCollector
* debug_info_collector
) {
534 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
535 DCHECK(debug_info_collector
);
537 debug_info_collector
->GetMetadata(
538 base::Bind(&DriveInternalsWebUIHandler::OnGetFilesystemMetadataForLocal
,
539 weak_ptr_factory_
.GetWeakPtr()));
542 void DriveInternalsWebUIHandler::OnGetFilesystemMetadataForLocal(
543 const drive::FileSystemMetadata
& metadata
) {
544 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
546 base::DictionaryValue local_metadata
;
547 local_metadata
.SetDouble("account-largest-changestamp-local",
548 metadata
.largest_changestamp
);
549 local_metadata
.SetBoolean("account-metadata-refreshing", metadata
.refreshing
);
550 web_ui()->CallJavascriptFunction("updateLocalMetadata", local_metadata
);
553 void DriveInternalsWebUIHandler::ClearAccessToken(const base::ListValue
* args
) {
554 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
556 drive::DriveServiceInterface
* drive_service
= GetDriveService();
558 drive_service
->ClearAccessToken();
561 void DriveInternalsWebUIHandler::ClearRefreshToken(
562 const base::ListValue
* args
) {
563 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
565 drive::DriveServiceInterface
* drive_service
= GetDriveService();
567 drive_service
->ClearRefreshToken();
570 void DriveInternalsWebUIHandler::ResetDriveFileSystem(
571 const base::ListValue
* args
) {
572 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
574 drive::DriveIntegrationService
* integration_service
=
575 GetIntegrationService();
576 if (integration_service
) {
577 integration_service
->ClearCacheAndRemountFileSystem(
578 base::Bind(&DriveInternalsWebUIHandler::ResetFinished
,
579 weak_ptr_factory_
.GetWeakPtr()));
583 void DriveInternalsWebUIHandler::ResetFinished(bool success
) {
584 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
586 web_ui()->CallJavascriptFunction("updateResetStatus",
587 base::FundamentalValue(success
));
590 void DriveInternalsWebUIHandler::ListFileEntries(const base::ListValue
* args
) {
591 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
593 UpdateFileSystemContentsSection();
596 void DriveInternalsWebUIHandler::UpdateDeltaUpdateStatusSection(
597 drive::DebugInfoCollector
* debug_info_collector
) {
598 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
599 DCHECK(debug_info_collector
);
601 debug_info_collector
->GetMetadata(
603 &DriveInternalsWebUIHandler::OnGetFilesystemMetadataForDeltaUpdate
,
604 weak_ptr_factory_
.GetWeakPtr()));
607 void DriveInternalsWebUIHandler::OnGetFilesystemMetadataForDeltaUpdate(
608 const drive::FileSystemMetadata
& metadata
) {
609 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
611 Profile
* profile
= Profile::FromWebUI(web_ui());
612 drive::DriveNotificationManager
* drive_notification_manager
=
613 drive::DriveNotificationManagerFactory::FindForBrowserContext(profile
);
614 if (!drive_notification_manager
)
617 base::DictionaryValue delta_update_status
;
618 delta_update_status
.SetBoolean(
619 "push-notification-enabled",
620 drive_notification_manager
->push_notification_enabled());
621 delta_update_status
.SetString(
622 "last-update-check-time",
623 google_apis::util::FormatTimeAsStringLocaltime(
624 metadata
.last_update_check_time
));
625 delta_update_status
.SetString(
626 "last-update-check-error",
627 drive::FileErrorToString(metadata
.last_update_check_error
));
629 web_ui()->CallJavascriptFunction("updateDeltaUpdateStatus",
630 delta_update_status
);
633 void DriveInternalsWebUIHandler::UpdateInFlightOperationsSection(
634 drive::JobListInterface
* job_list
) {
635 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
638 std::vector
<drive::JobInfo
> info_list
= job_list
->GetJobInfoList();
640 base::ListValue in_flight_operations
;
641 for (size_t i
= 0; i
< info_list
.size(); ++i
) {
642 const drive::JobInfo
& info
= info_list
[i
];
644 base::DictionaryValue
* dict
= new base::DictionaryValue
;
645 dict
->SetInteger("id", info
.job_id
);
646 dict
->SetString("type", drive::JobTypeToString(info
.job_type
));
647 dict
->SetString("file_path", info
.file_path
.AsUTF8Unsafe());
648 dict
->SetString("state", drive::JobStateToString(info
.state
));
649 dict
->SetDouble("progress_current", info
.num_completed_bytes
);
650 dict
->SetDouble("progress_total", info
.num_total_bytes
);
651 in_flight_operations
.Append(dict
);
653 web_ui()->CallJavascriptFunction("updateInFlightOperations",
654 in_flight_operations
);
657 void DriveInternalsWebUIHandler::UpdateGCacheContentsSection() {
658 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
660 // Start updating the GCache contents section.
661 Profile
* profile
= Profile::FromWebUI(web_ui());
662 const base::FilePath root_path
= drive::util::GetCacheRootPath(profile
);
663 base::ListValue
* gcache_contents
= new base::ListValue
;
664 base::DictionaryValue
* gcache_summary
= new base::DictionaryValue
;
665 BrowserThread::PostBlockingPoolTaskAndReply(
667 base::Bind(&GetGCacheContents
,
671 base::Bind(&DriveInternalsWebUIHandler::OnGetGCacheContents
,
672 weak_ptr_factory_
.GetWeakPtr(),
673 base::Owned(gcache_contents
),
674 base::Owned(gcache_summary
)));
677 void DriveInternalsWebUIHandler::UpdateFileSystemContentsSection() {
678 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
680 drive::DebugInfoCollector
* debug_info_collector
= GetDebugInfoCollector();
681 if (!debug_info_collector
)
684 // Start rendering the file system tree as text.
685 const base::FilePath root_path
= drive::util::GetDriveGrandRootPath();
687 debug_info_collector
->GetResourceEntry(
689 base::Bind(&DriveInternalsWebUIHandler::OnGetResourceEntryByPath
,
690 weak_ptr_factory_
.GetWeakPtr(),
693 debug_info_collector
->ReadDirectory(
695 base::Bind(&DriveInternalsWebUIHandler::OnReadDirectoryByPath
,
696 weak_ptr_factory_
.GetWeakPtr(),
700 void DriveInternalsWebUIHandler::UpdateLocalStorageUsageSection() {
701 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
703 // Propagate the amount of local free space in bytes.
704 base::FilePath home_path
;
705 if (PathService::Get(base::DIR_HOME
, &home_path
)) {
706 base::DictionaryValue
* local_storage_summary
= new base::DictionaryValue
;
707 BrowserThread::PostBlockingPoolTaskAndReply(
709 base::Bind(&GetFreeDiskSpace
, home_path
, local_storage_summary
),
710 base::Bind(&DriveInternalsWebUIHandler::OnGetFreeDiskSpace
,
711 weak_ptr_factory_
.GetWeakPtr(),
712 base::Owned(local_storage_summary
)));
714 LOG(ERROR
) << "Home directory not found";
718 void DriveInternalsWebUIHandler::UpdateCacheContentsSection(
719 drive::DebugInfoCollector
* debug_info_collector
) {
720 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
721 DCHECK(debug_info_collector
);
723 debug_info_collector
->IterateFileCache(
724 base::Bind(&DriveInternalsWebUIHandler::UpdateCacheEntry
,
725 weak_ptr_factory_
.GetWeakPtr()),
726 base::Bind(&base::DoNothing
));
729 void DriveInternalsWebUIHandler::UpdateEventLogSection() {
730 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
732 drive::DriveIntegrationService
* integration_service
=
733 GetIntegrationService();
734 if (!integration_service
)
737 const std::vector
<drive::EventLogger::Event
> log
=
738 integration_service
->event_logger()->GetHistory();
740 base::ListValue list
;
741 for (size_t i
= 0; i
< log
.size(); ++i
) {
742 // Skip events which were already sent.
743 if (log
[i
].id
<= last_sent_event_id_
)
746 std::string severity
= SeverityToString(log
[i
].severity
);
748 base::DictionaryValue
* dict
= new base::DictionaryValue
;
749 dict
->SetString("key",
750 google_apis::util::FormatTimeAsStringLocaltime(log
[i
].when
));
751 dict
->SetString("value", "[" + severity
+ "] " + log
[i
].what
);
752 dict
->SetString("class", "log-" + severity
);
754 last_sent_event_id_
= log
[i
].id
;
757 web_ui()->CallJavascriptFunction("updateEventLog", list
);
760 void DriveInternalsWebUIHandler::UpdatePathConfigurationsSection() {
761 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
763 Profile
* const profile
= Profile::FromWebUI(web_ui());
765 base::ListValue paths
;
769 file_manager::util::GetDownloadsFolderForProfile(profile
).AsUTF8Unsafe());
772 drive::util::GetDriveMountPointPath(profile
).AsUTF8Unsafe());
774 const char* kPathPreferences
[] = {
775 prefs::kSelectFileLastDirectory
,
776 prefs::kSaveFileDefaultDirectory
,
777 prefs::kDownloadDefaultDirectory
,
779 for (size_t i
= 0; i
< arraysize(kPathPreferences
); ++i
) {
780 const char* const key
= kPathPreferences
[i
];
781 AppendKeyValue(&paths
, key
,
782 profile
->GetPrefs()->GetFilePath(key
).AsUTF8Unsafe());
785 web_ui()->CallJavascriptFunction("updatePathConfigurations", paths
);
788 void DriveInternalsWebUIHandler::OnGetGCacheContents(
789 base::ListValue
* gcache_contents
,
790 base::DictionaryValue
* gcache_summary
) {
791 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
792 DCHECK(gcache_contents
);
793 DCHECK(gcache_summary
);
795 web_ui()->CallJavascriptFunction("updateGCacheContents",
800 void DriveInternalsWebUIHandler::OnGetResourceEntryByPath(
801 const base::FilePath
& path
,
802 drive::FileError error
,
803 scoped_ptr
<drive::ResourceEntry
> entry
) {
804 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
806 if (error
== drive::FILE_ERROR_OK
) {
808 const base::StringValue
value(FormatEntry(path
, *entry
) + "\n");
809 web_ui()->CallJavascriptFunction("updateFileSystemContents", value
);
813 void DriveInternalsWebUIHandler::OnReadDirectoryByPath(
814 const base::FilePath
& parent_path
,
815 drive::FileError error
,
816 scoped_ptr
<drive::ResourceEntryVector
> entries
) {
817 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
819 if (error
== drive::FILE_ERROR_OK
) {
820 DCHECK(entries
.get());
822 drive::DebugInfoCollector
* debug_info_collector
= GetDebugInfoCollector();
823 std::string file_system_as_text
;
824 for (size_t i
= 0; i
< entries
->size(); ++i
) {
825 const drive::ResourceEntry
& entry
= (*entries
)[i
];
826 const base::FilePath current_path
= parent_path
.Append(
827 base::FilePath::FromUTF8Unsafe(entry
.base_name()));
829 file_system_as_text
.append(FormatEntry(current_path
, entry
) + "\n");
831 if (entry
.file_info().is_directory()) {
832 debug_info_collector
->ReadDirectory(
834 base::Bind(&DriveInternalsWebUIHandler::OnReadDirectoryByPath
,
835 weak_ptr_factory_
.GetWeakPtr(),
840 // There may be pending ReadDirectoryByPath() calls, but we can update
841 // the page with what we have now. This results in progressive
842 // updates, which is good for a large file system.
843 const base::StringValue
value(file_system_as_text
);
844 web_ui()->CallJavascriptFunction("updateFileSystemContents", value
);
848 void DriveInternalsWebUIHandler::UpdateCacheEntry(
849 const std::string
& local_id
,
850 const drive::FileCacheEntry
& cache_entry
) {
851 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
853 // Convert |cache_entry| into a dictionary.
854 base::DictionaryValue value
;
855 value
.SetString("local_id", local_id
);
856 value
.SetString("md5", cache_entry
.md5());
857 value
.SetBoolean("is_present", cache_entry
.is_present());
858 value
.SetBoolean("is_pinned", cache_entry
.is_pinned());
859 value
.SetBoolean("is_dirty", cache_entry
.is_dirty());
861 web_ui()->CallJavascriptFunction("updateCacheContents", value
);
864 void DriveInternalsWebUIHandler::OnGetFreeDiskSpace(
865 base::DictionaryValue
* local_storage_summary
) {
866 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
867 DCHECK(local_storage_summary
);
869 web_ui()->CallJavascriptFunction(
870 "updateLocalStorageUsage", *local_storage_summary
);
873 void DriveInternalsWebUIHandler::OnPeriodicUpdate(const base::ListValue
* args
) {
874 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
876 drive::DriveIntegrationService
* integration_service
=
877 GetIntegrationService();
878 // |integration_service| may be NULL in the guest/incognito mode.
879 if (!integration_service
)
882 UpdateInFlightOperationsSection(integration_service
->job_list());
883 UpdateEventLogSection();
888 DriveInternalsUI::DriveInternalsUI(content::WebUI
* web_ui
)
889 : WebUIController(web_ui
) {
890 web_ui
->AddMessageHandler(new DriveInternalsWebUIHandler());
892 content::WebUIDataSource
* source
=
893 content::WebUIDataSource::Create(chrome::kChromeUIDriveInternalsHost
);
894 source
->AddResourcePath("drive_internals.css", IDR_DRIVE_INTERNALS_CSS
);
895 source
->AddResourcePath("drive_internals.js", IDR_DRIVE_INTERNALS_JS
);
896 source
->SetDefaultResource(IDR_DRIVE_INTERNALS_HTML
);
898 Profile
* profile
= Profile::FromWebUI(web_ui
);
899 content::WebUIDataSource::Add(profile
, source
);
902 } // namespace chromeos