Commit 58e5c2a6 authored by kmadhusu@chromium.org's avatar kmadhusu@chromium.org

[LINUX] Extract the name and id of the device and send it along the device...

[LINUX] Extract the name and id of the device and send it along the device attach notification message.

Using udev library, extract the device name and id property. If ID_FS_UUID
and ID_FS_LABEL does not exists, construct a unique id and label using
device model and vendor information.

BUG=none
TEST=none


Review URL: https://chromiumcodereview.appspot.com/10829228

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@151811 0039d316-1c4b-4281-b951-d872f2087c98
parent 4a321c46
...@@ -25,6 +25,12 @@ ...@@ -25,6 +25,12 @@
class FilePath; class FilePath;
// Gets the media device information given a |device_path|. On success,
// returns true and fills in |device_name| and |device_id|.
typedef bool (*GetDeviceInfoFunc)(const std::string& device_path,
std::string* device_name,
string16* device_id);
namespace chrome { namespace chrome {
class MediaDeviceNotificationsLinux class MediaDeviceNotificationsLinux
...@@ -37,6 +43,10 @@ class MediaDeviceNotificationsLinux ...@@ -37,6 +43,10 @@ class MediaDeviceNotificationsLinux
void Init(); void Init();
protected: protected:
// Only for use in unit tests.
MediaDeviceNotificationsLinux(const FilePath& path,
GetDeviceInfoFunc getDeviceInfo);
// Avoids code deleting the object while there are references to it. // Avoids code deleting the object while there are references to it.
// Aside from the base::RefCountedThreadSafe friend class, and derived // Aside from the base::RefCountedThreadSafe friend class, and derived
// classes, any attempts to call this dtor will result in a compile-time // classes, any attempts to call this dtor will result in a compile-time
...@@ -51,26 +61,33 @@ class MediaDeviceNotificationsLinux ...@@ -51,26 +61,33 @@ class MediaDeviceNotificationsLinux
friend struct content::BrowserThread::DeleteOnThread< friend struct content::BrowserThread::DeleteOnThread<
content::BrowserThread::FILE>; content::BrowserThread::FILE>;
// (mount device, device id) // Structure to save mounted device information such as device path and unique
typedef std::pair<std::string, std::string> MountDeviceAndId; // identifier.
struct MountDeviceAndId {
std::string mount_device;
std::string device_id;
};
// Mapping of mount points to MountDeviceAndId. // Mapping of mount points to MountDeviceAndId.
typedef std::map<std::string, MountDeviceAndId> MountMap; typedef std::map<std::string, MountDeviceAndId> MountMap;
// (mount point, mount device)
// Helper Map to get new entries from mtab file.
typedef std::map<std::string, std::string> MountPointDeviceMap;
void InitOnFileThread(); void InitOnFileThread();
// Parse the mtab file and find all changes. // Parses mtab file and find all changes.
void UpdateMtab(); void UpdateMtab();
// Read the mtab file entries into |mtab|. // Reads mtab file entries into |mtab|.
void ReadMtab(MountMap* mtab); void ReadMtab(MountPointDeviceMap* mtab);
// Add a media device with a given device and mount device. Assign it a device // Checks and adds |mount_device| as media device given the |mount_point|.
// id as well. void CheckAndAddMediaDevice(const std::string& mount_device,
void AddNewDevice(const std::string& mount_device, const std::string& mount_point);
const std::string& mount_point,
std::string* device_id);
// Remove a media device with a given device id. // Removes media device with a given device id.
void RemoveOldDevice(const std::string& device_id); void RemoveOldDevice(const std::string& device_id);
// Whether Init() has been called or not. // Whether Init() has been called or not.
...@@ -85,15 +102,15 @@ class MediaDeviceNotificationsLinux ...@@ -85,15 +102,15 @@ class MediaDeviceNotificationsLinux
// Mapping of relevant mount points and their corresponding mount devices. // Mapping of relevant mount points and their corresponding mount devices.
// Keep in mind on Linux, a device can be mounted at multiple mount points, // Keep in mind on Linux, a device can be mounted at multiple mount points,
// and multiple devices can be mounted at a mount point. // and multiple devices can be mounted at a mount point.
MountMap mtab_; MountMap mount_info_map_;
// The lowest available device id number.
// TODO(thestig) Remove this and use a real per-device unique id instead.
int current_device_id_;
// Set of known file systems that we care about. // Set of known file systems that we care about.
std::set<std::string> known_file_systems_; std::set<std::string> known_file_systems_;
// Function handler to get device information. This is useful to set a mock
// handler for unit testing.
GetDeviceInfoFunc get_device_info_func_;
DISALLOW_COPY_AND_ASSIGN(MediaDeviceNotificationsLinux); DISALLOW_COPY_AND_ASSIGN(MediaDeviceNotificationsLinux);
}; };
......
...@@ -37,15 +37,44 @@ const char kDevice1[] = "d1"; ...@@ -37,15 +37,44 @@ const char kDevice1[] = "d1";
const char kDevice2[] = "d2"; const char kDevice2[] = "d2";
const char kDevice3[] = "d3"; const char kDevice3[] = "d3";
const char kDeviceId1[] = "UUID:FFF0-000F";
const char kDeviceId2[] = "VendorModelSerial:ComName:Model2010:898989898989";
const char kDeviceId3[] = "VendorModelSerial:::WEM319X792";
const char kDeviceLabel1[] = "TEST_USB_MODEL_1";
const char kDeviceLabel2[] = "TEST_USB_MODEL_2";
const char kDeviceLabel3[] = "TEST_USB_MODEL_3";
const char kMountPointA[] = "mnt_a"; const char kMountPointA[] = "mnt_a";
const char kMountPointB[] = "mnt_b"; const char kMountPointB[] = "mnt_b";
bool GetDeviceInfo(const std::string& dev_path,
std::string* id,
string16* name) {
std::string device_name;
if (dev_path == kDevice1) {
*id = std::string(kDeviceId1);
device_name = kDeviceLabel1;
} else if (dev_path == kDevice2) {
*id = std::string(kDeviceId2);
device_name = kDeviceLabel2;
} else if (dev_path == kDevice3) {
*id = std::string(kDeviceId3);
device_name = kDeviceLabel3;
} else {
return false;
}
*name = ASCIIToUTF16(device_name);
return true;
}
class MediaDeviceNotificationsLinuxTestWrapper class MediaDeviceNotificationsLinuxTestWrapper
: public MediaDeviceNotificationsLinux { : public MediaDeviceNotificationsLinux {
public: public:
MediaDeviceNotificationsLinuxTestWrapper(const FilePath& path, MediaDeviceNotificationsLinuxTestWrapper(const FilePath& path,
MessageLoop* message_loop) MessageLoop* message_loop)
: MediaDeviceNotificationsLinux(path), : MediaDeviceNotificationsLinux(path, &GetDeviceInfo),
message_loop_(message_loop) { message_loop_(message_loop) {
} }
...@@ -236,18 +265,17 @@ TEST_F(MediaDeviceNotificationsLinuxTest, BasicAttachDetach) { ...@@ -236,18 +265,17 @@ TEST_F(MediaDeviceNotificationsLinuxTest, BasicAttachDetach) {
MtabTestData(kDevice1, kInvalidPath, kValidFS), MtabTestData(kDevice1, kInvalidPath, kValidFS),
MtabTestData(kDevice2, test_path.value(), kValidFS), MtabTestData(kDevice2, test_path.value(), kValidFS),
}; };
const std::string kDeviceId = "0";
// Only |kDevice2| should be attached, since |kDevice1| has a bad path. // Only |kDevice2| should be attached, since |kDevice1| has a bad path.
EXPECT_CALL(observer(), EXPECT_CALL(observer(),
OnMediaDeviceAttached(kDeviceId, OnMediaDeviceAttached(kDeviceId2,
ASCIIToUTF16(kDevice2), ASCIIToUTF16(kDeviceLabel2),
base::SystemMonitor::TYPE_PATH, base::SystemMonitor::TYPE_PATH,
test_path.value())) test_path.value()))
.InSequence(mock_sequence); .InSequence(mock_sequence);
AppendToMtabAndRunLoop(test_data, arraysize(test_data)); AppendToMtabAndRunLoop(test_data, arraysize(test_data));
// |kDevice2| should be detached here. // |kDevice2| should be detached here.
EXPECT_CALL(observer(), OnMediaDeviceDetached(kDeviceId)) EXPECT_CALL(observer(), OnMediaDeviceDetached(kDeviceId2))
.InSequence(mock_sequence); .InSequence(mock_sequence);
WriteEmptyMtabAndRunLoop(); WriteEmptyMtabAndRunLoop();
} }
...@@ -260,11 +288,10 @@ TEST_F(MediaDeviceNotificationsLinuxTest, DCIM) { ...@@ -260,11 +288,10 @@ TEST_F(MediaDeviceNotificationsLinuxTest, DCIM) {
MtabTestData test_data1[] = { MtabTestData test_data1[] = {
MtabTestData(kDevice1, test_path_a.value(), kValidFS), MtabTestData(kDevice1, test_path_a.value(), kValidFS),
}; };
const std::string kDeviceId = "0";
// |kDevice1| should be attached as expected. // |kDevice1| should be attached as expected.
EXPECT_CALL(observer(), EXPECT_CALL(observer(),
OnMediaDeviceAttached(kDeviceId, OnMediaDeviceAttached(kDeviceId1,
ASCIIToUTF16(kDevice1), ASCIIToUTF16(kDeviceLabel1),
base::SystemMonitor::TYPE_PATH, base::SystemMonitor::TYPE_PATH,
test_path_a.value())) test_path_a.value()))
.InSequence(mock_sequence); .InSequence(mock_sequence);
...@@ -279,11 +306,47 @@ TEST_F(MediaDeviceNotificationsLinuxTest, DCIM) { ...@@ -279,11 +306,47 @@ TEST_F(MediaDeviceNotificationsLinuxTest, DCIM) {
AppendToMtabAndRunLoop(test_data2, arraysize(test_data2)); AppendToMtabAndRunLoop(test_data2, arraysize(test_data2));
// |kDevice1| should be detached as expected. // |kDevice1| should be detached as expected.
EXPECT_CALL(observer(), OnMediaDeviceDetached(kDeviceId)) EXPECT_CALL(observer(), OnMediaDeviceDetached(kDeviceId1))
.InSequence(mock_sequence); .InSequence(mock_sequence);
WriteEmptyMtabAndRunLoop(); WriteEmptyMtabAndRunLoop();
} }
// More complicated test case with multiple devices on multiple mount points.
TEST_F(MediaDeviceNotificationsLinuxTest, SwapMountPoints) {
FilePath test_path_a = CreateMountPointWithDCIMDir(kMountPointA);
FilePath test_path_b = CreateMountPointWithDCIMDir(kMountPointB);
ASSERT_FALSE(test_path_a.empty());
ASSERT_FALSE(test_path_b.empty());
// Attach two devices.
// kDevice1 -> kMountPointA
// kDevice2 -> kMountPointB
MtabTestData test_data1[] = {
MtabTestData(kDevice1, test_path_a.value(), kValidFS),
MtabTestData(kDevice2, test_path_b.value(), kValidFS),
};
EXPECT_CALL(observer(), OnMediaDeviceAttached(_, _, _, _)).Times(2);
EXPECT_CALL(observer(), OnMediaDeviceDetached(_)).Times(0);
AppendToMtabAndRunLoop(test_data1, arraysize(test_data1));
// Detach two devices from old mount points and attach the devices at new
// mount points.
// kDevice1 -> kMountPointB
// kDevice2 -> kMountPointA
MtabTestData test_data2[] = {
MtabTestData(kDevice1, test_path_b.value(), kValidFS),
MtabTestData(kDevice2, test_path_a.value(), kValidFS),
};
EXPECT_CALL(observer(), OnMediaDeviceAttached(_, _, _, _)).Times(2);
EXPECT_CALL(observer(), OnMediaDeviceDetached(_)).Times(2);
OverwriteMtabAndRunLoop(test_data2, arraysize(test_data2));
// Detach all devices.
EXPECT_CALL(observer(), OnMediaDeviceAttached(_, _, _, _)).Times(0);
EXPECT_CALL(observer(), OnMediaDeviceDetached(_)).Times(2);
WriteEmptyMtabAndRunLoop();
}
// More complicated test case with multiple devices on multiple mount points. // More complicated test case with multiple devices on multiple mount points.
TEST_F(MediaDeviceNotificationsLinuxTest, MultiDevicesMultiMountPoints) { TEST_F(MediaDeviceNotificationsLinuxTest, MultiDevicesMultiMountPoints) {
FilePath test_path_a = CreateMountPointWithDCIMDir(kMountPointA); FilePath test_path_a = CreateMountPointWithDCIMDir(kMountPointA);
...@@ -359,8 +422,6 @@ TEST_F(MediaDeviceNotificationsLinuxTest, MultiDevicesOneMountPoint) { ...@@ -359,8 +422,6 @@ TEST_F(MediaDeviceNotificationsLinuxTest, MultiDevicesOneMountPoint) {
FilePath test_path_b = CreateMountPointWithDCIMDir(kMountPointB); FilePath test_path_b = CreateMountPointWithDCIMDir(kMountPointB);
ASSERT_FALSE(test_path_a.empty()); ASSERT_FALSE(test_path_a.empty());
ASSERT_FALSE(test_path_b.empty()); ASSERT_FALSE(test_path_b.empty());
const std::string kDeviceId0 = "0";
const std::string kDeviceId1 = "1";
// |kDevice1| is most recently mounted at |kMountPointB|. // |kDevice1| is most recently mounted at |kMountPointB|.
// kDevice1 -> kMountPointA // kDevice1 -> kMountPointA
...@@ -372,8 +433,8 @@ TEST_F(MediaDeviceNotificationsLinuxTest, MultiDevicesOneMountPoint) { ...@@ -372,8 +433,8 @@ TEST_F(MediaDeviceNotificationsLinuxTest, MultiDevicesOneMountPoint) {
MtabTestData(kDevice1, test_path_b.value(), kValidFS), MtabTestData(kDevice1, test_path_b.value(), kValidFS),
}; };
EXPECT_CALL(observer(), EXPECT_CALL(observer(),
OnMediaDeviceAttached(kDeviceId0, OnMediaDeviceAttached(kDeviceId1,
ASCIIToUTF16(kDevice1), ASCIIToUTF16(kDeviceLabel1),
base::SystemMonitor::TYPE_PATH, base::SystemMonitor::TYPE_PATH,
test_path_b.value())) test_path_b.value()))
.Times(1); .Times(1);
...@@ -391,10 +452,10 @@ TEST_F(MediaDeviceNotificationsLinuxTest, MultiDevicesOneMountPoint) { ...@@ -391,10 +452,10 @@ TEST_F(MediaDeviceNotificationsLinuxTest, MultiDevicesOneMountPoint) {
MtabTestData test_data2[] = { MtabTestData test_data2[] = {
MtabTestData(kDevice3, test_path_b.value(), kValidFS), MtabTestData(kDevice3, test_path_b.value(), kValidFS),
}; };
EXPECT_CALL(observer(), OnMediaDeviceDetached(kDeviceId0)).Times(1); EXPECT_CALL(observer(), OnMediaDeviceDetached(kDeviceId1)).Times(1);
EXPECT_CALL(observer(), EXPECT_CALL(observer(),
OnMediaDeviceAttached(kDeviceId1, OnMediaDeviceAttached(kDeviceId3,
ASCIIToUTF16(kDevice3), ASCIIToUTF16(kDeviceLabel3),
base::SystemMonitor::TYPE_PATH, base::SystemMonitor::TYPE_PATH,
test_path_b.value())) test_path_b.value()))
.Times(1); .Times(1);
...@@ -402,7 +463,7 @@ TEST_F(MediaDeviceNotificationsLinuxTest, MultiDevicesOneMountPoint) { ...@@ -402,7 +463,7 @@ TEST_F(MediaDeviceNotificationsLinuxTest, MultiDevicesOneMountPoint) {
// Detach all devices. // Detach all devices.
EXPECT_CALL(observer(), OnMediaDeviceAttached(_, _, _, _)).Times(0); EXPECT_CALL(observer(), OnMediaDeviceAttached(_, _, _, _)).Times(0);
EXPECT_CALL(observer(), OnMediaDeviceDetached(kDeviceId1)).Times(1); EXPECT_CALL(observer(), OnMediaDeviceDetached(kDeviceId3)).Times(1);
WriteEmptyMtabAndRunLoop(); WriteEmptyMtabAndRunLoop();
} }
......
...@@ -4544,6 +4544,11 @@ ...@@ -4544,6 +4544,11 @@
'browser/ui/tabs/tab_strip_layout_type_prefs.h', 'browser/ui/tabs/tab_strip_layout_type_prefs.h',
], ],
}], }],
['OS=="linux"', {
'dependencies': [
'../build/linux/system.gyp:udev',
],
}],
['chromeos==0', { ['chromeos==0', {
'sources/': [ 'sources/': [
['exclude', '^browser/chromeos'], ['exclude', '^browser/chromeos'],
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment