Ignore all virtual block devices except loop devices.

This CL modifies DiskManager to ignore all virtual block devices, except
loop devices, when enumerating devices and processing udev events.

BUG=chromium:265683
TEST=Tested the following:
1. Build and run unit tests.
2. Run the following tests:
   - platform_CrosDisksDBus
   - platform_CrosDisksFilesystem
3. Verify that no virtual block devices, except loop devices, are
   reported when running the following command on lumpy:

   dbus-send --system --print-reply --dest=org.chromium.CrosDisks \
       /org/chromium/CrosDisks org.chromium.CrosDisks.EnumerateDevices

Change-Id: I8315af19de914c75db350dfca5dc27faf713af73
Reviewed-on: https://gerrit.chromium.org/gerrit/63666
Tested-by: Ben Chan <benchan@chromium.org>
Reviewed-by: Luigi Semenzato <semenzato@chromium.org>
Commit-Queue: Ben Chan <benchan@chromium.org>
diff --git a/disk-manager.cc b/disk-manager.cc
index 49a9406..0b24e92 100644
--- a/disk-manager.cc
+++ b/disk-manager.cc
@@ -122,7 +122,10 @@
       LOG(INFO) << "      " << key << " = " << value;
     }
 
-    disks.push_back(UdevDevice(dev).ToDisk());
+    UdevDevice device(dev);
+    if (!device.IsIgnored()) {
+      disks.push_back(device.ToDisk());
+    }
     udev_device_unref(dev);
   }
 
@@ -134,6 +137,8 @@
 void DiskManager::ProcessBlockDeviceEvents(
     struct udev_device* dev, const char* action, DeviceEventList* events) {
   UdevDevice device(dev);
+  if (device.IsIgnored())
+    return;
 
   bool disk_added = false;
   bool disk_removed = false;
diff --git a/udev-device.cc b/udev-device.cc
index d71cef1..3cd01fe 100644
--- a/udev-device.cc
+++ b/udev-device.cc
@@ -53,6 +53,7 @@
 const char kPropertySerial[] = "ID_SERIAL";
 const char kSubsystemUsb[] = "usb";
 const char kVirtualDevicePathPrefix[] = "/sys/devices/virtual/";
+const char kLoopDevicePathPrefix[] = "/sys/devices/virtual/block/loop";
 const char kUSBDeviceInfoFile[] = "/opt/google/cros-disks/usb-device-info";
 const char kUSBIdentifierDatabase[] = "/usr/share/misc/usb.ids";
 const char* kNonAutoMountableFilesystemLabels[] = {
@@ -317,6 +318,10 @@
   return false;
 }
 
+bool UdevDevice::IsIgnored() const {
+  return IsVirtual() && !IsLoopDevice();
+}
+
 bool UdevDevice::IsOnBootDevice() const {
   // Obtain the boot device path, e.g. /dev/sda
   char boot_device_path[PATH_MAX];
@@ -371,6 +376,14 @@
   return true;
 }
 
+bool UdevDevice::IsLoopDevice() const {
+  const char *sys_path = udev_device_get_syspath(dev_);
+  if (sys_path) {
+    return StartsWithASCII(sys_path, kLoopDevicePathPrefix, true);
+  }
+  return false;
+}
+
 string UdevDevice::NativePath() const {
   const char *sys_path = udev_device_get_syspath(dev_);
   return sys_path ? sys_path : "";
diff --git a/udev-device.h b/udev-device.h
index 64122f2..456e3f0 100644
--- a/udev-device.h
+++ b/udev-device.h
@@ -69,6 +69,14 @@
   // Checks if a device should be hidden from the file browser.
   bool IsHidden();
 
+  // Checks if the device is completely ignored by cros-disks. Unlike
+  // IsAutoMountable() or IsHidden(), IsIgnored() prevents a device from being
+  // reported by cros-disks during device enumeration and udev events, such that
+  // the system does not even gather properties of the device. Currently, all
+  // virtual devices, except loop devices, are ignored. Loop devices are used
+  // by automated tests to simulate removable devices and thus not ignored.
+  bool IsIgnored() const;
+
   // Checks if any media is available in the device.
   bool IsMediaAvailable() const;
 
@@ -84,6 +92,9 @@
   // Checks if the device is a virtual device.
   bool IsVirtual() const;
 
+  // Checks if the device is a loop device.
+  bool IsLoopDevice() const;
+
   // Gets the native sysfs path of the device.
   std::string NativePath() const;
 
diff --git a/udev-device_unittest.cc b/udev-device_unittest.cc
index 3ee69ea..6b3ff1c 100644
--- a/udev-device_unittest.cc
+++ b/udev-device_unittest.cc
@@ -16,6 +16,8 @@
 namespace {
 
 const char kLoopDeviceFile[] = "/dev/loop0";
+const char kRamDeviceFile[] = "/dev/ram0";
+const char kZRamDeviceFile[] = "/dev/zram0";
 
 }  // namespace
 
@@ -64,6 +66,13 @@
         loop_device_ = device;
       }
 
+      if (!ram_device_ &&
+          (strcmp(device_file, kRamDeviceFile) == 0 ||
+           strcmp(device_file, kZRamDeviceFile) == 0)) {
+        udev_device_ref(device);
+        ram_device_ = device;
+      }
+
       udev_device_unref(device);
     }
     udev_enumerate_unref(enumerate);
