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/profiles/profile.h"
32 #include "chrome/common/pref_names.h"
33 #include "chrome/common/url_constants.h"
34 #include "chromeos/chromeos_switches.h"
35 #include "content/public/browser/browser_thread.h"
36 #include "content/public/browser/web_ui.h"
37 #include "content/public/browser/web_ui_data_source.h"
38 #include "content/public/browser/web_ui_message_handler.h"
39 #include "google_apis/drive/auth_service.h"
40 #include "google_apis/drive/drive_api_parser.h"
41 #include "google_apis/drive/gdata_errorcode.h"
42 #include "google_apis/drive/gdata_wapi_parser.h"
43 #include "google_apis/drive/time_util.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
, base::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
= base::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
, base::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: %s\n", entry
.shared() ? "true" : "false");
138 StringAppendF(&out
, " shared_with_me: %s\n",
139 entry
.shared_with_me() ? "true" : "false");
141 const drive::PlatformFileInfoProto
& file_info
= entry
.file_info();
142 StringAppendF(&out
, " file_info\n");
143 StringAppendF(&out
, " size: %" PRId64
"\n", file_info
.size());
144 StringAppendF(&out
, " is_directory: %d\n", file_info
.is_directory());
145 StringAppendF(&out
, " is_symbolic_link: %d\n",
146 file_info
.is_symbolic_link());
148 const base::Time last_modified
= base::Time::FromInternalValue(
149 file_info
.last_modified());
150 const base::Time last_accessed
= base::Time::FromInternalValue(
151 file_info
.last_accessed());
152 const base::Time creation_time
= base::Time::FromInternalValue(
153 file_info
.creation_time());
154 StringAppendF(&out
, " last_modified: %s\n",
155 google_apis::util::FormatTimeAsString(last_modified
).c_str());
156 StringAppendF(&out
, " last_accessed: %s\n",
157 google_apis::util::FormatTimeAsString(last_accessed
).c_str());
158 StringAppendF(&out
, " creation_time: %s\n",
159 google_apis::util::FormatTimeAsString(creation_time
).c_str());
161 if (entry
.has_file_specific_info()) {
162 const drive::FileSpecificInfo
& file_specific_info
=
163 entry
.file_specific_info();
164 StringAppendF(&out
, " alternate_url: %s\n",
165 file_specific_info
.alternate_url().c_str());
166 StringAppendF(&out
, " content_mime_type: %s\n",
167 file_specific_info
.content_mime_type().c_str());
168 StringAppendF(&out
, " file_md5: %s\n",
169 file_specific_info
.md5().c_str());
170 StringAppendF(&out
, " document_extension: %s\n",
171 file_specific_info
.document_extension().c_str());
172 StringAppendF(&out
, " is_hosted_document: %d\n",
173 file_specific_info
.is_hosted_document());
176 if (entry
.has_directory_specific_info()) {
177 StringAppendF(&out
, " directory_info\n");
178 const drive::DirectorySpecificInfo
& directory_specific_info
=
179 entry
.directory_specific_info();
180 StringAppendF(&out
, " changestamp: %" PRId64
"\n",
181 directory_specific_info
.changestamp());
187 std::string
SeverityToString(logging::LogSeverity severity
) {
189 case logging::LOG_INFO
:
191 case logging::LOG_WARNING
:
193 case logging::LOG_ERROR
:
195 default: // Treat all other higher severities as ERROR.
200 // Class to handle messages from chrome://drive-internals.
201 class DriveInternalsWebUIHandler
: public content::WebUIMessageHandler
{
203 DriveInternalsWebUIHandler()
204 : last_sent_event_id_(-1),
205 weak_ptr_factory_(this) {
208 virtual ~DriveInternalsWebUIHandler() {
212 // WebUIMessageHandler override.
213 virtual void RegisterMessages() OVERRIDE
;
215 // Returns a DriveIntegrationService.
216 drive::DriveIntegrationService
* GetIntegrationService();
218 // Returns a DriveService instance.
219 drive::DriveServiceInterface
* GetDriveService();
221 // Returns a FileSystem instance.
222 drive::FileSystemInterface
* GetFileSystem();
224 // Called when the page is first loaded.
225 void OnPageLoaded(const base::ListValue
* args
);
227 // Updates respective sections.
228 void UpdateDriveRelatedFlagsSection();
229 void UpdateDriveRelatedPreferencesSection();
230 void UpdateConnectionStatusSection(
231 drive::DriveServiceInterface
* drive_service
);
232 void UpdateAboutResourceSection(
233 drive::DriveServiceInterface
* drive_service
);
234 void UpdateAppListSection(
235 drive::DriveServiceInterface
* drive_service
);
236 void UpdateLocalMetadataSection(
237 drive::DebugInfoCollector
* debug_info_collector
);
238 void UpdateDeltaUpdateStatusSection(
239 drive::DebugInfoCollector
* debug_info_collector
);
240 void UpdateInFlightOperationsSection(drive::JobListInterface
* job_list
);
241 void UpdateGCacheContentsSection();
242 void UpdateFileSystemContentsSection();
243 void UpdateLocalStorageUsageSection();
244 void UpdateCacheContentsSection(
245 drive::DebugInfoCollector
* debug_info_collector
);
246 void UpdateEventLogSection();
248 // Called when GetGCacheContents() is complete.
249 void OnGetGCacheContents(base::ListValue
* gcache_contents
,
250 base::DictionaryValue
* cache_summary
);
252 // Called when GetResourceEntryByPath() is complete.
253 void OnGetResourceEntryByPath(const base::FilePath
& path
,
254 drive::FileError error
,
255 scoped_ptr
<drive::ResourceEntry
> entry
);
257 // Called when ReadDirectoryByPath() is complete.
258 void OnReadDirectoryByPath(const base::FilePath
& parent_path
,
259 drive::FileError error
,
260 scoped_ptr
<drive::ResourceEntryVector
> entries
);
262 // Called as the iterator for DebugInfoCollector::IterateFileCache().
263 void UpdateCacheEntry(const std::string
& local_id
,
264 const drive::FileCacheEntry
& cache_entry
);
266 // Called when GetFreeDiskSpace() is complete.
267 void OnGetFreeDiskSpace(base::DictionaryValue
* local_storage_summary
);
269 // Called when GetAboutResource() call to DriveService is complete.
270 void OnGetAboutResource(
271 google_apis::GDataErrorCode status
,
272 scoped_ptr
<google_apis::AboutResource
> about_resource
);
274 // Called when GetAppList() call to DriveService is complete.
276 google_apis::GDataErrorCode status
,
277 scoped_ptr
<google_apis::AppList
> app_list
);
279 // Callback for DebugInfoCollector::GetMetadata for local update.
280 void OnGetFilesystemMetadataForLocal(
281 const drive::FileSystemMetadata
& metadata
);
283 // Callback for DebugInfoCollector::GetMetadata for delta update.
284 void OnGetFilesystemMetadataForDeltaUpdate(
285 const drive::FileSystemMetadata
& metadata
);
287 // Called when the page requests periodic update.
288 void OnPeriodicUpdate(const base::ListValue
* args
);
290 // Called when the corresponding button on the page is pressed.
291 void ClearAccessToken(const base::ListValue
* args
);
292 void ClearRefreshToken(const base::ListValue
* args
);
293 void ResetDriveFileSystem(const base::ListValue
* args
);
294 void ListFileEntries(const base::ListValue
* args
);
296 // Called after file system reset for ResetDriveFileSystem is done.
297 void ResetFinished(bool success
);
299 // The last event sent to the JavaScript side.
300 int last_sent_event_id_
;
302 base::WeakPtrFactory
<DriveInternalsWebUIHandler
> weak_ptr_factory_
;
303 DISALLOW_COPY_AND_ASSIGN(DriveInternalsWebUIHandler
);
306 void DriveInternalsWebUIHandler::OnGetAboutResource(
307 google_apis::GDataErrorCode status
,
308 scoped_ptr
<google_apis::AboutResource
> parsed_about_resource
) {
309 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
311 if (status
!= google_apis::HTTP_SUCCESS
) {
312 LOG(ERROR
) << "Failed to get about resource";
315 DCHECK(parsed_about_resource
);
317 base::DictionaryValue about_resource
;
318 about_resource
.SetDouble("account-quota-total",
319 parsed_about_resource
->quota_bytes_total());
320 about_resource
.SetDouble("account-quota-used",
321 parsed_about_resource
->quota_bytes_used());
322 about_resource
.SetDouble("account-largest-changestamp-remote",
323 parsed_about_resource
->largest_change_id());
324 about_resource
.SetString("root-resource-id",
325 parsed_about_resource
->root_folder_id());
327 web_ui()->CallJavascriptFunction("updateAboutResource", about_resource
);
330 void DriveInternalsWebUIHandler::OnGetAppList(
331 google_apis::GDataErrorCode status
,
332 scoped_ptr
<google_apis::AppList
> parsed_app_list
) {
333 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
335 if (status
!= google_apis::HTTP_SUCCESS
) {
336 LOG(ERROR
) << "Failed to get app list";
339 DCHECK(parsed_app_list
);
341 base::DictionaryValue app_list
;
342 app_list
.SetString("etag", parsed_app_list
->etag());
344 base::ListValue
* items
= new base::ListValue();
345 for (size_t i
= 0; i
< parsed_app_list
->items().size(); ++i
) {
346 const google_apis::AppResource
* app
= parsed_app_list
->items()[i
];
347 base::DictionaryValue
* app_data
= new base::DictionaryValue();
348 app_data
->SetString("name", app
->name());
349 app_data
->SetString("application_id", app
->application_id());
350 app_data
->SetString("object_type", app
->object_type());
351 app_data
->SetBoolean("supports_create", app
->supports_create());
353 items
->Append(app_data
);
355 app_list
.Set("items", items
);
357 web_ui()->CallJavascriptFunction("updateAppList", app_list
);
360 void DriveInternalsWebUIHandler::RegisterMessages() {
361 web_ui()->RegisterMessageCallback(
363 base::Bind(&DriveInternalsWebUIHandler::OnPageLoaded
,
364 weak_ptr_factory_
.GetWeakPtr()));
365 web_ui()->RegisterMessageCallback(
367 base::Bind(&DriveInternalsWebUIHandler::OnPeriodicUpdate
,
368 weak_ptr_factory_
.GetWeakPtr()));
369 web_ui()->RegisterMessageCallback(
371 base::Bind(&DriveInternalsWebUIHandler::ClearAccessToken
,
372 weak_ptr_factory_
.GetWeakPtr()));
373 web_ui()->RegisterMessageCallback(
375 base::Bind(&DriveInternalsWebUIHandler::ClearRefreshToken
,
376 weak_ptr_factory_
.GetWeakPtr()));
377 web_ui()->RegisterMessageCallback(
378 "resetDriveFileSystem",
379 base::Bind(&DriveInternalsWebUIHandler::ResetDriveFileSystem
,
380 weak_ptr_factory_
.GetWeakPtr()));
381 web_ui()->RegisterMessageCallback(
383 base::Bind(&DriveInternalsWebUIHandler::ListFileEntries
,
384 weak_ptr_factory_
.GetWeakPtr()));
387 drive::DriveIntegrationService
*
388 DriveInternalsWebUIHandler::GetIntegrationService() {
389 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
391 Profile
* profile
= Profile::FromWebUI(web_ui());
392 drive::DriveIntegrationService
* service
=
393 drive::DriveIntegrationServiceFactory::FindForProfile(profile
);
394 if (!service
|| !service
->is_enabled())
399 drive::DriveServiceInterface
* DriveInternalsWebUIHandler::GetDriveService() {
400 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
402 Profile
* profile
= Profile::FromWebUI(web_ui());
403 return drive::util::GetDriveServiceByProfile(profile
);
406 drive::FileSystemInterface
* DriveInternalsWebUIHandler::GetFileSystem() {
407 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
409 Profile
* profile
= Profile::FromWebUI(web_ui());
410 return drive::util::GetFileSystemByProfile(profile
);
413 void DriveInternalsWebUIHandler::OnPageLoaded(const base::ListValue
* args
) {
414 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
416 drive::DriveIntegrationService
* integration_service
=
417 GetIntegrationService();
418 // |integration_service| may be NULL in the guest/incognito mode.
419 if (!integration_service
)
422 drive::DriveServiceInterface
* drive_service
=
423 integration_service
->drive_service();
424 DCHECK(drive_service
);
425 drive::DebugInfoCollector
* debug_info_collector
=
426 integration_service
->debug_info_collector();
427 DCHECK(debug_info_collector
);
429 UpdateDriveRelatedFlagsSection();
430 UpdateDriveRelatedPreferencesSection();
431 UpdateConnectionStatusSection(drive_service
);
432 UpdateAboutResourceSection(drive_service
);
433 UpdateAppListSection(drive_service
);
434 UpdateLocalMetadataSection(debug_info_collector
);
435 UpdateDeltaUpdateStatusSection(debug_info_collector
);
436 UpdateInFlightOperationsSection(integration_service
->job_list());
437 UpdateGCacheContentsSection();
438 UpdateCacheContentsSection(debug_info_collector
);
439 UpdateLocalStorageUsageSection();
441 // When the drive-internals page is reloaded by the reload key, the page
442 // content is recreated, but this WebUI object is not (instead, OnPageLoaded
443 // is called again). In that case, we have to forget the last sent ID here,
444 // and resent whole the logs to the page.
445 last_sent_event_id_
= -1;
446 UpdateEventLogSection();
449 void DriveInternalsWebUIHandler::UpdateDriveRelatedFlagsSection() {
450 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
452 const char* kDriveRelatedFlags
[] = {
453 drive::switches::kEnableDriveV2Api
,
454 chromeos::switches::kDisableDrive
,
457 base::ListValue flags
;
458 for (size_t i
= 0; i
< arraysize(kDriveRelatedFlags
); ++i
) {
459 const std::string key
= kDriveRelatedFlags
[i
];
460 std::string value
= "(not set)";
461 if (CommandLine::ForCurrentProcess()->HasSwitch(key
))
462 value
= CommandLine::ForCurrentProcess()->GetSwitchValueASCII(key
);
463 base::DictionaryValue
* flag
= new base::DictionaryValue
;
464 flag
->SetString("key", key
);
465 flag
->SetString("value", value
.empty() ? "(set)" : value
);
469 web_ui()->CallJavascriptFunction("updateDriveRelatedFlags", flags
);
472 void DriveInternalsWebUIHandler::UpdateDriveRelatedPreferencesSection() {
473 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
475 const char* kDriveRelatedPreferences
[] = {
476 prefs::kDisableDrive
,
477 prefs::kDisableDriveOverCellular
,
478 prefs::kDisableDriveHostedFiles
,
481 Profile
* profile
= Profile::FromWebUI(web_ui());
482 PrefService
* pref_service
= profile
->GetPrefs();
484 base::ListValue preferences
;
485 for (size_t i
= 0; i
< arraysize(kDriveRelatedPreferences
); ++i
) {
486 const std::string key
= kDriveRelatedPreferences
[i
];
487 // As of now, all preferences are boolean.
488 const std::string value
=
489 (pref_service
->GetBoolean(key
.c_str()) ? "true" : "false");
490 base::DictionaryValue
* preference
= new base::DictionaryValue
;
491 preference
->SetString("key", key
);
492 preference
->SetString("value", value
);
493 preferences
.Append(preference
);
496 web_ui()->CallJavascriptFunction("updateDriveRelatedPreferences",
500 void DriveInternalsWebUIHandler::UpdateConnectionStatusSection(
501 drive::DriveServiceInterface
* drive_service
) {
502 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
503 DCHECK(drive_service
);
506 switch (drive::util::GetDriveConnectionStatus(Profile::FromWebUI(web_ui()))) {
507 case drive::util::DRIVE_DISCONNECTED_NOSERVICE
:
508 status
= "no service";
510 case drive::util::DRIVE_DISCONNECTED_NONETWORK
:
511 status
= "no network";
513 case drive::util::DRIVE_DISCONNECTED_NOTREADY
:
514 status
= "not ready";
516 case drive::util::DRIVE_CONNECTED_METERED
:
519 case drive::util::DRIVE_CONNECTED
:
520 status
= "connected";
524 base::DictionaryValue connection_status
;
525 connection_status
.SetString("status", status
);
526 connection_status
.SetBoolean("has-refresh-token",
527 drive_service
->HasRefreshToken());
528 connection_status
.SetBoolean("has-access-token",
529 drive_service
->HasAccessToken());
530 web_ui()->CallJavascriptFunction("updateConnectionStatus", connection_status
);
533 void DriveInternalsWebUIHandler::UpdateAboutResourceSection(
534 drive::DriveServiceInterface
* drive_service
) {
535 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
536 DCHECK(drive_service
);
538 drive_service
->GetAboutResource(
539 base::Bind(&DriveInternalsWebUIHandler::OnGetAboutResource
,
540 weak_ptr_factory_
.GetWeakPtr()));
543 void DriveInternalsWebUIHandler::UpdateAppListSection(
544 drive::DriveServiceInterface
* drive_service
) {
545 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
546 DCHECK(drive_service
);
548 drive_service
->GetAppList(
549 base::Bind(&DriveInternalsWebUIHandler::OnGetAppList
,
550 weak_ptr_factory_
.GetWeakPtr()));
553 void DriveInternalsWebUIHandler::UpdateLocalMetadataSection(
554 drive::DebugInfoCollector
* debug_info_collector
) {
555 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
556 DCHECK(debug_info_collector
);
558 debug_info_collector
->GetMetadata(
559 base::Bind(&DriveInternalsWebUIHandler::OnGetFilesystemMetadataForLocal
,
560 weak_ptr_factory_
.GetWeakPtr()));
563 void DriveInternalsWebUIHandler::OnGetFilesystemMetadataForLocal(
564 const drive::FileSystemMetadata
& metadata
) {
565 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
567 base::DictionaryValue local_metadata
;
568 local_metadata
.SetDouble("account-largest-changestamp-local",
569 metadata
.largest_changestamp
);
570 local_metadata
.SetBoolean("account-metadata-refreshing", metadata
.refreshing
);
571 web_ui()->CallJavascriptFunction("updateLocalMetadata", local_metadata
);
574 void DriveInternalsWebUIHandler::ClearAccessToken(const base::ListValue
* args
) {
575 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
577 drive::DriveServiceInterface
* drive_service
= GetDriveService();
579 drive_service
->ClearAccessToken();
582 void DriveInternalsWebUIHandler::ClearRefreshToken(
583 const base::ListValue
* args
) {
584 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
586 drive::DriveServiceInterface
* drive_service
= GetDriveService();
588 drive_service
->ClearRefreshToken();
591 void DriveInternalsWebUIHandler::ResetDriveFileSystem(
592 const base::ListValue
* args
) {
593 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
595 drive::DriveIntegrationService
* integration_service
=
596 GetIntegrationService();
597 if (integration_service
) {
598 integration_service
->ClearCacheAndRemountFileSystem(
599 base::Bind(&DriveInternalsWebUIHandler::ResetFinished
,
600 weak_ptr_factory_
.GetWeakPtr()));
604 void DriveInternalsWebUIHandler::ResetFinished(bool success
) {
605 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
607 web_ui()->CallJavascriptFunction("updateResetStatus",
608 base::FundamentalValue(success
));
611 void DriveInternalsWebUIHandler::ListFileEntries(const base::ListValue
* args
) {
612 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
614 UpdateFileSystemContentsSection();
617 void DriveInternalsWebUIHandler::UpdateDeltaUpdateStatusSection(
618 drive::DebugInfoCollector
* debug_info_collector
) {
619 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
620 DCHECK(debug_info_collector
);
622 debug_info_collector
->GetMetadata(
624 &DriveInternalsWebUIHandler::OnGetFilesystemMetadataForDeltaUpdate
,
625 weak_ptr_factory_
.GetWeakPtr()));
628 void DriveInternalsWebUIHandler::OnGetFilesystemMetadataForDeltaUpdate(
629 const drive::FileSystemMetadata
& metadata
) {
630 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
632 Profile
* profile
= Profile::FromWebUI(web_ui());
633 drive::DriveNotificationManager
* drive_notification_manager
=
634 drive::DriveNotificationManagerFactory::GetForBrowserContext(profile
);
635 if (!drive_notification_manager
)
638 base::DictionaryValue delta_update_status
;
639 delta_update_status
.SetBoolean(
640 "push-notification-enabled",
641 drive_notification_manager
->push_notification_enabled());
642 delta_update_status
.SetString(
643 "last-update-check-time",
644 google_apis::util::FormatTimeAsStringLocaltime(
645 metadata
.last_update_check_time
));
646 delta_update_status
.SetString(
647 "last-update-check-error",
648 drive::FileErrorToString(metadata
.last_update_check_error
));
650 web_ui()->CallJavascriptFunction("updateDeltaUpdateStatus",
651 delta_update_status
);
654 void DriveInternalsWebUIHandler::UpdateInFlightOperationsSection(
655 drive::JobListInterface
* job_list
) {
656 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
659 std::vector
<drive::JobInfo
> info_list
= job_list
->GetJobInfoList();
661 base::ListValue in_flight_operations
;
662 for (size_t i
= 0; i
< info_list
.size(); ++i
) {
663 const drive::JobInfo
& info
= info_list
[i
];
665 base::DictionaryValue
* dict
= new base::DictionaryValue
;
666 dict
->SetInteger("id", info
.job_id
);
667 dict
->SetString("type", drive::JobTypeToString(info
.job_type
));
668 dict
->SetString("file_path", info
.file_path
.AsUTF8Unsafe());
669 dict
->SetString("state", drive::JobStateToString(info
.state
));
670 dict
->SetDouble("progress_current", info
.num_completed_bytes
);
671 dict
->SetDouble("progress_total", info
.num_total_bytes
);
672 in_flight_operations
.Append(dict
);
674 web_ui()->CallJavascriptFunction("updateInFlightOperations",
675 in_flight_operations
);
678 void DriveInternalsWebUIHandler::UpdateGCacheContentsSection() {
679 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
681 // Start updating the GCache contents section.
682 Profile
* profile
= Profile::FromWebUI(web_ui());
683 const base::FilePath root_path
= drive::util::GetCacheRootPath(profile
);
684 base::ListValue
* gcache_contents
= new base::ListValue
;
685 base::DictionaryValue
* gcache_summary
= new base::DictionaryValue
;
686 BrowserThread::PostBlockingPoolTaskAndReply(
688 base::Bind(&GetGCacheContents
,
692 base::Bind(&DriveInternalsWebUIHandler::OnGetGCacheContents
,
693 weak_ptr_factory_
.GetWeakPtr(),
694 base::Owned(gcache_contents
),
695 base::Owned(gcache_summary
)));
698 void DriveInternalsWebUIHandler::UpdateFileSystemContentsSection() {
699 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
701 drive::DriveServiceInterface
* drive_service
= GetDriveService();
702 drive::FileSystemInterface
* file_system
= GetFileSystem();
703 if (!drive_service
|| !file_system
)
706 // Start updating the file system tree section, if we have access token.
707 if (!drive_service
->HasAccessToken())
710 // Start rendering the file system tree as text.
711 const base::FilePath root_path
= drive::util::GetDriveGrandRootPath();
713 file_system
->GetResourceEntry(
715 base::Bind(&DriveInternalsWebUIHandler::OnGetResourceEntryByPath
,
716 weak_ptr_factory_
.GetWeakPtr(),
719 file_system
->ReadDirectory(
721 base::Bind(&DriveInternalsWebUIHandler::OnReadDirectoryByPath
,
722 weak_ptr_factory_
.GetWeakPtr(),
726 void DriveInternalsWebUIHandler::UpdateLocalStorageUsageSection() {
727 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
729 // Propagate the amount of local free space in bytes.
730 base::FilePath home_path
;
731 if (PathService::Get(base::DIR_HOME
, &home_path
)) {
732 base::DictionaryValue
* local_storage_summary
= new base::DictionaryValue
;
733 BrowserThread::PostBlockingPoolTaskAndReply(
735 base::Bind(&GetFreeDiskSpace
, home_path
, local_storage_summary
),
736 base::Bind(&DriveInternalsWebUIHandler::OnGetFreeDiskSpace
,
737 weak_ptr_factory_
.GetWeakPtr(),
738 base::Owned(local_storage_summary
)));
740 LOG(ERROR
) << "Home directory not found";
744 void DriveInternalsWebUIHandler::UpdateCacheContentsSection(
745 drive::DebugInfoCollector
* debug_info_collector
) {
746 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
747 DCHECK(debug_info_collector
);
749 debug_info_collector
->IterateFileCache(
750 base::Bind(&DriveInternalsWebUIHandler::UpdateCacheEntry
,
751 weak_ptr_factory_
.GetWeakPtr()),
752 base::Bind(&base::DoNothing
));
755 void DriveInternalsWebUIHandler::UpdateEventLogSection() {
756 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
758 const std::vector
<drive::EventLogger::Event
> log
=
759 drive::util::GetLogHistory();
761 base::ListValue list
;
762 for (size_t i
= 0; i
< log
.size(); ++i
) {
763 // Skip events which were already sent.
764 if (log
[i
].id
<= last_sent_event_id_
)
767 std::string severity
= SeverityToString(log
[i
].severity
);
769 base::DictionaryValue
* dict
= new base::DictionaryValue
;
770 dict
->SetString("key",
771 google_apis::util::FormatTimeAsStringLocaltime(log
[i
].when
));
772 dict
->SetString("value", "[" + severity
+ "] " + log
[i
].what
);
773 dict
->SetString("class", "log-" + severity
);
775 last_sent_event_id_
= log
[i
].id
;
778 web_ui()->CallJavascriptFunction("updateEventLog", list
);
781 void DriveInternalsWebUIHandler::OnGetGCacheContents(
782 base::ListValue
* gcache_contents
,
783 base::DictionaryValue
* gcache_summary
) {
784 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
785 DCHECK(gcache_contents
);
786 DCHECK(gcache_summary
);
788 web_ui()->CallJavascriptFunction("updateGCacheContents",
793 void DriveInternalsWebUIHandler::OnGetResourceEntryByPath(
794 const base::FilePath
& path
,
795 drive::FileError error
,
796 scoped_ptr
<drive::ResourceEntry
> entry
) {
797 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
799 if (error
== drive::FILE_ERROR_OK
) {
801 const base::StringValue
value(FormatEntry(path
, *entry
) + "\n");
802 web_ui()->CallJavascriptFunction("updateFileSystemContents", value
);
806 void DriveInternalsWebUIHandler::OnReadDirectoryByPath(
807 const base::FilePath
& parent_path
,
808 drive::FileError error
,
809 scoped_ptr
<drive::ResourceEntryVector
> entries
) {
810 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
812 if (error
== drive::FILE_ERROR_OK
) {
813 DCHECK(entries
.get());
815 drive::FileSystemInterface
* file_system
= GetFileSystem();
816 std::string file_system_as_text
;
817 for (size_t i
= 0; i
< entries
->size(); ++i
) {
818 const drive::ResourceEntry
& entry
= (*entries
)[i
];
819 const base::FilePath current_path
= parent_path
.Append(
820 base::FilePath::FromUTF8Unsafe(entry
.base_name()));
822 file_system_as_text
.append(FormatEntry(current_path
, entry
) + "\n");
824 if (entry
.file_info().is_directory()) {
825 file_system
->ReadDirectory(
827 base::Bind(&DriveInternalsWebUIHandler::OnReadDirectoryByPath
,
828 weak_ptr_factory_
.GetWeakPtr(),
833 // There may be pending ReadDirectoryByPath() calls, but we can update
834 // the page with what we have now. This results in progressive
835 // updates, which is good for a large file system.
836 const base::StringValue
value(file_system_as_text
);
837 web_ui()->CallJavascriptFunction("updateFileSystemContents", value
);
841 void DriveInternalsWebUIHandler::UpdateCacheEntry(
842 const std::string
& local_id
,
843 const drive::FileCacheEntry
& cache_entry
) {
844 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
846 // Convert |cache_entry| into a dictionary.
847 base::DictionaryValue value
;
848 value
.SetString("local_id", local_id
);
849 value
.SetString("md5", cache_entry
.md5());
850 value
.SetBoolean("is_present", cache_entry
.is_present());
851 value
.SetBoolean("is_pinned", cache_entry
.is_pinned());
852 value
.SetBoolean("is_dirty", cache_entry
.is_dirty());
854 web_ui()->CallJavascriptFunction("updateCacheContents", value
);
857 void DriveInternalsWebUIHandler::OnGetFreeDiskSpace(
858 base::DictionaryValue
* local_storage_summary
) {
859 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
860 DCHECK(local_storage_summary
);
862 web_ui()->CallJavascriptFunction(
863 "updateLocalStorageUsage", *local_storage_summary
);
866 void DriveInternalsWebUIHandler::OnPeriodicUpdate(const base::ListValue
* args
) {
867 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
869 drive::DriveIntegrationService
* integration_service
=
870 GetIntegrationService();
871 // |integration_service| may be NULL in the guest/incognito mode.
872 if (!integration_service
)
875 UpdateInFlightOperationsSection(integration_service
->job_list());
876 UpdateEventLogSection();
881 DriveInternalsUI::DriveInternalsUI(content::WebUI
* web_ui
)
882 : WebUIController(web_ui
) {
883 web_ui
->AddMessageHandler(new DriveInternalsWebUIHandler());
885 content::WebUIDataSource
* source
=
886 content::WebUIDataSource::Create(chrome::kChromeUIDriveInternalsHost
);
887 source
->AddResourcePath("drive_internals.css", IDR_DRIVE_INTERNALS_CSS
);
888 source
->AddResourcePath("drive_internals.js", IDR_DRIVE_INTERNALS_JS
);
889 source
->SetDefaultResource(IDR_DRIVE_INTERNALS_HTML
);
891 Profile
* profile
= Profile::FromWebUI(web_ui
);
892 content::WebUIDataSource::Add(profile
, source
);
895 } // namespace chromeos