Browse Source

recovery: Implement a volume manager

This is a copy of the pre-binderized vold which has been converted to
use direct calls instead of sockets and stripped down to only what is
needed to support recovery.

Change-Id: Ic82d929e052b5ba70ecf7b475e0a223d77d9687e
Tom Marshall 2 years ago
parent
commit
2be10173bf
50 changed files with 4175 additions and 51 deletions
  1. 1
    0
      Android.bp
  2. 3
    0
      Android.mk
  3. 5
    4
      device.cpp
  4. 5
    2
      device.h
  5. 20
    0
      etc/init.rc
  6. 0
    4
      fuse_sdcard_provider.cpp
  7. 18
    1
      install.cpp
  8. 12
    0
      mounts.cpp
  9. 1
    0
      mounts.h
  10. 104
    28
      recovery.cpp
  11. 74
    10
      roots.cpp
  12. 7
    1
      roots.h
  13. 24
    1
      ui.cpp
  14. 7
    0
      ui.h
  15. 25
    0
      volclient.cpp
  16. 33
    0
      volclient.h
  17. 55
    0
      volume_manager/Android.bp
  18. 393
    0
      volume_manager/Disk.cpp
  19. 124
    0
      volume_manager/Disk.h
  20. 80
    0
      volume_manager/DiskPartition.cpp
  21. 54
    0
      volume_manager/DiskPartition.h
  22. 97
    0
      volume_manager/EmulatedVolume.cpp
  23. 62
    0
      volume_manager/EmulatedVolume.h
  24. 57
    0
      volume_manager/NetlinkHandler.cpp
  25. 34
    0
      volume_manager/NetlinkHandler.h
  26. 105
    0
      volume_manager/NetlinkManager.cpp
  27. 44
    0
      volume_manager/NetlinkManager.h
  28. 218
    0
      volume_manager/Process.cpp
  29. 35
    0
      volume_manager/Process.h
  30. 158
    0
      volume_manager/PublicVolume.cpp
  31. 75
    0
      volume_manager/PublicVolume.h
  32. 42
    0
      volume_manager/ResponseCode.cpp
  33. 90
    0
      volume_manager/ResponseCode.h
  34. 336
    0
      volume_manager/Utils.cpp
  35. 87
    0
      volume_manager/Utils.h
  36. 193
    0
      volume_manager/VolumeBase.cpp
  37. 137
    0
      volume_manager/VolumeBase.h
  38. 414
    0
      volume_manager/VolumeManager.cpp
  39. 79
    0
      volume_manager/fs/Exfat.cpp
  40. 38
    0
      volume_manager/fs/Exfat.h
  41. 170
    0
      volume_manager/fs/Ext4.cpp
  42. 40
    0
      volume_manager/fs/Ext4.h
  43. 93
    0
      volume_manager/fs/F2fs.cpp
  44. 39
    0
      volume_manager/fs/F2fs.h
  45. 84
    0
      volume_manager/fs/Ntfs.cpp
  46. 38
    0
      volume_manager/fs/Ntfs.h
  47. 171
    0
      volume_manager/fs/Vfat.cpp
  48. 39
    0
      volume_manager/fs/Vfat.h
  49. 131
    0
      volume_manager/include/volume_manager/VolumeManager.h
  50. 24
    0
      volume_manager/sehandle.h

+ 1
- 0
Android.bp View File

@@ -5,4 +5,5 @@ subdirs = [
5 5
     "otafault",
6 6
     "otautil",
7 7
     "uncrypt",
8
+    "volume_manager",
8 9
 ]

+ 3
- 0
Android.mk View File

@@ -64,6 +64,7 @@ LOCAL_STATIC_LIBRARIES := \
64 64
     libcrypto \
65 65
     libbase \
66 66
     libziparchive \
67
+    libvolume_manager \
67 68
 
68 69
 include $(BUILD_STATIC_LIBRARY)
69 70
 
@@ -80,6 +81,7 @@ LOCAL_SRC_FILES := \
80 81
     rotate_logs.cpp \
81 82
     screen_ui.cpp \
82 83
     ui.cpp \
84
+    volclient.cpp \
83 85
     vr_ui.cpp \
84 86
     wear_ui.cpp \
85 87
 
@@ -166,6 +168,7 @@ LOCAL_STATIC_LIBRARIES += \
166 168
     libsparse \
167 169
     libreboot \
168 170
     libziparchive \
171
+    libvolume_manager \
169 172
     libminipigz_static \
170 173
     libzopfli_static \
171 174
     libminizip_static \

+ 5
- 4
device.cpp View File

