diff options
author | hirono <hirono@chromium.org> | 2015-03-11 22:04:28 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-03-12 05:05:30 +0000 |
commit | 86aa57796c183cf2782c972025ed33c403ac067b (patch) | |
tree | 0f145dcafc926100a173aba42f0600d712fd52e3 | |
parent | c1456d32aa5911ef628cc77703e0c0487321aec5 (diff) | |
download | chromium_src-86aa57796c183cf2782c972025ed33c403ac067b.zip chromium_src-86aa57796c183cf2782c972025ed33c403ac067b.tar.gz chromium_src-86aa57796c183cf2782c972025ed33c403ac067b.tar.bz2 |
Files.app: Fix race condition in VolumeManager.
Gallery sometimes misses drive volume by the following logic.
It also can be happened to Files.app.
1. chrome.fileManagerPrivate.getVolumeMetadataList
2. Before complete #1, drive volume is mounted.
3. After complete #1, register a listener to onMountCompleted event.
BUG=466467
TEST=FileManagerJsTest.VolumeManager
Review URL: https://codereview.chromium.org/988713003
Cr-Commit-Position: refs/heads/master@{#320235}
-rw-r--r-- | ui/file_manager/file_manager/background/js/volume_manager.js | 70 | ||||
-rw-r--r-- | ui/file_manager/file_manager/background/js/volume_manager_unittest.js | 30 |
2 files changed, 69 insertions, 31 deletions
diff --git a/ui/file_manager/file_manager/background/js/volume_manager.js b/ui/file_manager/file_manager/background/js/volume_manager.js index 565ab06..5563cf7 100644 --- a/ui/file_manager/file_manager/background/js/volume_manager.js +++ b/ui/file_manager/file_manager/background/js/volume_manager.js @@ -625,7 +625,34 @@ VolumeManager.getInstance = function(opt_callback) { VolumeManager.revokeInstanceForTesting = function() { VolumeManager.instancePromise_ = null; VolumeManager.instance_ = null; -} +}; + +/** + * Adds new volume info from the given volumeMetadata. If the corresponding + * volume info has already been added, the volumeMetadata is ignored. + * @param {!VolumeMetadata} volumeMetadata + * @return {!Promise<!VolumeInfo>} + * @private + */ +VolumeManager.prototype.addVolumeMetadata_ = function(volumeMetadata) { + return new Promise(function(callback) { + volumeManagerUtil.createVolumeInfo(volumeMetadata, callback); + }).then(function(volumeInfo) { + if (this.volumeInfoList.findIndex(volumeInfo.volumeId) === -1) { + this.volumeInfoList.add(volumeInfo); + + // Update the network connection status, because until the drive is + // initialized, the status is set to not ready. + // TODO(mtomasz): The connection status should be migrated into + // VolumeMetadata. + if (volumeMetadata.volumeType === + VolumeManagerCommon.VolumeType.DRIVE) { + this.onDriveConnectionStatusChanged_(); + } + } + return volumeInfo; + }.bind(this)); +}; /** * Initializes mount points. @@ -634,6 +661,8 @@ VolumeManager.revokeInstanceForTesting = function() { * @private */ VolumeManager.prototype.initialize_ = function(callback) { + chrome.fileManagerPrivate.onMountCompleted.addListener( + this.onMountCompleted_.bind(this)); console.debug('Requesting volume list.'); chrome.fileManagerPrivate.getVolumeMetadataList(function(volumeMetadataList) { console.debug('Volume list fetched with: ' + volumeMetadataList.length + @@ -644,23 +673,16 @@ VolumeManager.prototype.initialize_ = function(callback) { // volumes in the volumeMetadataList are mounted. crbug.com/135477. this.mountQueue_.run(function(inCallback) { // Create VolumeInfo for each volume. - var group = new AsyncUtil.Group(); - for (var i = 0; i < volumeMetadataList.length; i++) { - console.debug('Initializing volume: ' + volumeMetadataList[i].volumeId); - group.add(function(volumeMetadata, continueCallback) { - volumeManagerUtil.createVolumeInfo( - volumeMetadata, + Promise.all([ + volumeMetadataList.map(function(volumeMetadata) { + console.debug( + 'Initializing volume: ' + volumeMetadata.volumeId); + return this.addVolumeMetadata_(volumeMetadata).then( function(volumeInfo) { - this.volumeInfoList.add(volumeInfo); - if (volumeMetadata.volumeType === - VolumeManagerCommon.VolumeType.DRIVE) - this.onDriveConnectionStatusChanged_(); console.debug('Initialized volume: ' + volumeInfo.volumeId); - continueCallback(); - }.bind(this)); - }.bind(this, volumeMetadataList[i])); - } - group.run(function() { + }); + }.bind(this)) + ]).then(function() { console.debug('Initialized all volumes.'); // Call the callback of the initialize function. callback(); @@ -669,9 +691,6 @@ VolumeManager.prototype.initialize_ = function(callback) { inCallback(); }); }.bind(this)); - - chrome.fileManagerPrivate.onMountCompleted.addListener( - this.onMountCompleted_.bind(this)); }.bind(this)); }; @@ -693,20 +712,9 @@ VolumeManager.prototype.onMountCompleted_ = function(event) { VolumeManagerCommon.VolumeError.UNKNOWN_FILESYSTEM || event.status === VolumeManagerCommon.VolumeError.UNSUPPORTED_FILESYSTEM) { - volumeManagerUtil.createVolumeInfo( - event.volumeMetadata, + this.addVolumeMetadata_(event.volumeMetadata).then( function(volumeInfo) { - this.volumeInfoList.add(volumeInfo); this.finishRequest_(requestKey, event.status, volumeInfo); - - if (volumeInfo.volumeType === - VolumeManagerCommon.VolumeType.DRIVE) { - // Update the network connection status, because until the - // drive is initialized, the status is set to not ready. - // TODO(mtomasz): The connection status should be migrated - // into VolumeMetadata. - this.onDriveConnectionStatusChanged_(); - } callback(); }.bind(this)); } else { diff --git a/ui/file_manager/file_manager/background/js/volume_manager_unittest.js b/ui/file_manager/file_manager/background/js/volume_manager_unittest.js index d7e97b7..e77a34e 100644 --- a/ui/file_manager/file_manager/background/js/volume_manager_unittest.js +++ b/ui/file_manager/file_manager/background/js/volume_manager_unittest.js @@ -251,3 +251,33 @@ function testVolumeInfoListWhenReady(callback) { assertEquals(volumeInfo, volumes[1]); }), callback); } + +function testDriveMountedDuringInitialization(callback) { + var sendMetadataListCallback; + chrome.fileManagerPrivate.getVolumeMetadataList = function(callback) { + sendMetadataListCallback = callback; + }; + + // Start initialization. + var instancePromise = VolumeManager.getInstance(); + + // Drive is mounted during initialization. + chrome.fileManagerPrivate.onMountCompleted.dispatchEvent({ + eventType: 'mount', + status: 'success', + volumeMetadata: { + volumeId: 'drive', + volumeType: VolumeManagerCommon.VolumeType.DRIVE, + sourcePath: '/drive', + profile: getMockProfile() + } + }); + + // Complete initialization. + sendMetadataListCallback([]); + + reportPromise(instancePromise.then(function(volumeManager) { + assertTrue(!!volumeManager.getCurrentProfileVolumeInfo( + VolumeManagerCommon.VolumeType.DRIVE)); + }), callback); +} |