@@ -78,6 +87,10 @@
       udev_device_unref(loop_device_);
       loop_device_ = NULL;
     }
+    if (ram_device_) {
+      udev_device_unref(ram_device_);
+      ram_device_ = NULL;
+    }
     if (mounted_device_) {
       udev_device_unref(mounted_device_);
       mounted_device_ = NULL;
@@ -98,12 +111,14 @@
   static struct udev* udev_;
   static struct udev_device* boot_device_;
   static struct udev_device* loop_device_;
+  static struct udev_device* ram_device_;
   static struct udev_device* mounted_device_;
 };
 
 struct udev* UdevDeviceTest::udev_ = NULL;
 struct udev_device* UdevDeviceTest::boot_device_ = NULL;
 struct udev_device* UdevDeviceTest::loop_device_ = NULL;
+struct udev_device* UdevDeviceTest::ram_device_ = NULL;
 struct udev_device* UdevDeviceTest::mounted_device_ = NULL;
 
 TEST_F(UdevDeviceTest, EnsureUTF8String) {
@@ -219,6 +234,21 @@
   }
 }
 
+TEST_F(UdevDeviceTest, IsIgnored) {
+  if (boot_device_) {
+    UdevDevice device(boot_device_);
+    EXPECT_FALSE(device.IsIgnored());
+  }
+  if (loop_device_) {
+    UdevDevice device(loop_device_);
+    EXPECT_FALSE(device.IsIgnored());
+  }
+  if (ram_device_) {
+    UdevDevice device(ram_device_);
+    EXPECT_TRUE(device.IsIgnored());
+  }
+}
+
 TEST_F(UdevDeviceTest, IsOnBootDevice) {
   if (boot_device_) {
     UdevDevice device(boot_device_);
@@ -260,6 +290,21 @@
     UdevDevice device(loop_device_);
     EXPECT_TRUE(device.IsVirtual());
   }
+  if (ram_device_) {
+    UdevDevice device(ram_device_);
+    EXPECT_TRUE(device.IsVirtual());
+  }
+}
+
+TEST_F(UdevDeviceTest, IsLoopDevice) {
+  if (loop_device_) {
+    UdevDevice device(loop_device_);
+    EXPECT_TRUE(device.IsLoopDevice());
+  }
+  if (ram_device_) {
+    UdevDevice device(ram_device_);
+    EXPECT_FALSE(device.IsLoopDevice());
+  }
 }
 
 TEST_F(UdevDeviceTest, GetSizeInfo) {