@@ -19,8 +19,7 @@
19 19
 static const char* MENU_ITEMS[] = {
20 20
   "Reboot system now",
21 21
   "Reboot to bootloader",
22
-  "Apply update from ADB",
23
-  "Apply update from SD card",
22
+  "Apply update",
24 23
   "Wipe data/factory reset",
25 24
 #ifndef AB_OTA_UPDATER
26 25
   "Wipe cache partition",
@@ -36,8 +35,7 @@ static const char* MENU_ITEMS[] = {
36 35
 static const Device::BuiltinAction MENU_ACTIONS[] = {
37 36
   Device::REBOOT,
38 37
   Device::REBOOT_BOOTLOADER,
39
-  Device::APPLY_ADB_SIDELOAD,
40
-  Device::APPLY_SDCARD,
38
+  Device::APPLY_UPDATE,
41 39
   Device::WIPE_DATA,
42 40
 #ifndef AB_OTA_UPDATER
43 41
   Device::WIPE_CACHE,
@@ -94,6 +92,9 @@ int Device::HandleMenuKey(int key, bool visible) {
94 92
     case KEY_BACK:
95 93
       return kGoBack;
96 94
 
95
+    case KEY_REFRESH:
96
+      return kRefresh;
97
+
97 98
     default:
98 99
       // If you have all of the above buttons, any other buttons
99 100
       // are ignored. Otherwise, any button cycles the highlight.

+ 5
- 2
device.h View File

@@ -56,9 +56,9 @@ class Device {
56 56
   enum BuiltinAction {
57 57
     NO_ACTION = 0,
58 58
     REBOOT = 1,
59
-    APPLY_SDCARD = 2,
59
+    APPLY_UPDATE = 2,
60 60
     // APPLY_CACHE was 3.
61
-    APPLY_ADB_SIDELOAD = 4,
61
+    // APPLY_ADB_SIDELOAD was 4.
62 62
     WIPE_DATA = 5,
63 63
     WIPE_CACHE = 6,
64 64
     REBOOT_BOOTLOADER = 7,
@@ -87,6 +87,7 @@ class Device {
87 87
   static const int kInvokeItem = -4;
88 88
   static const int kGoBack = -5;
89 89
   static const int kGoHome = -6;
90
+  static const int kRefresh = -7;
90 91
 
91 92
   // Called before and after we do a wipe data/factory reset operation, either via a reboot from the
92 93
   // main system with the --wipe_data flag, or when the user boots into recovery image manually and
@@ -101,6 +102,8 @@ class Device {
101 102
     return true;
102 103
   }
103 104
 
105
+  virtual void handleVolumeChanged() { ui_->onVolumeChanged(); }
106
+
104 107
  private:
105 108
   RecoveryUI* ui_;
106 109
 };

+ 20
- 0
etc/init.rc View File

@@ -27,6 +27,16 @@ on init
27 27
     chown root shell /tmp
28 28
     chmod 0775 /tmp
29 29
 
30
+    mkdir /mnt 0775 root system
31
+    mkdir /storage 0050 root sdcard_r
32
+    mount tmpfs tmpfs /storage mode=0050,uid=0,gid=1028
33
+
34
+    # See storage config details at http://source.android.com/tech/storage/
35
+    mkdir /mnt/shell 0700 shell shell
36
+
37
+    # Directory for staging bindmounts
38
+    mkdir /mnt/staging 0700 root root
39
+
30 40
     write /proc/sys/kernel/panic_on_oops 1
31 41
     write /proc/sys/vm/max_map_count 1000000
32 42
 
@@ -112,3 +122,13 @@ on property:lineage.service.adb.root=1
112 122
     write /sys/class/android_usb/android0/enable 0
113 123
     restart adbd
114 124
     write /sys/class/android_usb/android0/enable 1
125
+
126
+on property:sys.storage.ums_enabled=1
127
+    write /sys/class/android_usb/android0/enable 0
128
+    write /sys/class/android_usb/android0/functions adb,mass_storage
129
+    write /sys/class/android_usb/android0/enable 1
130
+
131
+on property:sys.storage.ums_enabled=0
132
+    write /sys/class/android_usb/android0/enable 0
133
+    write /sys/class/android_usb/android0/functions adb
134
+    write /sys/class/android_usb/android0/enable ${lineage.service.adb.root}

+ 0
- 4
fuse_sdcard_provider.cpp View File

@@ -114,10 +114,6 @@ void* start_sdcard_fuse(const char* path) {
114 114
     }
115 115
   }
116 116
 
117
-  // The installation process expects to find the sdcard unmounted. Unmount it with MNT_DETACH so
118
-  // that our open file continues to work but new references see it as unmounted.
119
-  umount2("/sdcard", MNT_DETACH);
120
-
121 117
   return t;
122 118
 }
123 119
 

+ 18
- 1
install.cpp View File

@@ -561,7 +561,7 @@ bool verify_package_compatibility(ZipArchiveHandle package_zip) {
561 561
   return false;
562 562
 }
563 563
 
564
-static int really_install_package(const std::string& path, bool* wipe_cache, bool needs_mount,
564
+static int really_install_package(std::string path, bool* wipe_cache, bool needs_mount,
565 565
                                   std::vector<std::string>* log_buffer, int retry_count,
566 566
                                   int* max_temperature) {
567 567
   ui->SetBackground(RecoveryUI::INSTALLING_UPDATE);
@@ -569,6 +569,23 @@ static int really_install_package(const std::string& path, bool* wipe_cache, boo
569 569
   // Give verification half the progress bar...
570 570
   ui->SetProgressType(RecoveryUI::DETERMINATE);
571 571
   ui->ShowProgress(VERIFICATION_PROGRESS_FRACTION, VERIFICATION_PROGRESS_TIME);
572
+
573
+    // Resolve symlink in case legacy /sdcard path is used
574
+    // Requires: symlink uses absolute path
575
+    if (path.size() > 1) {
576
+      size_t root_pos = path.find('/', 1);
577
+      if (root_pos != std::string::npos) {
578
+        char link_path[PATH_MAX];
579
+        ssize_t link_len;
580
+        memset(link_path, 0, sizeof(link_path));
581
+        link_len = readlink(path.substr(0, root_pos).c_str(),
582
+                            link_path, sizeof(link_path)-1);
583
+        if (link_len > 0) {
584
+          path = link_path + path.substr(root_pos);
585
+        }
586
+      }
587
+    }
588
+
572 589
   LOG(INFO) << "Update location: " << path;
573 590
 
574 591
   // Map the update package into memory.

+ 12
- 0
mounts.cpp View File

@@ -80,3 +80,15 @@ int unmount_mounted_volume(MountedVolume* volume) {
80 80
   }
81 81
   return result;
82 82
 }
83
+
84
+int unmount_mounted_volume_detach(MountedVolume* volume) {
85
+  // Intentionally pass the empty string to umount if the caller tries to unmount a volume they
86
+  // already unmounted using this function.
87
+  std::string mount_point = volume->mount_point;
88
+  volume->mount_point.clear();
89
+  int result = umount2(mount_point.c_str(), MNT_DETACH);
90
+  if (result == -1) {
91
+    PLOG(WARNING) << "Failed to umount " << mount_point;
92
+  }
93
+  return result;
94
+}

+ 1
- 0
mounts.h View File

@@ -24,5 +24,6 @@ bool scan_mounted_volumes();
24 24
 MountedVolume* find_mounted_volume_by_mount_point(const char* mount_point);
25 25
 
26 26
 int unmount_mounted_volume(MountedVolume* volume);
27
+int unmount_mounted_volume_detach(MountedVolume* volume);
27 28
 
28 29
 #endif

+ 104
- 28
recovery.cpp View File

@@ -56,6 +56,7 @@
56 56
 #include <selinux/label.h>
57 57
 #include <selinux/selinux.h>
58 58
 #include <ziparchive/zip_archive.h>
59
+#include <volume_manager/VolumeManager.h>
59 60
 
60 61
 #include "adb_install.h"
61 62
 #include "common.h"
@@ -72,6 +73,7 @@
72 73
 #include "screen_ui.h"
73 74
 #include "stub_ui.h"
74 75
 #include "ui.h"
76
+#include "volclient.h"
75 77
 
76 78
 // For e2fsprogs
77 79
 extern "C" {
@@ -136,6 +138,9 @@ struct recovery_cmd get_command(char* command) {
136 138
   return recovery_cmds[i];
137 139
 }
138 140
 
141
+using android::volmgr::VolumeInfo;
142
+using android::volmgr::VolumeManager;
143
+
139 144
 static const struct option OPTIONS[] = {
140 145
   { "update_package", required_argument, NULL, 'u' },
141 146
   { "retry_count", required_argument, NULL, 'n' },
@@ -171,7 +176,6 @@ static const char *CONVERT_FBE_FILE = "/tmp/convert_fbe/convert_fbe";
171 176
 static const char *CACHE_ROOT = "/cache";
172 177
 static const char *DATA_ROOT = "/data";
173 178
 static const char* METADATA_ROOT = "/metadata";
174
-static const char *SDCARD_ROOT = "/sdcard";
175 179
 static const char *TEMPORARY_LOG_FILE = "/tmp/recovery.log";
176 180
 static const char *TEMPORARY_INSTALL_FILE = "/tmp/last_install";
177 181
 static const char *LAST_KMSG_FILE = "/cache/recovery/last_kmsg";
@@ -724,8 +728,8 @@ static bool erase_volume(const char* volume) {
724 728
 // return a positive number beyond the given range. Caller sets 'menu_only' to true to ensure only
725 729
 // a menu item gets selected. 'initial_selection' controls the initial cursor location. Returns the
726 730
 // (non-negative) chosen item number, or -1 if timed out waiting for input.
727
-static int get_menu_selection(const char* const* headers, const char* const* items, bool menu_only,
728
-                              int initial_selection, Device* device) {
731
+int get_menu_selection(const char* const* headers, const char* const* items, bool menu_only,
732
+                       int initial_selection, Device* device) {
729 733
   // Throw away keys pressed previously, so user doesn't accidentally trigger menu items.
730 734
   ui->FlushKeys();
731 735
 
@@ -767,12 +771,16 @@ static int get_menu_selection(const char* const* headers, const char* const* ite
767 771
         case Device::kGoHome:
768 772
           chosen_item = Device::kGoHome;
769 773
           break;
774
+        case Device::kRefresh:
775
+          chosen_item = Device::kRefresh;
776
+          break;
770 777
       }
771 778
     } else if (!menu_only) {
772 779
       chosen_item = action;
773 780
     }
774 781
     if (chosen_item == Device::kGoBack ||
775
-        chosen_item == Device::kGoHome) {
782
+        chosen_item == Device::kGoHome ||
783
+        chosen_item == Device::kRefresh) {
776 784
       break;
777 785
     }
778 786
   }
@@ -783,8 +791,6 @@ static int get_menu_selection(const char* const* headers, const char* const* ite
783 791
 
784 792
 // Returns the selected filename, or an empty string.
785 793
 static std::string browse_directory(const std::string& path, Device* device) {
786
-  ensure_path_mounted(path.c_str());
787
-
788 794
   std::unique_ptr<DIR, decltype(&closedir)> d(opendir(path.c_str()), closedir);
789 795
   if (!d) {
790 796
     PLOG(ERROR) << "error opening " << path;
@@ -831,6 +837,9 @@ static std::string browse_directory(const std::string& path, Device* device) {
831 837
       // Go up but continue browsing (if the caller is browse_directory).
832 838
       return "";
833 839
     }
840
+    if (chosen_item == Device::kRefresh) {
841
+      return "@refresh";
842
+    }
834 843
 
835 844
     const std::string& item = zips[chosen_item];
836 845
 
@@ -852,8 +861,11 @@ static std::string browse_directory(const std::string& path, Device* device) {
852 861
 static bool yes_no(Device* device, const char* question1, const char* question2) {
853 862
     const char* headers[] = { question1, question2, NULL };
854 863
     const char* items[] = { " No", " Yes", NULL };
855
-
856
-    int chosen_item = get_menu_selection(headers, items, true, 0, device);
864
+    int chosen_item;
865
+    do {
866
+        chosen_item = get_menu_selection(headers, items, true, 0, device);
867
+    }
868
+    while (chosen_item == Device::kRefresh);
857 869
     return (chosen_item == 1);
858 870
 }
859 871
 
@@ -1150,33 +1162,90 @@ static void run_graphics_test() {
1150 1162
   ui->ShowText(true);
1151 1163
 }
1152 1164
 
1153
-static int apply_from_sdcard(Device* device, bool* wipe_cache) {
1165
+static int apply_from_storage(Device* device, VolumeInfo& vi, bool* wipe_cache) {
1154 1166
     modified_flash = true;
1155 1167
 
1156
-    if (ensure_path_mounted(SDCARD_ROOT) != 0) {
1157
-        ui->Print("\n-- Couldn't mount %s.\n", SDCARD_ROOT);
1168
+    int status;
1169
+
1170
+    if (!VolumeManager::Instance()->volumeMount(vi.mId)) {
1158 1171
         return INSTALL_ERROR;
1159 1172
     }
1160 1173
 
1161
-    std::string path = browse_directory(SDCARD_ROOT, device);
1162
-    if (path == "@") {
1163
-        return INSTALL_NONE;
1174
+    std::string path;
1175
+    do {
1176
+        path = browse_directory(vi.mPath, device);
1177
+        if (path == "@") {
1178
+            return INSTALL_NONE;
1179
+        }
1164 1180
     }
1181
+    while (path == "@refresh");
1182
+
1165 1183
     if (path.empty()) {
1166 1184
         ui->Print("\n-- No package file selected.\n");
1167
-        ensure_path_unmounted(SDCARD_ROOT);
1168
-        return INSTALL_ERROR;
1185
+        VolumeManager::Instance()->volumeUnmount(vi.mId);
1186
+        return INSTALL_NONE;
1169 1187
     }
1170 1188
 
1171 1189
     ui->Print("\n-- Install %s ...\n", path.c_str());
1172 1190
     set_sdcard_update_bootloader_message();
1173 1191
     void* token = start_sdcard_fuse(path.c_str());
1192
+    if (!token) {
1193
+        LOG(ERROR) << "Failed to start FUSE for sdcard install";
1194
+        return INSTALL_ERROR;
1195
+    }
1174 1196
 
1175
-    int status = install_package(FUSE_SIDELOAD_HOST_PATHNAME, wipe_cache,
1197
+    VolumeManager::Instance()->volumeUnmount(vi.mId, true);
1198
+
1199
+    status = install_package(FUSE_SIDELOAD_HOST_PATHNAME, wipe_cache,
1176 1200
                                  TEMPORARY_INSTALL_FILE, false, 0/*retry_count*/);
1177 1201
 
1178 1202
     finish_sdcard_fuse(token);
1179
-    ensure_path_unmounted(SDCARD_ROOT);
1203
+    return status;
1204
+}
1205
+
1206
+static int
1207
+show_apply_update_menu(Device* device, bool* wipe_cache) {
1208
+    static const char* headers[] = { "Apply update", nullptr };
1209
+    char* menu_items[MAX_NUM_MANAGED_VOLUMES + 1 + 1];
1210
+
1211
+    const int item_sideload = 0;
1212
+    int n, i;
1213
+
1214
+refresh:
1215
+    menu_items[item_sideload] = strdup("Apply from ADB");
1216
+
1217
+    std::vector<VolumeInfo> volumes;
1218
+    VolumeManager::Instance()->getVolumeInfo(volumes);
1219
+
1220
+    n = item_sideload + 1;
1221
+    for (auto& vitr : volumes) {
1222
+        menu_items[n] = (char*)malloc(256);
1223
+        sprintf(menu_items[n], "Choose from %s", vitr.mLabel.c_str());
1224
+        ++n;
1225
+    }
1226
+    menu_items[n] = nullptr;
1227
+
1228
+    int status = INSTALL_ERROR;
1229
+
1230
+    for (;;) {
1231
+        int chosen = get_menu_selection(headers, menu_items, 0, 0, device);
1232
+        for (i = 0; i < n; ++i) {
1233
+            free(menu_items[i]);
1234
+        }
1235
+        if (chosen == Device::kRefresh) {
1236
+            goto refresh;
1237
+        }
1238
+        if (chosen == Device::kGoBack) {
1239
+            break;
1240
+        }
1241
+        if (chosen == item_sideload) {
1242
+            status = apply_from_adb(wipe_cache, TEMPORARY_INSTALL_FILE);
1243
+        }
1244
+        else {
1245
+            status = apply_from_storage(device, volumes[chosen - 1], wipe_cache);
1246
+        }
1247
+    }
1248
+
1180 1249
     return status;
1181 1250
 }
1182 1251
 
@@ -1201,7 +1270,8 @@ static Device::BuiltinAction prompt_and_wait(Device* device, int status) {
1201 1270
     int chosen_item = get_menu_selection(nullptr, device->GetMenuItems(), false, 0, device);
1202 1271
     // We are already in the main menu
1203 1272
     if (chosen_item == Device::kGoBack ||
1204
-        chosen_item == Device::kGoHome) {
1273
+        chosen_item == Device::kGoHome ||
1274
+        chosen_item == Device::kRefresh) {
1205 1275
       continue;
1206 1276
     }
1207 1277
 
@@ -1236,15 +1306,9 @@ static Device::BuiltinAction prompt_and_wait(Device* device, int status) {
1236 1306
         if (!ui->IsTextVisible()) return Device::NO_ACTION;
1237 1307
         break;
1238 1308
 
1239
-      case Device::APPLY_ADB_SIDELOAD:
1240
-      case Device::APPLY_SDCARD:
1309
+      case Device::APPLY_UPDATE:
1241 1310
         {
1242
-          bool adb = (chosen_action == Device::APPLY_ADB_SIDELOAD);
1243
-          if (adb) {
1244
-            status = apply_from_adb(&should_wipe_cache, TEMPORARY_INSTALL_FILE);
1245
-          } else {
1246
-            status = apply_from_sdcard(device, &should_wipe_cache);
1247
-          }
1311
+          status = show_apply_update_menu(device, &should_wipe_cache);
1248 1312
 
1249 1313
           if (status == INSTALL_SUCCESS && should_wipe_cache) {
1250 1314
             if (!wipe_cache(false, device)) {
@@ -1259,7 +1323,7 @@ static Device::BuiltinAction prompt_and_wait(Device* device, int status) {
1259 1323
           } else if (!ui->IsTextVisible()) {
1260 1324
             return Device::NO_ACTION;  // reboot if logs aren't visible
1261 1325
           } else {
1262
-            ui->Print("\nInstall from %s complete.\n", adb ? "ADB" : "SD card");
1326
+            ui->Print("\nInstall complete.\n");
1263 1327
           }
1264 1328
         }
1265 1329
         break;
@@ -1682,6 +1746,12 @@ int main(int argc, char **argv) {
1682 1746
     }
1683 1747
   }
1684 1748
 
1749
+  VolumeClient* volclient = new VolumeClient(device);
1750
+  VolumeManager* volmgr = VolumeManager::Instance();
1751
+  if (!volmgr->start(volclient)) {
1752
+      printf("Failed to start volume manager\n");
1753
+  }
1754
+
1685 1755
   // Set background string to "installing security update" for security update,
1686 1756
   // otherwise set it to "installing system update".
1687 1757
   ui->SetSystemUpdateText(security_update);
@@ -1847,6 +1917,12 @@ int main(int argc, char **argv) {
1847 1917
   // Save logs and clean up before rebooting or shutting down.
1848 1918
   finish_recovery();
1849 1919
 
1920
+  volmgr->unmountAll();
1921
+  volmgr->stop();
1922
+  delete volclient;
1923
+
1924
+  sync();
1925
+
1850 1926
   switch (after) {
1851 1927
     case Device::SHUTDOWN:
1852 1928
       ui->Print("Shutting down...\n");

+ 74
- 10
roots.cpp View File

@@ -19,6 +19,7 @@
19 19
 #include <ctype.h>
20 20
 #include <fcntl.h>
21 21
 #include <stdint.h>
22
+#include <dirent.h>
22 23
 #include <stdlib.h>
23 24
 #include <string.h>
24 25
 #include <sys/mount.h>
@@ -35,6 +36,7 @@
35 36
 #include <android-base/properties.h>
36 37
 #include <android-base/stringprintf.h>
37 38
 #include <android-base/unique_fd.h>
39
+#include <cutils/fs.h>
38 40
 #include <cryptfs.h>
39 41
 #include <ext4_utils/wipe.h>
40 42
 #include <fs_mgr.h>
@@ -59,6 +61,14 @@ static void write_fstab_entry(const Volume *v, FILE *file)
59 61
   }
60 62
 }
61 63
 
64
+int get_num_volumes() {
65
+  return fstab->num_entries;
66
+}
67
+
68
+Volume* get_device_volumes() {
69
+  return fstab->recs;
70
+}
71
+
62 72
 void load_volume_table() {
63 73
   fstab = fs_mgr_read_fstab_default();
64 74
   if (!fstab) {
@@ -122,6 +132,17 @@ static Volume* volume_for_path(const char* path) {
122 132
   return nullptr;
123 133
 }
124 134
 
135
+Volume* volume_for_label(const char* label) {
136
+  int i;
137
+  for (i = 0; i < get_num_volumes(); i++) {
138
+    Volume* v = get_device_volumes() + i;
139
+    if (v->label && !strcmp(v->label, label)) {
140
+      return v;
141
+    }
142
+  }
143
+  return nullptr;
144
+}
145
+
125 146
 // Mount the volume specified by path at the given mount_point.
126 147
 int ensure_path_mounted_at(const char* path, const char* mount_point) {
127 148
   Volume* v = volume_for_path(path);
@@ -143,13 +164,15 @@ int ensure_path_mounted_at(const char* path, const char* mount_point) {
143 164
     mount_point = v->mount_point;
144 165
   }
145 166
 
146
-  const MountedVolume* mv = find_mounted_volume_by_mount_point(mount_point);
147
-  if (mv != nullptr) {
148
-    // Volume is already mounted.
149
-    return 0;
167
+  if (!fs_mgr_is_voldmanaged(v)) {
168
+    const MountedVolume* mv = find_mounted_volume_by_mount_point(mount_point);
169
+    if (mv) {
170
+      // volume is already mounted
171
+      return 0;
172
+    }
150 173
   }
151 174
 
152
-  mkdir(mount_point, 0755);  // in case it doesn't already exist
175
+  fs_mkdirs(mount_point, 0755);  // in case it doesn't already exist
153 176
 
154 177
   if (strcmp(v->fs_type, "ext4") == 0 || strcmp(v->fs_type, "squashfs") == 0 ||
155 178
       strcmp(v->fs_type, "vfat") == 0) {
@@ -165,15 +188,44 @@ int ensure_path_mounted_at(const char* path, const char* mount_point) {
165 188
   return -1;
166 189
 }
167 190
 
191
+int ensure_volume_mounted(Volume* v) {
192
+  if (v == nullptr) {
193
+    LOG(ERROR) << "cannot mount unknown volume";
194
+    return -1;
195
+  }
196
+  return ensure_path_mounted_at(v->mount_point, nullptr);
197
+}
198
+
168 199
 int ensure_path_mounted(const char* path) {
169 200
   // Mount at the default mount point.
170 201
   return ensure_path_mounted_at(path, nullptr);
171 202
 }
172 203
 
173
-int ensure_path_unmounted(const char* path) {
174
-  const Volume* v = volume_for_path(path);
204
+int ensure_path_unmounted(const char* path, bool detach /* = false */) {
205
+  const Volume* v;
206
+  if (memcmp(path, "/storage/", 9) == 0) {
207
+    char label[PATH_MAX];
208
+    const char* p = path+9;
209
+    const char* q = strchr(p, '/');
210
+    memset(label, 0, sizeof(label));
211
+    if (q) {
212
+      memcpy(label, p, q-p);
213
+    }
214
+    else {
215
+      strcpy(label, p);
216
+    }
217
+    v = volume_for_label(label);
218
+  }
219
+  else {
220
+      v = volume_for_path(path);
221
+  }
222
+
223
+  return ensure_volume_unmounted(v, detach);
224
+}
225
+
226
+int ensure_volume_unmounted(const Volume* v, bool detach /* = false */) {
175 227
   if (v == nullptr) {
176
-    LOG(ERROR) << "unknown volume for path [" << path << "]";
228
+    LOG(ERROR) << "cannot unmount unknown volume";
177 229
     return -1;
178 230
   }
179 231
   if (strcmp(v->fs_type, "ramdisk") == 0) {
@@ -192,7 +244,9 @@ int ensure_path_unmounted(const char* path) {
192 244
     return 0;
193 245
   }
194 246
 
195
-  return unmount_mounted_volume(mv);
247
+  return (detach ?
248
+          unmount_mounted_volume_detach(mv) :
249
+          unmount_mounted_volume(mv));
196 250
 }
197 251
 
198 252
 static int exec_cmd(const std::vector<std::string>& args) {
@@ -295,6 +349,11 @@ int format_volume(const char* volume, const char* directory) {
295 349
     }
296 350
   }
297 351
 
352
+  if (fs_mgr_is_voldmanaged(v)) {
353
+    LOG(ERROR) << "can't format vold volume \"" << volume << "\"";
354
+    return -1;
355
+  }
356
+
298 357
   if (strcmp(v->fs_type, "ext4") == 0) {
299 358
     static constexpr int kBlockSize = 4096;
300 359
     std::vector<std::string> mke2fs_args = {
@@ -400,7 +459,12 @@ int setup_install_mounts() {
400 459
         return -1;
401 460
       }
402 461
     } else {
403
-      if (ensure_path_unmounted(v->mount_point) != 0) {
462
+      // datam must be unmounted with the detach flag to ensure that FUSE works.
463
+      bool detach = false;
464
+      if (strcmp(v->mount_point, "/data") == 0) {
465
+        detach = true;
466
+      }
467
+      if (ensure_volume_unmounted(v, detach) != 0) {
404 468
         LOG(ERROR) << "Failed to unmount " << v->mount_point;
405 469
         return -1;
406 470
       }

+ 7
- 1
roots.h View File

@@ -29,6 +29,7 @@ Volume* volume_for_mount_point(const std::string& mount_point);
29 29
 
30 30
 // Make sure that the volume 'path' is on is mounted.  Returns 0 on
31 31
 // success (volume is mounted).
32
+int ensure_volume_mounted(Volume* v);
32 33
 int ensure_path_mounted(const char* path);
33 34
 
34 35
 // Similar to ensure_path_mounted, but allows one to specify the mount_point.
@@ -36,7 +37,8 @@ int ensure_path_mounted_at(const char* path, const char* mount_point);
36 37
 
37 38
 // Make sure that the volume 'path' is on is unmounted.  Returns 0 on
38 39
 // success (volume is unmounted);
39
-int ensure_path_unmounted(const char* path);
40
+int ensure_volume_unmounted(const Volume *v, bool detach=false);
41
+int ensure_path_unmounted(const char* path, bool detach=false);
40 42
 
41 43
 // Reformat the given volume (must be the mount point only, eg
42 44
 // "/cache"), no paths permitted.  Attempts to unmount the volume if
@@ -53,4 +55,8 @@ int format_volume(const char* volume, const char* directory);
53 55
 // mounted (/tmp and /cache) are mounted.  Returns 0 on success.
54 56
 int setup_install_mounts();
55 57
 
58
+int get_num_volumes();
59
+
60
+#define MAX_NUM_MANAGED_VOLUMES 10
61
+
56 62
 #endif  // RECOVERY_ROOTS_H_

+ 24
- 1
ui.cpp View File

@@ -41,6 +41,8 @@
41 41
 #include <cutils/android_reboot.h>
42 42
 #include <minui/minui.h>
43 43
 
44
+#include <volume_manager/VolumeManager.h>
45
+
44 46
 #include "common.h"
45 47
 #include "roots.h"
46 48
 #include "device.h"
@@ -74,6 +76,7 @@ RecoveryUI::RecoveryUI()
74 76
       has_touch_screen(false),
75 77
       touch_slot_(0),
76 78
       is_bootreason_recovery_ui_(false),
79
+      volumes_changed_(false),
77 80
       screensaver_state_(ScreensaverState::DISABLED) {
78 81
   pthread_mutex_init(&key_queue_mutex, nullptr);
79 82
   pthread_cond_init(&key_queue_cond, nullptr);
@@ -433,6 +436,7 @@ void RecoveryUI::ProcessKey(int key_code, int updown) {
433 436
 
434 437
       case RecoveryUI::REBOOT:
435 438
         if (reboot_enabled) {
439
+          android::volmgr::VolumeManager::Instance()->unmountAll();
436 440
           reboot("reboot,");
437 441
           while (true) {
438 442
             pause();
@@ -490,7 +494,20 @@ int RecoveryUI::WaitKey() {
490 494
 
491 495
     int rc = 0;
492 496
     while (key_queue_len == 0 && rc != ETIMEDOUT) {
493
-      rc = pthread_cond_timedwait(&key_queue_cond, &key_queue_mutex, &timeout);
497
+      struct timespec key_timeout;
498
+      gettimeofday(&now, nullptr);
499
+      key_timeout.tv_sec = now.tv_sec + 1;
500
+      key_timeout.tv_nsec = now.tv_usec * 1000;
501
+      rc = pthread_cond_timedwait(&key_queue_cond, &key_queue_mutex, &key_timeout);
502
+      if (rc == ETIMEDOUT) {
503
+        if (VolumesChanged()) {
504
+          pthread_mutex_unlock(&key_queue_mutex);
505
+          return KEY_REFRESH;
506
+        }
507
+        if (key_timeout.tv_sec <= timeout.tv_sec) {
508
+          rc = 0;
509
+        }
510
+      }
494 511
     }
495 512
 
496 513
     if (screensaver_state_ != ScreensaverState::DISABLED) {
@@ -637,3 +654,9 @@ void RecoveryUI::SetEnableReboot(bool enabled) {
637 654
   enable_reboot = enabled;
638 655
   pthread_mutex_unlock(&key_queue_mutex);
639 656
 }
657
+
658
+bool RecoveryUI::VolumesChanged() {
659
+    bool ret = volumes_changed_;
660
+    volumes_changed_ = false;
661
+    return ret;
662
+}

+ 7
- 0
ui.h View File

@@ -178,6 +178,9 @@ class RecoveryUI {
178 178
   // Ends menu mode, resetting the text overlay so that ui_print() statements will be displayed.
179 179
   virtual void EndMenu() = 0;
180 180
 
181
+  // Notify of volume state change
182
+  void onVolumeChanged() { volumes_changed_ = 1; }
183
+
181 184
  protected:
182 185
   void EnqueueKey(int key_code);
183 186
 
@@ -218,6 +221,8 @@ class RecoveryUI {
218 221
 
219 222
   bool IsUsbConnected();
220 223
 
224
+  bool VolumesChanged();
225
+
221 226
   static void* time_key_helper(void* cookie);
222 227
   void time_key(int key_code, int count);
223 228
 
@@ -259,6 +264,8 @@ class RecoveryUI {
259 264
 
260 265
   pthread_t input_thread_;
261 266
 
267
+  bool volumes_changed_;
268
+
262 269
   ScreensaverState screensaver_state_;
263 270
 
264 271
   // The following two contain the absolute values computed from brightness_normal_ and

+ 25
- 0
volclient.cpp View File

@@ -0,0 +1,25 @@
1
+/*
2
+ * Copyright (C) 2008 The Lineage Android Project
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *      http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+#include "volclient.h"
18
+
19
+void VolumeClient::handleEvent(int code, const std::vector<std::string>& argv)
20
+{
21
+printf("VolumeClient::handleEvent: code=%d, argv=<", code);
22
+for (auto& arg : argv) { printf("%s,", arg.c_str()); }
23
+printf(">\n");
24
+    mDevice->handleVolumeChanged();
25
+}

+ 33
- 0
volclient.h View File

@@ -0,0 +1,33 @@
1
+/*
2
+ * Copyright (C) 2008 The Lineage Android Project
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *      http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+#ifndef _RECOVERY_VOLCLIENT_H
18
+#define _RECOVERY_VOLCLIENT_H
19
+
20
+#include "device.h"
21
+#include <volume_manager/VolumeManager.h>
22
+
23
+class VolumeClient : public VolumeWatcher {
24
+public:
25
+    VolumeClient(Device* device) : mDevice(device) {}
26
+    virtual ~VolumeClient(void) {}
27
+    virtual void handleEvent(int code, const std::vector<std::string>& argv);
28
+
29
+private:
30
+    Device*     mDevice;
31
+};
32
+
33
+#endif

+ 55
- 0
volume_manager/Android.bp View File

@@ -0,0 +1,55 @@
1
+//
2
+// Copyright (C) 2018 The Lineage Android Project
3
+//
4
+// Licensed under the Apache License, Version 2.0 (the "License");
5
+// you may not use this file except in compliance with the License.
6
+// You may obtain a copy of the License at
7
+//
8
+//      http://www.apache.org/licenses/LICENSE-2.0
9
+//
10
+// Unless required by applicable law or agreed to in writing, software
11
+// distributed under the License is distributed on an "AS IS" BASIS,
12
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+// See the License for the specific language governing permissions and
14
+// limitations under the License.
15
+//
16
+
17
+cc_library_static {
18
+    name: "libvolume_manager",
19
+    srcs: [
20
+        "Disk.cpp",
21
+        "DiskPartition.cpp",
22
+        "EmulatedVolume.cpp",
23
+        "NetlinkHandler.cpp",
24
+        "NetlinkManager.cpp",
25
+        "Process.cpp",
26
+        "PublicVolume.cpp",
27
+        "Utils.cpp",
28
+        "VolumeBase.cpp",
29
+        "VolumeManager.cpp",
30
+        "fs/Exfat.cpp",
31
+        "fs/Ext4.cpp",
32
+        "fs/F2fs.cpp",
33
+        "fs/Ntfs.cpp",
34
+        "fs/Vfat.cpp",
35
+    ],
36
+    cflags: [
37
+        "-Wall",
38
+        "-Werror",
39
+    ],
40
+    include_dirs: [
41
+        "external/gptfdisk",
42
+    ],
43
+    static_libs: [
44
+        "libbase",
45
+        "libfs_mgr",
46
+        "libdiskconfig",
47
+        "libselinux",
48
+    ],
49
+    whole_static_libs: [
50
+        "libext2_blkid",
51
+        "libext2_uuid",
52
+        "libsysutils",
53
+    ],
54
+    export_include_dirs: ["include"],
55
+}

+ 393
- 0
volume_manager/Disk.cpp View File

@@ -0,0 +1,393 @@
1
+/*
2
+ * Copyright (C) 2015 The Android Open Source Project
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *      http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+#include "Disk.h"
18
+#include "PublicVolume.h"
19
+#include "Utils.h"
20
+#include "VolumeBase.h"
21
+#include <volume_manager/VolumeManager.h>
22
+#include "ResponseCode.h"
23
+
24
+#include <android-base/file.h>
25
+#include <android-base/properties.h>
26
+#include <android-base/stringprintf.h>
27
+#include <android-base/logging.h>
28
+#include <diskconfig/diskconfig.h>
29
+
30
+#include <sgdisk.h>
31
+
32
+#include <vector>
33
+#include <fcntl.h>
34
+#include <inttypes.h>
35
+#include <stdio.h>
36
+#include <stdlib.h>
37
+#include <sys/types.h>
38
+#include <sys/stat.h>
39
+#include <sys/sysmacros.h>
40
+#include <sys/mount.h>
41
+
42
+using android::base::ReadFileToString;
43
+using android::base::WriteStringToFile;
44
+using android::base::StringPrintf;
45
+
46
+namespace android {
47
+namespace volmgr {
48
+
49
+static const char* kSysfsLoopMaxMinors = "/sys/module/loop/parameters/max_part";
50
+static const char* kSysfsMmcMaxMinorsDeprecated = "/sys/module/mmcblk/parameters/perdev_minors";
51
+static const char* kSysfsMmcMaxMinors = "/sys/module/mmc_block/parameters/perdev_minors";
52
+
53
+static const unsigned int kMajorBlockLoop = 7;
54
+static const unsigned int kMajorBlockScsiA = 8;
55
+static const unsigned int kMajorBlockScsiB = 65;
56
+static const unsigned int kMajorBlockScsiC = 66;
57
+static const unsigned int kMajorBlockScsiD = 67;
58
+static const unsigned int kMajorBlockScsiE = 68;
59
+static const unsigned int kMajorBlockScsiF = 69;
60
+static const unsigned int kMajorBlockScsiG = 70;
61
+static const unsigned int kMajorBlockScsiH = 71;
62
+static const unsigned int kMajorBlockScsiI = 128;
63
+static const unsigned int kMajorBlockScsiJ = 129;
64
+static const unsigned int kMajorBlockScsiK = 130;
65
+static const unsigned int kMajorBlockScsiL = 131;
66
+static const unsigned int kMajorBlockScsiM = 132;
67
+static const unsigned int kMajorBlockScsiN = 133;
68
+static const unsigned int kMajorBlockScsiO = 134;
69
+static const unsigned int kMajorBlockScsiP = 135;
70
+static const unsigned int kMajorBlockMmc = 179;
71
+static const unsigned int kMajorBlockExperimentalMin = 240;
72
+static const unsigned int kMajorBlockExperimentalMax = 254;
73
+
74
+static const char* kGptBasicData = "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7";
75
+static const char* kGptLinuxFilesystem = "0FC63DAF-8483-4772-8E79-3D69D8477DE4";
76
+
77
+enum class Table {
78
+    kUnknown,
79
+    kMbr,
80
+    kGpt,
81
+};
82
+
83
+static bool isVirtioBlkDevice(unsigned int major) {
84
+    /*
85
+     * The new emulator's "ranchu" virtual board no longer includes a goldfish
86
+     * MMC-based SD card device; instead, it emulates SD cards with virtio-blk,
87
+     * which has been supported by upstream kernel and QEMU for quite a while.
88
+     * Unfortunately, the virtio-blk block device driver does not use a fixed
89
+     * major number, but relies on the kernel to assign one from a specific
90
+     * range of block majors, which are allocated for "LOCAL/EXPERIMENAL USE"
91
+     * per Documentation/devices.txt. This is true even for the latest Linux
92
+     * kernel (4.4; see init() in drivers/block/virtio_blk.c).
93
+     *
94
+     * This makes it difficult for vold to detect a virtio-blk based SD card.
95
+     * The current solution checks two conditions (both must be met):
96
+     *
97
+     *  a) If the running environment is the emulator;
98
+     *  b) If the major number is an experimental block device major number (for
99
+     *     x86/x86_64 3.10 ranchu kernels, virtio-blk always gets major number
100
+     *     253, but it is safer to match the range than just one value).
101
+     *
102
+     * Other conditions could be used, too, e.g. the hardware name should be
103
+     * "ranchu", the device's sysfs path should end with "/block/vd[d-z]", etc.
104
+     * But just having a) and b) is enough for now.
105
+     */
106
+    return IsRunningInEmulator() && major >= kMajorBlockExperimentalMin
107
+            && major <= kMajorBlockExperimentalMax;
108
+}
109
+
110
+Disk::Disk(const std::string& eventPath, dev_t device,
111
+        const std::string& nickname, int flags) :
112
+        mDevice(device), mSize(-1), mNickname(nickname), mFlags(flags), mCreated(
113
+                false), mSkipChange(false) {
114
+    mId = StringPrintf("disk:%u_%u", major(device), minor(device));
115
+    mEventPath = eventPath;
116
+    mSysPath = StringPrintf("/sys/%s", eventPath.c_str());
117
+    mDevPath = StringPrintf("/dev/block/volmgr/%s", mId.c_str());
118
+    CreateDeviceNode(mDevPath, mDevice);
119
+}
120
+
121
+Disk::~Disk() {
122
+    CHECK(!mCreated);
123
+    DestroyDeviceNode(mDevPath);
124
+}
125
+
126
+void Disk::getVolumeInfo(std::vector<VolumeInfo>& info) {
127
+    for (auto vol : mVolumes) {
128
+        info.push_back(VolumeInfo(vol.get()));
129
+    }
130
+}
131
+
132
+std::shared_ptr<VolumeBase> Disk::findVolume(const std::string& id) {
133
+    for (auto vol : mVolumes) {
134
+        if (vol->getId() == id) {
135
+            return vol;
136
+        }
137
+    }
138
+    return nullptr;
139
+}
140
+
141
+void Disk::listVolumes(VolumeBase::Type type, std::list<std::string>& list) {
142
+    for (const auto& vol : mVolumes) {
143
+        if (vol->getType() == type) {
144
+            list.push_back(vol->getId());
145
+        }
146
+        // TODO: consider looking at stacked volumes
147
+    }
148
+}
149
+
150
+status_t Disk::create() {
151
+    CHECK(!mCreated);
152
+    mCreated = true;
153
+    VolumeManager::Instance()->notifyEvent(ResponseCode::DiskCreated,
154
+                                           StringPrintf("%d", mFlags));
155
+    readMetadata();
156
+    readPartitions();
157
+    return OK;
158
+}
159
+
160
+status_t Disk::destroy() {
161
+    CHECK(mCreated);
162
+    destroyAllVolumes();
163
+    mCreated = false;
164
+    VolumeManager::Instance()->notifyEvent(ResponseCode::DiskDestroyed);
165
+    return OK;
166
+}
167
+
168
+void Disk::createPublicVolume(dev_t device,
169
+                const std::string& fstype /* = "" */,
170
+                const std::string& mntopts /* = "" */) {
171
+    auto vol = std::shared_ptr<VolumeBase>(new PublicVolume(device, mNickname, fstype, mntopts));
172
+
173
+    mVolumes.push_back(vol);
174
+    vol->setDiskId(getId());
175
+    vol->create();
176
+}
177
+
178
+void Disk::destroyAllVolumes() {
179
+    for (const auto& vol : mVolumes) {
180
+        vol->destroy();
181
+    }
182
+    mVolumes.clear();
183
+}
184
+
185
+status_t Disk::readMetadata() {
186
+
187
+    if (mSkipChange) {
188
+        return OK;
189
+    }
190
+
191
+    mSize = -1;
192
+    mLabel.clear();
193
+
194
+    int fd = open(mDevPath.c_str(), O_RDONLY | O_CLOEXEC);
195
+    if (fd != -1) {
196
+        if (ioctl(fd, BLKGETSIZE64, &mSize)) {
197
+            mSize = -1;
198
+        }
199
+        close(fd);
200
+    }
201
+
202
+    unsigned int majorId = major(mDevice);
203
+    switch (majorId) {
204
+    case kMajorBlockLoop: {
205
+        mLabel = "Virtual";
206
+        break;
207
+    }
208
+    case kMajorBlockScsiA: case kMajorBlockScsiB: case kMajorBlockScsiC: case kMajorBlockScsiD:
209
+    case kMajorBlockScsiE: case kMajorBlockScsiF: case kMajorBlockScsiG: case kMajorBlockScsiH:
210
+    case kMajorBlockScsiI: case kMajorBlockScsiJ: case kMajorBlockScsiK: case kMajorBlockScsiL:
211
+    case kMajorBlockScsiM: case kMajorBlockScsiN: case kMajorBlockScsiO: case kMajorBlockScsiP: {
212
+        std::string path(mSysPath + "/device/vendor");
213
+        std::string tmp;
214
+        if (!ReadFileToString(path, &tmp)) {
215
+            PLOG(WARNING) << "Failed to read vendor from " << path;
216
+            return -errno;
217
+        }
218
+        mLabel = tmp;
219
+        break;
220
+    }
221
+    case kMajorBlockMmc: {
222
+        std::string path(mSysPath + "/device/manfid");
223
+        std::string tmp;
224
+        if (!ReadFileToString(path, &tmp)) {
225
+            PLOG(WARNING) << "Failed to read manufacturer from " << path;
226
+            return -errno;
227
+        }
228
+        uint64_t manfid = strtoll(tmp.c_str(), nullptr, 16);
229
+        // Our goal here is to give the user a meaningful label, ideally
230
+        // matching whatever is silk-screened on the card.  To reduce
231
+        // user confusion, this list doesn't contain white-label manfid.
232
+        switch (manfid) {
233
+        case 0x000003: mLabel = "SanDisk"; break;
234
+        case 0x00001b: mLabel = "Samsung"; break;
235
+        case 0x000028: mLabel = "Lexar"; break;
236
+        case 0x000074: mLabel = "Transcend"; break;
237
+        }
238
+        break;
239
+    }
240
+    default: {
241
+        if (isVirtioBlkDevice(majorId)) {
242
+            LOG(DEBUG) << "Recognized experimental block major ID " << majorId
243
+                    << " as virtio-blk (emulator's virtual SD card device)";
244
+            mLabel = "Virtual";
245
+            break;
246
+        }
247
+        LOG(WARNING) << "Unsupported block major type " << majorId;
248
+        return -ENOTSUP;
249
+    }
250
+    }
251
+
252
+    VolumeManager::Instance()->notifyEvent(ResponseCode::DiskSizeChanged,
253
+                                           StringPrintf("%" PRIu64, mSize));
254
+    VolumeManager::Instance()->notifyEvent(ResponseCode::DiskLabelChanged,
255
+                                           mLabel);
256
+    VolumeManager::Instance()->notifyEvent(ResponseCode::DiskSysPathChanged,
257
+                                           mSysPath);
258
+    return OK;
259
+}
260
+
261
+status_t Disk::readPartitions() {
262
+    int8_t maxMinors = getMaxMinors();
263
+    if (maxMinors < 0) {
264
+        return -ENOTSUP;
265
+    }
266
+
267
+    if (mSkipChange) {
268
+        mSkipChange = false;
269
+        LOG(INFO) << "Skip first change";
270
+        return OK;
271
+    }
272
+
273
+    destroyAllVolumes();
274
+
275
+    // Parse partition table
276
+    sgdisk_partition_table ptbl;
277
+    std::vector<sgdisk_partition> partitions;
278
+    int res = sgdisk_read(mDevPath.c_str(), ptbl, partitions);
279
+    if (res != 0) {
280
+        LOG(WARNING) << "sgdisk failed to scan " << mDevPath;
281
+        VolumeManager::Instance()->notifyEvent(ResponseCode::DiskScanned);
282
+        return res;
283
+    }
284
+
285
+    Table table = Table::kUnknown;
286
+    bool foundParts = false;
287
+
288
+    switch (ptbl.type) {
289
+    case MBR:
290
+        table = Table::kMbr;
291
+        break;
292
+    case GPT:
293
+        table = Table::kGpt;
294
+    default:
295
+        table = Table::kUnknown;
296
+    }
297
+
298
+    foundParts = partitions.size() > 0;
299
+    for (const auto& part : partitions) {
300
+        if (part.num <= 0 || part.num > maxMinors) {
301
+            LOG(WARNING) << mId << " is ignoring partition " << part.num
302
+                    << " beyond max supported devices";
303
+            continue;
304
+        }
305
+        dev_t partDevice = makedev(major(mDevice), minor(mDevice) + part.num);
306
+        if (table == Table::kMbr) {
307
+            switch (strtol(part.type.c_str(), nullptr, 16)) {
308
+            case 0x06: // FAT16
309
+            case 0x07: // NTFS/exFAT
310
+            case 0x0b: // W95 FAT32 (LBA)
311
+            case 0x0c: // W95 FAT32 (LBA)
312
+            case 0x0e: // W95 FAT16 (LBA)
313
+            case 0x83: // Linux EXT4/F2FS/...
314
+                createPublicVolume(partDevice);
315
+                break;
316
+            }
317
+        }
318
+        else if (table == Table::kGpt) {
319
+            if (!strcasecmp(part.guid.c_str(), kGptBasicData)
320
+                    || !strcasecmp(part.guid.c_str(), kGptLinuxFilesystem)) {
321
+                createPublicVolume(partDevice);
322
+            }
323
+        }
324
+    }
325
+
326
+    // Ugly last ditch effort, treat entire disk as partition
327
+    if (table == Table::kUnknown || !foundParts) {
328
+        LOG(WARNING) << mId << " has unknown partition table; trying entire device";
329
+
330
+        std::string fsType;
331
+        std::string unused;
332
+        if (ReadMetadataUntrusted(mDevPath, fsType, unused, unused) == OK) {
333
+            createPublicVolume(mDevice);
334
+        } else {
335
+            LOG(WARNING) << mId << " failed to identify, giving up";
336
+        }
337
+    }
338
+
339
+    VolumeManager::Instance()->notifyEvent(ResponseCode::DiskScanned);
340
+    return OK;
341
+}
342
+
343
+status_t Disk::unmountAll() {
344
+    for (const auto& vol : mVolumes) {
345
+        vol->unmount();
346
+    }
347
+    return OK;
348
+}
349
+
350
+int Disk::getMaxMinors() {
351
+    // Figure out maximum partition devices supported
352
+    unsigned int majorId = major(mDevice);
353
+    switch (majorId) {
354
+    case kMajorBlockLoop: {
355
+        std::string tmp;
356
+        if (!ReadFileToString(kSysfsLoopMaxMinors, &tmp)) {
357
+            LOG(ERROR) << "Failed to read max minors";
358
+            return -errno;
359
+        }
360
+        return atoi(tmp.c_str());
361
+    }
362
+    case kMajorBlockScsiA: case kMajorBlockScsiB: case kMajorBlockScsiC: case kMajorBlockScsiD:
363
+    case kMajorBlockScsiE: case kMajorBlockScsiF: case kMajorBlockScsiG: case kMajorBlockScsiH:
364
+    case kMajorBlockScsiI: case kMajorBlockScsiJ: case kMajorBlockScsiK: case kMajorBlockScsiL:
365
+    case kMajorBlockScsiM: case kMajorBlockScsiN: case kMajorBlockScsiO: case kMajorBlockScsiP: {
366
+        // Per Documentation/devices.txt this is static
367
+        return 15;
368
+    }
369
+    case kMajorBlockMmc: {
370
+        // Per Documentation/devices.txt this is dynamic
371
+        std::string tmp;
372
+        if (!ReadFileToString(kSysfsMmcMaxMinors, &tmp) &&
373
+                !ReadFileToString(kSysfsMmcMaxMinorsDeprecated, &tmp)) {
374
+            LOG(ERROR) << "Failed to read max minors";
375
+            return -errno;
376
+        }
377
+        return atoi(tmp.c_str());
378
+    }
379
+    default: {
380
+        if (isVirtioBlkDevice(majorId)) {
381
+            // drivers/block/virtio_blk.c has "#define PART_BITS 4", so max is
382
+            // 2^4 - 1 = 15
383
+            return 15;
384
+        }
385
+    }
386
+    }
387
+
388
+    LOG(ERROR) << "Unsupported block major type " << majorId;
389
+    return -ENOTSUP;
390
+}
391
+
392
+}  // namespace volmgr
393
+}  // namespace android

+ 124
- 0
volume_manager/Disk.h View File

@@ -0,0 +1,124 @@
1
+/*
2
+ * Copyright (C) 2015 The Android Open Source Project
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *      http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+#ifndef ANDROID_VOLMGR_DISK_H
18
+#define ANDROID_VOLMGR_DISK_H
19
+
20
+#include "Utils.h"
21
+#include "VolumeBase.h"
22
+
23
+#include <utils/Errors.h>
24
+
25
+#include <vector>
26
+
27
+#include <volume_manager/VolumeManager.h>
28
+
29
+namespace android {
30
+namespace volmgr {
31
+
32
+class VolumeBase;
33
+
34
+/*
35
+ * Representation of detected physical media.
36
+ *
37
+ * Knows how to create volumes based on the partition tables found, and also
38
+ * how to repartition itself.
39
+ */
40
+class Disk {
41
+public:
42
+    Disk(const std::string& eventPath, dev_t device, const std::string& nickname, int flags);
43
+    virtual ~Disk();
44
+
45
+    enum Flags {
46
+        /* Flag that disk is adoptable */
47
+        kAdoptable = 1 << 0,
48
+        /* Flag that disk is considered primary when the user hasn't
49
+         * explicitly picked a primary storage location */
50
+        kDefaultPrimary = 1 << 1,
51
+        /* Flag that disk is SD card */
52
+        kSd = 1 << 2,
53
+        /* Flag that disk is USB disk */
54
+        kUsb = 1 << 3,
55
+        /* Flag that disk is EMMC internal */
56
+        kEmmc = 1 << 4,
57
+        /* Flag that disk is non-removable */
58
+        kNonRemovable = 1 << 5,
59
+    };
60
+
61
+    const std::string& getId() { return mId; }
62
+    const std::string& getEventPath() { return mEventPath; }
63
+    const std::string& getSysPath() { return mSysPath; }
64
+    const std::string& getDevPath() { return mDevPath; }
65
+    dev_t getDevice() { return mDevice; }
66
+    uint64_t getSize() { return mSize; }
67
+    const std::string& getLabel() { return mLabel; }
68
+    int getFlags() { return mFlags; }
69
+
70
+    void getVolumeInfo(std::vector<VolumeInfo>& info);
71
+
72
+    std::shared_ptr<VolumeBase> findVolume(const std::string& id);
73
+
74
+    void listVolumes(VolumeBase::Type type, std::list<std::string>& list);
75
+
76
+    virtual status_t create();
77
+    virtual status_t destroy();
78
+
79
+    virtual status_t readMetadata();
80
+    virtual status_t readPartitions();
81
+
82
+    status_t unmountAll();
83
+
84
+protected:
85
+    /* ID that uniquely references this disk */
86
+    std::string mId;
87
+    /* Original event path */
88
+    std::string mEventPath;
89
+    /* Device path under sysfs */
90
+    std::string mSysPath;
91
+    /* Device path under dev */
92
+    std::string mDevPath;
93
+    /* Kernel device representing disk */
94
+    dev_t mDevice;
95
+    /* Size of disk, in bytes */
96
+    uint64_t mSize;
97
+    /* User-visible label, such as manufacturer */
98
+    std::string mLabel;
99
+    /* Current partitions on disk */
100
+    std::vector<std::shared_ptr<VolumeBase>> mVolumes;
101
+    /* Nickname for this disk */
102
+    std::string mNickname;
103
+    /* Flags applicable to this disk */
104
+    int mFlags;
105
+    /* Flag indicating object is created */
106
+    bool mCreated;
107
+    /* Flag that we need to skip first disk change events after partitioning*/
108
+    bool mSkipChange;
109
+
110
+    void createPublicVolume(dev_t device,
111
+                    const std::string& fstype = "",
112
+                    const std::string& mntopts = "");
113
+
114
+    void destroyAllVolumes();
115
+
116
+    int getMaxMinors();
117
+
118
+    DISALLOW_COPY_AND_ASSIGN(Disk);
119
+};
120
+
121
+}  // namespace volmgr
122
+}  // namespace android
123
+
124
+#endif

+ 80
- 0
volume_manager/DiskPartition.cpp View File

@@ -0,0 +1,80 @@
1
+/*
2
+ * Copyright (C) 2015 Cyanogen, Inc.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *      http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+#include "DiskPartition.h"
18
+#include "PublicVolume.h"
19
+#include "Utils.h"
20
+#include "VolumeBase.h"
21
+#include <volume_manager/VolumeManager.h>
22
+#include "ResponseCode.h"
23
+
24
+#include <android-base/file.h>
25
+#include <android-base/stringprintf.h>
26
+#include <android-base/logging.h>
27
+#include <diskconfig/diskconfig.h>
28
+
29
+#include <vector>
30
+#include <fcntl.h>
31
+#include <inttypes.h>
32
+#include <stdio.h>
33
+#include <stdlib.h>
34
+#include <sys/types.h>
35
+#include <sys/sysmacros.h>
36
+#include <sys/stat.h>
37
+#include <sys/mount.h>
38
+
39
+using android::base::ReadFileToString;
40
+using android::base::WriteStringToFile;
41
+using android::base::StringPrintf;
42
+
43
+namespace android {
44
+namespace volmgr {
45
+
46
+DiskPartition::DiskPartition(const std::string& eventPath, dev_t device,
47
+            const std::string& nickname, int flags, int partnum,
48
+            const std::string& fstype /* = "" */, const std::string& mntopts /* = "" */) :
49
+        Disk(eventPath, device, nickname, flags),
50
+        mPartNum(partnum),
51
+        mFsType(fstype),
52
+        mMntOpts(mntopts) {
53
+    // Empty
54
+}
55
+
56
+DiskPartition::~DiskPartition() {
57
+    // Empty
58
+}
59
+
60
+status_t DiskPartition::create() {
61
+    CHECK(!mCreated);
62
+    mCreated = true;
63
+    VolumeManager::Instance()->notifyEvent(ResponseCode::DiskCreated,
64
+                                           StringPrintf("%d", mFlags));
65
+    dev_t partDevice = makedev(major(mDevice), minor(mDevice) + mPartNum);
66
+    createPublicVolume(partDevice, mFsType, mMntOpts);
67
+    return OK;
68
+}
69
+
70
+status_t DiskPartition::destroy() {
71
+    CHECK(mCreated);
72
+    destroyAllVolumes();
73
+    mCreated = false;
74
+    VolumeManager::Instance()->notifyEvent(ResponseCode::DiskDestroyed);
75
+    return OK;
76
+}
77
+
78
+}  // namespace volmgr
79
+}  // namespace android
80
+

+ 54
- 0
volume_manager/DiskPartition.h View File

@@ -0,0 +1,54 @@
1
+/*
2
+ * Copyright (C) 2015 Cyanogen, Inc.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *      http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+#ifndef ANDROID_VOLMGR_DISKPARTITION_H
18
+#define ANDROID_VOLMGR_DISKPARTITION_H
19
+
20
+#include "Disk.h"
21
+
22
+namespace android {
23
+namespace volmgr {
24
+
25
+/*
26
+ * Representation of a single partition on physical media.  Useful for
27
+ * single media partitions such as "internal" sdcard partitions.
28
+ */
29
+
30
+class DiskPartition : public Disk {
31
+public:
32
+    DiskPartition(const std::string& eventPath, dev_t device,
33
+            const std::string& nickname,
34
+             int flags, int partnum,
35
+            const std::string& fstype = "", const std::string& mntopts = "");
36
+    virtual ~DiskPartition();
37
+
38
+    virtual status_t create();
39
+    virtual status_t destroy();
40
+
41
+private:
42
+    /* Partition number */
43
+    int mPartNum;
44
+    /* Filesystem type */
45
+    std::string mFsType;
46
+    /* Mount options */
47
+    std::string mMntOpts;
48
+};
49
+
50
+}  // namespace volmgr
51
+}  // namespace android
52
+
53
+#endif
54
+

+ 97
- 0
volume_manager/EmulatedVolume.cpp View File

@@ -0,0 +1,97 @@
1
+/*
2
+ * Copyright (C) 2015 The Android Open Source Project
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *      http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+#include "Utils.h"
18
+#include "EmulatedVolume.h"
19
+#include <volume_manager/VolumeManager.h>
20
+#include "ResponseCode.h"
21
+
22
+#include <android-base/stringprintf.h>
23
+#include <android-base/logging.h>
24
+#include <cutils/fs.h>
25
+#include <private/android_filesystem_config.h>
26
+
27
+#include <fcntl.h>
28
+#include <stdlib.h>
29
+#include <sys/mount.h>
30
+#include <sys/stat.h>
31
+#include <sys/types.h>
32
+#include <sys/sysmacros.h>
33
+#include <sys/wait.h>
34
+
35
+#include <fs_mgr.h>
36
+
37
+using android::base::StringPrintf;
38
+
39
+namespace android {
40
+namespace volmgr {
41
+
42
+static const std::string kStagingPath = "/mnt/staging/emulated";
43
+
44
+EmulatedVolume::EmulatedVolume(fstab_rec* rec, const std::string& subdir) :
45
+        VolumeBase(Type::kEmulated),
46
+        mSubdir(subdir),
47
+        mDevPath(rec->blk_device),
48
+        mFsType(rec->fs_type),
49
+        mFlags(rec->flags),
50
+        mFsOptions(rec->fs_options) {
51
+    setId("emulated");
52
+    setPartLabel("emulated");
53
+    setPath("/storage/emulated");
54
+}
55
+
56
+EmulatedVolume::~EmulatedVolume() {
57
+}
58
+
59
+status_t EmulatedVolume::doMount() {
60
+    if (fs_prepare_dir(kStagingPath.c_str(), 0700, AID_ROOT, AID_ROOT)) {
61
+        PLOG(ERROR) << getId() << " failed to create mount points";
62
+        return -errno;
63
+    }
64
+    if (fs_prepare_dir(getPath().c_str(), 0700, AID_ROOT, AID_ROOT)) {
65
+        PLOG(ERROR) << getId() << " failed to create mount points";
66
+        return -errno;
67
+    }
68
+
69
+    std::string bindPath = kStagingPath + "/" + mSubdir;
70
+
71
+    if (::mount(mDevPath.c_str(), kStagingPath.c_str(),
72
+                mFsType.c_str(), mFlags, mFsOptions.c_str()) != 0) {
73
+        PLOG(ERROR) << getId() << " failed to mount " << mDevPath << " on " << kStagingPath;
74
+        return -EIO;
75
+    }
76
+    if (BindMount(bindPath, getPath()) != OK) {
77
+        PLOG(ERROR) << getId() << " failed to bind mount " << bindPath << " on " << getPath();
78
+        ForceUnmount(kStagingPath);
79
+        return -EIO;
80
+    }
81
+
82
+    return OK;
83
+}
84
+
85
+status_t EmulatedVolume::doUnmount(bool detach /* = false */) {
86
+
87
+    ForceUnmount(getPath(), detach);
88
+    ForceUnmount(kStagingPath, detach);
89
+
90
+    rmdir(getPath().c_str());
91
+    rmdir(kStagingPath.c_str());
92
+
93
+    return OK;
94
+}
95
+
96
+}  // namespace volmgr
97
+}  // namespace android

+ 62
- 0
volume_manager/EmulatedVolume.h View File

@@ -0,0 +1,62 @@
1
+/*
2
+ * Copyright (C) 2015 The Android Open Source Project
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *      http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+#ifndef ANDROID_VOLMGR_EMULATED_VOLUME_H
18
+#define ANDROID_VOLMGR_EMULATED_VOLUME_H
19
+
20
+#include "VolumeBase.h"
21
+
22
+#include <cutils/multiuser.h>
23
+
24
+struct fstab_rec;
25
+
26
+namespace android {
27
+namespace volmgr {
28
+
29
+/*
30
+ * Shared storage emulated on top of private storage.
31
+ *
32
+ * Knows how to spawn a FUSE daemon to synthesize permissions.  ObbVolume
33
+ * can be stacked above it.
34
+ *
35
+ * This volume is always multi-user aware, but is only binds itself to
36
+ * users when its primary storage.  This volume should never be presented
37
+ * as secondary storage, since we're strongly encouraging developers to
38
+ * store data local to their app.
39
+ */
40
+class EmulatedVolume : public VolumeBase {
41
+public:
42
+    explicit EmulatedVolume(fstab_rec* rec, const std::string& subdir);
43
+    virtual ~EmulatedVolume();
44
+
45
+protected:
46
+    status_t doMount() override;
47
+    status_t doUnmount(bool detach = false) override;
48
+
49
+private:
50
+    std::string         mSubdir;
51
+    std::string         mDevPath;
52
+    std::string         mFsType;
53
+    unsigned long       mFlags;
54
+    std::string         mFsOptions;
55
+
56
+    DISALLOW_COPY_AND_ASSIGN(EmulatedVolume);
57
+};
58
+
59
+}  // namespace volmgr
60
+}  // namespace android
61
+
62
+#endif

+ 57
- 0
volume_manager/NetlinkHandler.cpp View File

@@ -0,0 +1,57 @@
1
+/*
2
+ * Copyright (C) 2008 The Android Open Source Project
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *      http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+#include <stdio.h>
18
+#include <stdlib.h>
19
+#include <errno.h>
20
+#include <string.h>
21
+
22
+#define LOG_TAG "Vold"
23
+
24
+#include <cutils/log.h>
25
+
26
+#include <sysutils/NetlinkEvent.h>
27
+#include "NetlinkHandler.h"
28
+#include <volume_manager/VolumeManager.h>
29
+
30
+NetlinkHandler::NetlinkHandler(int listenerSocket) :
31
+                NetlinkListener(listenerSocket) {
32
+}
33
+
34
+NetlinkHandler::~NetlinkHandler() {
35
+}
36
+
37
+bool NetlinkHandler::start() {
38
+    return this->startListener() == 0;
39
+}
40
+
41
+void NetlinkHandler::stop() {
42
+    this->stopListener();
43
+}
44
+
45
+void NetlinkHandler::onEvent(NetlinkEvent *evt) {
46
+    android::volmgr::VolumeManager *vm = android::volmgr::VolumeManager::Instance();
47
+    const char *subsys = evt->getSubsystem();
48
+
49
+    if (!subsys) {
50
+        SLOGW("No subsystem found in netlink event");
51
+        return;
52
+    }
53
+
54
+    if (!strcmp(subsys, "block")) {
55
+        vm->handleBlockEvent(evt);
56
+    }
57
+}

+ 34
- 0
volume_manager/NetlinkHandler.h View File

@@ -0,0 +1,34 @@
1
+/*
2
+ * Copyright (C) 2008 The Android Open Source Project
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *      http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+#ifndef _NETLINKHANDLER_H
18
+#define _NETLINKHANDLER_H
19
+
20
+#include <sysutils/NetlinkListener.h>
21
+
22
+class NetlinkHandler: public NetlinkListener {
23
+
24
+public:
25
+    explicit NetlinkHandler(int listenerSocket);
26
+    virtual ~NetlinkHandler();
27
+
28
+    bool start(void);
29
+    void stop(void);
30
+
31
+protected:
32
+    virtual void onEvent(NetlinkEvent *evt);
33
+};
34
+#endif

+ 105
- 0
volume_manager/NetlinkManager.cpp View File

@@ -0,0 +1,105 @@
1
+/*
2
+ * Copyright (C) 2008 The Android Open Source Project
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *      http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+#include <stdio.h>
18
+#include <errno.h>
19
+#include <string.h>
20
+
21
+#include <sys/socket.h>
22
+#include <sys/select.h>
23
+#include <sys/time.h>
24
+#include <sys/types.h>
25
+#include <sys/un.h>
26
+
27
+#include <linux/netlink.h>
28
+
29
+#define LOG_TAG "Vold"
30
+
31
+#include <cutils/log.h>
32
+
33
+#include "NetlinkManager.h"
34
+#include "NetlinkHandler.h"
35
+
36
+NetlinkManager *NetlinkManager::sInstance = NULL;
37
+
38
+NetlinkManager *NetlinkManager::Instance() {
39
+    if (!sInstance)
40
+        sInstance = new NetlinkManager();
41
+    return sInstance;
42
+}
43
+
44
+NetlinkManager::NetlinkManager() {
45
+    // Empty
46
+}
47
+
48
+NetlinkManager::~NetlinkManager() {
49
+}
50
+
51
+bool NetlinkManager::start() {
52
+    struct sockaddr_nl nladdr;
53
+    int sz = 64 * 1024;
54
+    int on = 1;
55
+
56
+    memset(&nladdr, 0, sizeof(nladdr));
57
+    nladdr.nl_family = AF_NETLINK;
58
+    nladdr.nl_pid = getpid();
59
+    nladdr.nl_groups = 0xffffffff;
60
+
61
+    if ((mSock = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC,
62
+            NETLINK_KOBJECT_UEVENT)) < 0) {
63
+        SLOGE("Unable to create uevent socket: %s", strerror(errno));
64
+        return false;
65
+    }
66
+
67
+    // When running in a net/user namespace, SO_RCVBUFFORCE is not available.
68
+    // Try using SO_RCVBUF first.
69
+    if ((setsockopt(mSock, SOL_SOCKET, SO_RCVBUF, &sz, sizeof(sz)) < 0) &&
70
+        (setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0)) {
71
+        SLOGE("Unable to set uevent socket SO_RCVBUF/SO_RCVBUFFORCE option: %s", strerror(errno));
72
+        goto out;
73
+    }
74
+
75
+    if (setsockopt(mSock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
76
+        SLOGE("Unable to set uevent socket SO_PASSCRED option: %s", strerror(errno));
77
+        goto out;
78
+    }
79
+
80
+    if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {
81
+        SLOGE("Unable to bind uevent socket: %s", strerror(errno));
82
+        goto out;
83
+    }
84
+
85
+    mHandler = new NetlinkHandler(mSock);
86
+    if (!mHandler->start()) {
87
+        SLOGE("Unable to start NetlinkHandler: %s", strerror(errno));
88
+        goto out;
89
+    }
90
+
91
+    return true;
92
+
93
+out:
94
+    close(mSock);
95
+    return false;
96
+}
97
+
98
+void NetlinkManager::stop() {
99
+    mHandler->stop();
100
+    delete mHandler;
101
+    mHandler = NULL;
102
+
103
+    close(mSock);
104
+    mSock = -1;
105
+}

+ 44
- 0
volume_manager/NetlinkManager.h View File

@@ -0,0 +1,44 @@
1
+/*
2
+ * Copyright (C) 2008 The Android Open Source Project
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *      http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+#ifndef _NETLINKMANAGER_H
18
+#define _NETLINKMANAGER_H
19
+
20
+#include <sysutils/SocketListener.h>
21
+#include <sysutils/NetlinkListener.h>
22
+
23
+class NetlinkHandler;
24
+
25
+class NetlinkManager {
26
+private:
27
+    static NetlinkManager *sInstance;
28
+
29
+private:
30
+    NetlinkHandler       *mHandler;
31
+    int                  mSock;
32
+
33
+public:
34
+    virtual ~NetlinkManager();
35
+
36
+    bool start();
37
+    void stop();
38
+
39
+    static NetlinkManager *Instance();
40
+
41
+private:
42
+    NetlinkManager();
43
+};
44
+#endif

+ 218
- 0
volume_manager/Process.cpp View File

@@ -0,0 +1,218 @@
1
+/*
2
+ * Copyright (C) 2008 The Android Open Source Project
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *      http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+#include <stdio.h>
18
+#include <unistd.h>
19
+#include <errno.h>
20
+#include <string.h>
21
+#include <fcntl.h>
22
+#include <dirent.h>
23
+#include <ctype.h>
24
+#include <pwd.h>
25
+#include <stdlib.h>
26
+#include <poll.h>
27
+#include <sys/stat.h>
28
+#include <signal.h>
29
+
30
+#define LOG_TAG "ProcessKiller"
31
+
32
+#include <android-base/file.h>
33
+#include <android-base/stringprintf.h>
34
+#include <android-base/logging.h>
35
+#include <cutils/log.h>
36
+
37
+#include "Process.h"
38
+
39
+using android::base::ReadFileToString;
40
+using android::base::StringPrintf;
41
+
42
+int Process::readSymLink(const char *path, char *link, size_t max) {
43
+    struct stat s;
44
+    int length;
45
+
46
+    if (lstat(path, &s) < 0)
47
+        return 0;
48
+    if ((s.st_mode & S_IFMT) != S_IFLNK)
49
+        return 0;
50
+
51
+    // we have a symlink
52
+    length = readlink(path, link, max- 1);
53
+    if (length <= 0)
54
+        return 0;
55
+    link[length] = 0;
56
+    return 1;
57
+}
58
+
59
+int Process::pathMatchesMountPoint(const char* path, const char* mountPoint) {
60
+    int length = strlen(mountPoint);
61
+    if (length > 1 && strncmp(path, mountPoint, length) == 0) {
62
+        // we need to do extra checking if mountPoint does not end in a '/'
63
+        if (mountPoint[length - 1] == '/')
64
+            return 1;
65
+        // if mountPoint does not have a trailing slash, we need to make sure
66
+        // there is one in the path to avoid partial matches.
67
+        return (path[length] == 0 || path[length] == '/');
68
+    }
69
+    
70
+    return 0;
71
+}
72
+
73
+void Process::getProcessName(int pid, std::string& out_name) {
74
+    if (!ReadFileToString(StringPrintf("/proc/%d/cmdline", pid), &out_name)) {
75
+        out_name = "???";
76
+    }
77
+}
78
+
79
+int Process::checkFileDescriptorSymLinks(int pid, const char *mountPoint) {
80
+    return checkFileDescriptorSymLinks(pid, mountPoint, NULL, 0);
81
+}
82
+
83
+int Process::checkFileDescriptorSymLinks(int pid, const char *mountPoint, char *openFilename, size_t max) {
84
+
85
+
86
+    // compute path to process's directory of open files
87
+    char    path[PATH_MAX];
88
+    snprintf(path, sizeof(path), "/proc/%d/fd", pid);
89
+    DIR *dir = opendir(path);
90
+    if (!dir)
91
+        return 0;
92
+
93
+    // remember length of the path
94
+    int parent_length = strlen(path);
95
+    // append a trailing '/'
96
+    path[parent_length++] = '/';
97
+
98
+    struct dirent* de;
99
+    while ((de = readdir(dir))) {
100
+        if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")
101
+                || strlen(de->d_name) + parent_length + 1 >= PATH_MAX)
102
+            continue;
103
+        
104
+        // append the file name, after truncating to parent directory
105
+        path[parent_length] = 0;
106
+        strlcat(path, de->d_name, PATH_MAX);
107
+
108
+        char link[PATH_MAX];
109
+
110
+        if (readSymLink(path, link, sizeof(link)) && pathMatchesMountPoint(link, mountPoint)) {
111
+            if (openFilename) {
112
+                memset(openFilename, 0, max);
113
+                strlcpy(openFilename, link, max);
114
+            }
115
+            closedir(dir);
116
+            return 1;
117
+        }
118
+    }
119
+
120
+    closedir(dir);
121
+    return 0;
122
+}
123
+
124
+int Process::checkFileMaps(int pid, const char *mountPoint) {
125
+    return checkFileMaps(pid, mountPoint, NULL, 0);
126
+}
127
+
128
+int Process::checkFileMaps(int pid, const char *mountPoint, char *openFilename, size_t max) {
129
+    FILE *file;
130
+    char buffer[PATH_MAX + 100];
131
+
132
+    snprintf(buffer, sizeof(buffer), "/proc/%d/maps", pid);
133
+    file = fopen(buffer, "re");
134
+    if (!file)
135
+        return 0;
136
+    
137
+    while (fgets(buffer, sizeof(buffer), file)) {
138
+        // skip to the path
139
+        const char* path = strchr(buffer, '/');
140
+        if (path && pathMatchesMountPoint(path, mountPoint)) {
141
+            if (openFilename) {
142
+                memset(openFilename, 0, max);
143
+                strlcpy(openFilename, path, max);
144
+            }
145
+            fclose(file);
146
+            return 1;
147
+        }
148
+    }
149
+    
150
+    fclose(file);
151
+    return 0;
152
+}
153
+
154
+int Process::checkSymLink(int pid, const char *mountPoint, const char *name) {
155
+    char    path[PATH_MAX];
156
+    char    link[PATH_MAX];
157
+
158
+    snprintf(path, sizeof(path), "/proc/%d/%s", pid, name);
159
+    if (readSymLink(path, link, sizeof(link)) && pathMatchesMountPoint(link, mountPoint)) 
160
+        return 1;
161
+    return 0;
162
+}
163
+
164
+int Process::getPid(const char *s) {
165
+    int result = 0;
166
+    while (*s) {
167
+        if (!isdigit(*s)) return -1;
168
+        result = 10 * result + (*s++ - '0');
169
+    }
170
+    return result;
171
+}
172
+
173
+/*
174
+ * Hunt down processes that have files open at the given mount point.
175
+ */
176
+int Process::killProcessesWithOpenFiles(const char *path, int signal) {
177
+    int count = 0;
178
+    DIR* dir;
179
+    struct dirent* de;
180
+
181
+    if (!(dir = opendir("/proc"))) {
182
+        SLOGE("opendir failed (%s)", strerror(errno));
183
+        return count;
184
+    }
185
+
186
+    while ((de = readdir(dir))) {
187
+        int pid = getPid(de->d_name);
188
+        if (pid == -1)
189
+            continue;
190
+
191
+        std::string name;
192
+        getProcessName(pid, name);
193
+
194
+        char openfile[PATH_MAX];
195
+
196
+        if (checkFileDescriptorSymLinks(pid, path, openfile, sizeof(openfile))) {
197
+            SLOGE("Process %s (%d) has open file %s", name.c_str(), pid, openfile);
198
+        } else if (checkFileMaps(pid, path, openfile, sizeof(openfile))) {
199
+            SLOGE("Process %s (%d) has open filemap for %s", name.c_str(), pid, openfile);
200
+        } else if (checkSymLink(pid, path, "cwd")) {
201
+            SLOGE("Process %s (%d) has cwd within %s", name.c_str(), pid, path);
202
+        } else if (checkSymLink(pid, path, "root")) {
203
+            SLOGE("Process %s (%d) has chroot within %s", name.c_str(), pid, path);
204
+        } else if (checkSymLink(pid, path, "exe")) {
205
+            SLOGE("Process %s (%d) has executable path within %s", name.c_str(), pid, path);
206
+        } else {
207
+            continue;
208
+        }
209
+
210
+        if (signal != 0) {
211
+            SLOGW("Sending %s to process %d", strsignal(signal), pid);
212
+            kill(pid, signal);
213
+            count++;
214
+        }
215
+    }
216
+    closedir(dir);
217
+    return count;
218
+}

+ 35
- 0
volume_manager/Process.h View File

@@ -0,0 +1,35 @@
1
+/*
2
+ * Copyright (C) 2008 The Android Open Source Project
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *      http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+#ifndef _PROCESS_H
18
+#define _PROCESS_H
19
+
20
+class Process {
21
+public:
22
+    static int killProcessesWithOpenFiles(const char *path, int signal);
23
+    static int getPid(const char *s);
24
+    static int checkSymLink(int pid, const char *path, const char *name);
25
+    static int checkFileMaps(int pid, const char *path);
26
+    static int checkFileMaps(int pid, const char *path, char *openFilename, size_t max);
27
+    static int checkFileDescriptorSymLinks(int pid, const char *mountPoint);
28
+    static int checkFileDescriptorSymLinks(int pid, const char *mountPoint, char *openFilename, size_t max);
29
+    static void getProcessName(int pid, std::string& out_name);
30
+private:
31
+    static int readSymLink(const char *path, char *link, size_t max);
32
+    static int pathMatchesMountPoint(const char *path, const char *mountPoint);
33
+};
34
+
35
+#endif

+ 158
- 0
volume_manager/PublicVolume.cpp View File

@@ -0,0 +1,158 @@
1
+/*
2
+ * Copyright (C) 2015 The Android Open Source Project
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *      http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+#include "fs/Exfat.h"
18
+#include "fs/Ext4.h"
19
+#include "fs/F2fs.h"
20
+#include "fs/Ntfs.h"
21
+#include "fs/Vfat.h"
22
+#include "PublicVolume.h"
23
+#include "Utils.h"
24
+#include <volume_manager/VolumeManager.h>
25
+#include "ResponseCode.h"
26
+
27
+#include <android-base/stringprintf.h>
28
+#include <android-base/logging.h>
29
+#include <cutils/fs.h>
30
+#include <private/android_filesystem_config.h>
31
+
32
+#include <fcntl.h>
33
+#include <stdlib.h>
34
+#include <sys/mount.h>
35
+#include <sys/stat.h>
36
+#include <sys/types.h>
37
+#include <sys/sysmacros.h>
38
+#include <sys/wait.h>
39
+
40
+using android::base::StringPrintf;
41
+
42
+namespace android {
43
+namespace volmgr {
44
+
45
+PublicVolume::PublicVolume(dev_t device, const std::string& nickname,
46
+                const std::string& fstype /* = "" */,
47
+                const std::string& mntopts /* = "" */) :
48
+        VolumeBase(Type::kPublic), mDevice(device),
49
+        mFsType(fstype), mMntOpts(mntopts) {
50
+    setId(StringPrintf("public:%u_%u", major(device), minor(device)));
51
+    setPartLabel(nickname);
52
+    mDevPath = StringPrintf("/dev/block/volmgr/%s", getId().c_str());
53
+}
54
+
55
+PublicVolume::~PublicVolume() {
56
+}
57
+
58
+status_t PublicVolume::readMetadata() {
59
+    std::string label;
60
+    status_t res = ReadMetadataUntrusted(mDevPath, mFsType, mFsUuid, label);
61
+    if (!label.empty()) {
62
+        setPartLabel(label);
63
+    }
64
+    VolumeManager::Instance()->notifyEvent(ResponseCode::VolumeFsTypeChanged,
65
+                                           mFsType);
66
+    VolumeManager::Instance()->notifyEvent(ResponseCode::VolumeFsUuidChanged,
67
+                                           mFsUuid);
68
+    return res;
69
+}
70
+
71
+status_t PublicVolume::doCreate() {
72
+    status_t res = CreateDeviceNode(mDevPath, mDevice);
73
+    if (res != OK) {
74
+        return res;
75
+    }
76
+    readMetadata();
77
+
78
+    // Use UUID as stable name, if available
79
+    std::string stableName = getId();
80
+    if (!mFsUuid.empty()) {
81
+        stableName = mFsUuid;
82
+    }
83
+    setPath(StringPrintf("/storage/%s", stableName.c_str()));
84
+
85
+    return OK;
86
+}
87
+
88
+status_t PublicVolume::doDestroy() {
89
+    return DestroyDeviceNode(mDevPath);
90
+}
91
+
92
+status_t PublicVolume::doMount() {
93
+    if (!IsFilesystemSupported(mFsType)) {
94
+        LOG(ERROR) << getId() << " unsupported filesystem " << mFsType;
95
+        return -EIO;
96
+    }
97
+
98
+
99
+    if (fs_prepare_dir(getPath().c_str(), 0700, AID_ROOT, AID_ROOT)) {
100
+        PLOG(ERROR) << getId() << " failed to create mount points";
101
+        return -errno;
102
+    }
103
+
104
+    int ret = 0;
105
+    if (mFsType == "exfat") {
106
+        ret = exfat::Check(mDevPath);
107
+    } else
108
+    if (mFsType == "ext4") {
109
+        ret = ext4::Check(mDevPath, getPath(), false);
110
+    } else if (mFsType == "f2fs") {
111
+        ret = f2fs::Check(mDevPath, false);
112
+    } else if (mFsType == "ntfs") {
113
+        ret = ntfs::Check(mDevPath);
114
+    } else if (mFsType == "vfat") {
115
+        ret = vfat::Check(mDevPath);
116
+    } else {
117
+        LOG(WARNING) << getId() << " unsupported filesystem check, skipping";
118
+    }
119
+    if (ret) {
120
+        LOG(ERROR) << getId() << " failed filesystem check";
121
+        return -EIO;
122
+    }
123
+
124
+    if (mFsType == "exfat") {
125
+        ret = exfat::Mount(mDevPath, getPath(),
126
+                AID_MEDIA_RW, AID_MEDIA_RW, 0007);
127
+    } else if (mFsType == "ext4") {
128
+        ret = ext4::Mount(mDevPath, getPath(), false, false, true, mMntOpts,
129
+                false, true);
130
+    } else if (mFsType == "f2fs") {
131
+        ret = f2fs::Mount(mDevPath, getPath(), mMntOpts, false, true);
132
+    } else if (mFsType == "ntfs") {
133
+        ret = ntfs::Mount(mDevPath, getPath(), false, false, false,
134
+                AID_MEDIA_RW, AID_MEDIA_RW, 0007);
135
+    } else if (mFsType == "vfat") {
136
+        ret = vfat::Mount(mDevPath, getPath(), false, false, false,
137
+                AID_MEDIA_RW, AID_MEDIA_RW, 0007, true);
138
+    } else {
139
+        ret = ::mount(mDevPath.c_str(), getPath().c_str(), mFsType.c_str(), 0, nullptr);
140
+    }
141
+    if (ret) {
142
+        PLOG(ERROR) << getId() << " failed to mount " << mDevPath;
143
+        return -EIO;
144
+    }
145
+
146
+    return OK;
147
+}
148
+
149
+status_t PublicVolume::doUnmount(bool detach /* = false */) {
150
+    ForceUnmount(getPath(), detach);
151
+
152
+    rmdir(getPath().c_str());
153
+
154
+    return OK;
155
+}
156
+
157
+}  // namespace volmgr
158
+}  // namespace android

+ 75
- 0
volume_manager/PublicVolume.h View File

@@ -0,0 +1,75 @@
1
+/*
2
+ * Copyright (C) 2015 The Android Open Source Project
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *      http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+#ifndef ANDROID_VOLMGR_PUBLIC_VOLUME_H
18
+#define ANDROID_VOLMGR_PUBLIC_VOLUME_H
19
+
20
+#include "VolumeBase.h"
21
+
22
+#include <cutils/multiuser.h>
23
+
24
+namespace android {
25
+namespace volmgr {
26
+
27
+
28
+/*
29
+ * Shared storage provided by public (vfat) partition.
30
+ *
31
+ * Knows how to mount itself and then spawn a FUSE daemon to synthesize
32
+ * permissions.
33
+ *
34
+ * This volume is not inherently multi-user aware, so it has two possible
35
+ * modes of operation:
36
+ * 1. If primary storage for the device, it only binds itself to the
37
+ * owner user.
38
+ * 2. If secondary storage, it binds itself for all users, but masks
39
+ * away the Android directory for secondary users.
40
+ */
41
+class PublicVolume : public VolumeBase {
42
+public:
43
+    PublicVolume(dev_t device, const std::string& nickname,
44
+                 const std::string& mntopts = "",
45
+                 const std::string& fstype = "");
46
+    virtual ~PublicVolume();
47
+
48
+protected:
49
+    status_t doCreate() override;
50
+    status_t doDestroy() override;
51
+    status_t doMount() override;
52
+    status_t doUnmount(bool detach = false) override;
53
+
54
+    status_t readMetadata();
55
+
56
+private:
57
+    /* Kernel device representing partition */
58
+    dev_t mDevice;
59
+    /* Block device path */
60
+    std::string mDevPath;
61
+
62
+    /* Filesystem type */
63
+    std::string mFsType;
64
+    /* Filesystem UUID */
65
+    std::string mFsUuid;
66
+    /* Mount options */
67
+    std::string mMntOpts;
68
+
69
+    DISALLOW_COPY_AND_ASSIGN(PublicVolume);
70
+};
71
+
72
+}  // namespace volmgr
73
+}  // namespace android
74
+
75
+#endif

+ 42
- 0
volume_manager/ResponseCode.cpp View File

@@ -0,0 +1,42 @@
1
+/*
2
+ * Copyright (C) 2008 The Android Open Source Project
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *      http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+#include <stdio.h>
18
+#include <errno.h>
19
+#include <string.h>
20
+
21
+#define LOG_TAG "Vold"
22
+
23
+#include <cutils/log.h>
24
+
25
+#include "ResponseCode.h"
26
+
27
+int ResponseCode::convertFromErrno() {
28
+   if (errno == ENODEV) {
29
+        return(ResponseCode::OpFailedNoMedia);
30
+    } else if (errno == ENODATA) {
31
+        return(ResponseCode::OpFailedMediaBlank);
32
+    } else if (errno == EIO) {
33
+        return(ResponseCode::OpFailedMediaCorrupt);
34
+    } else if (errno == EBUSY) {
35
+        return(ResponseCode::OpFailedStorageBusy);
36
+    } else if (errno == ENOENT) {
37
+        return(ResponseCode::OpFailedStorageNotFound);
38
+    }
39
+
40
+    SLOGW("Returning OperationFailed - no handler for errno %d", errno);
41
+    return(ResponseCode::OperationFailed);
42
+}

+ 90
- 0
volume_manager/ResponseCode.h View File

@@ -0,0 +1,90 @@
1
+/*
2
+ * Copyright (C) 2008 The Android Open Source Project
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *      http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+#ifndef _RESPONSECODE_H
18
+#define _RESPONSECODE_H
19
+
20
+class ResponseCode {
21
+public:
22
+    // 100 series - Requestion action was initiated; expect another reply
23
+    // before proceeding with a new command.
24
+    static const int ActionInitiated  = 100;
25
+
26
+    static const int VolumeListResult         = 110;
27
+    static const int AsecListResult           = 111;
28
+    static const int StorageUsersListResult   = 112;
29
+    static const int CryptfsGetfieldResult    = 113;
30
+
31
+    // 200 series - Requested action has been successfully completed
32
+    static const int CommandOkay              = 200;
33
+    static const int ShareStatusResult        = 210;
34
+    static const int AsecPathResult           = 211;
35
+    static const int ShareEnabledResult       = 212;
36
+    static const int PasswordTypeResult       = 213;
37
+
38
+    // 400 series - The command was accepted but the requested action
39
+    // did not take place.
40
+    static const int OperationFailed          = 400;
41
+    static const int OpFailedNoMedia          = 401;
42
+    static const int OpFailedMediaBlank       = 402;
43
+    static const int OpFailedMediaCorrupt     = 403;
44
+    static const int OpFailedVolNotMounted    = 404;
45
+    static const int OpFailedStorageBusy      = 405;
46
+    static const int OpFailedStorageNotFound  = 406;
47
+
48
+    // 500 series - The command was not accepted and the requested
49
+    // action did not take place.
50
+    static const int CommandSyntaxError = 500;
51
+    static const int CommandParameterError = 501;
52
+    static const int CommandNoPermission = 502;
53
+
54
+    // 600 series - Unsolicited broadcasts
55
+    static const int UnsolicitedInformational       = 600;
56
+    static const int VolumeStateChange              = 605;
57
+    static const int VolumeMountFailedBlank         = 610;
58
+    static const int VolumeMountFailedDamaged       = 611;
59
+    static const int VolumeMountFailedNoMedia       = 612;
60
+    static const int VolumeUuidChange               = 613;
61
+    static const int VolumeUserLabelChange          = 614;
62
+
63
+    static const int ShareAvailabilityChange        = 620;
64
+
65
+    static const int VolumeDiskInserted            = 630;
66
+    static const int VolumeDiskRemoved             = 631;
67
+    static const int VolumeBadRemoval              = 632;
68
+
69
+    static const int DiskCreated = 640;
70
+    static const int DiskSizeChanged = 641;
71
+    static const int DiskLabelChanged = 642;
72
+    static const int DiskScanned = 643;
73
+    static const int DiskSysPathChanged = 644;
74
+    static const int DiskDestroyed = 649;
75
+
76
+    static const int VolumeCreated = 650;
77
+    static const int VolumeStateChanged = 651;
78
+    static const int VolumeFsTypeChanged = 652;
79
+    static const int VolumeFsUuidChanged = 653;
80
+    static const int VolumeFsLabelChanged = 654;
81
+    static const int VolumePathChanged = 655;
82
+    static const int VolumeDestroyed = 659;
83
+
84
+    static const int MoveStatus = 660;
85
+    static const int BenchmarkResult = 661;
86
+    static const int TrimResult = 662;
87
+
88
+    static int convertFromErrno();
89
+};
90
+#endif

+ 336
- 0
volume_manager/Utils.cpp View File

@@ -0,0 +1,336 @@
1
+/*
2
+ * Copyright (C) 2015 The Android Open Source Project
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *      http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+#include "sehandle.h"
18
+#include "Utils.h"
19
+#include "Process.h"
20
+#include <volume_manager/VolumeManager.h>
21
+
22
+#include <android-base/file.h>
23
+#include <android-base/logging.h>
24
+#include <android-base/properties.h>
25
+#include <android-base/stringprintf.h>
26
+
27
+#include <cutils/fs.h>
28
+#include <private/android_filesystem_config.h>
29
+
30
+#include <mutex>
31
+#include <dirent.h>
32
+#include <fcntl.h>
33
+#include <linux/fs.h>
34
+#include <stdlib.h>
35
+#include <sys/mount.h>
36
+#include <sys/types.h>
37
+#include <sys/stat.h>
38
+#include <sys/sysmacros.h>
39
+#include <sys/wait.h>
40
+#include <sys/statvfs.h>
41
+#include <thread>
42
+
43
+#ifndef UMOUNT_NOFOLLOW
44
+#define UMOUNT_NOFOLLOW    0x00000008  /* Don't follow symlink on umount */
45
+#endif
46
+
47
+using android::base::ReadFileToString;
48
+using android::base::StringPrintf;
49
+
50
+using namespace std::chrono_literals;
51
+
52
+namespace android {
53
+namespace volmgr {
54
+
55
+security_context_t sBlkidContext = nullptr;
56
+security_context_t sBlkidUntrustedContext = nullptr;
57
+security_context_t sFsckContext = nullptr;
58
+security_context_t sFsckUntrustedContext = nullptr;
59
+
60
+#include <blkid/blkid.h>
61
+
62
+static const char* kProcFilesystems = "/proc/filesystems";
63
+
64
+status_t CreateDeviceNode(const std::string& path, dev_t dev) {
65
+    const char* cpath = path.c_str();
66
+    status_t res = 0;
67
+
68
+    char* secontext = nullptr;
69
+    if (sehandle) {
70