[FP4-128]add exfat support
diff --git a/model/Disk.cpp b/model/Disk.cpp
index 98b9596..0ca894b 100644
--- a/model/Disk.cpp
+++ b/model/Disk.cpp
@@ -23,6 +23,8 @@
 #include "VolumeEncryption.h"
 #include "VolumeManager.h"
 
+#include "fs/Exfat.h"
+
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/parseint.h>
@@ -384,6 +386,8 @@
                 }
 
                 switch (type) {
+                    case 0x01:  // FAT12 (in first 32 MB of disk)
+                    case 0x04:  // FAT16 (in first 32 MB of disk)
                     case 0x06:  // FAT16
                     case 0x07:  // HPFS/NTFS/exFAT
                     case 0x0b:  // W95 FAT32 (LBA)
@@ -458,6 +462,12 @@
         LOG(WARNING) << "Failed to zap; status " << res;
     }
 
+    if (exfat::CheckSize(mDevPath, false) == 1) {
+        /* Should format filesystem as exFAT, so we must partition the device
+         * according to SDXC rules. */
+        return exfat::PartitionDisk(mDevPath);
+    }
+
     // Now let's build the new MBR table. We heavily rely on sgdisk to
     // force optimal alignment on the created partitions.
     cmd.clear();
diff --git a/model/PublicVolume.cpp b/model/PublicVolume.cpp
index 12e31ff..552eab1 100644
--- a/model/PublicVolume.cpp
+++ b/model/PublicVolume.cpp
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2010-2021 Tuxera Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,6 +21,7 @@
 #include "Utils.h"
 #include "VolumeManager.h"
 #include "fs/Exfat.h"
+#include "fs/Filesystems.h"
 #include "fs/Vfat.h"
 
 #include <android-base/logging.h>
@@ -57,6 +59,13 @@
 PublicVolume::~PublicVolume() {}
 
 status_t PublicVolume::readMetadata() {
+    if(filesystems::Detect(mDevPath, &mFsTypeId)) {
+        /* Error while detecting filesystem. This should not happen, but in case
+         * it does, pretend that it is recognized as FAT since this most
+         * accurately reflects the behaviour of a stock AOSP vold. */
+        mFsTypeId = FSTYPE_FAT;
+    }
+
     status_t res = ReadMetadataUntrusted(mDevPath, &mFsType, &mFsUuid, &mFsLabel);
 
     auto listener = getListener();
@@ -100,21 +109,16 @@
     bool isVisible = getMountFlags() & MountFlags::kVisible;
     readMetadata();
 
-    if (mFsType == "vfat" && vfat::IsSupported()) {
-        if (vfat::Check(mDevPath)) {
-            LOG(ERROR) << getId() << " failed filesystem check";
-            return -EIO;
-        }
-    } else if (mFsType == "exfat" && exfat::IsSupported()) {
-        if (exfat::Check(mDevPath)) {
-            LOG(ERROR) << getId() << " failed filesystem check";
-            return -EIO;
-        }
-    } else {
+    if (!filesystems::IsSupported(mFsTypeId)) {
         LOG(ERROR) << getId() << " unsupported filesystem " << mFsType;
         return -EIO;
     }
 
+    if (filesystems::Check(mFsTypeId, mDevPath)) {
+        LOG(ERROR) << getId() << " failed filesystem check";
+        return -EIO;
+    }
+
     // Use UUID as stable name, if available
     std::string stableName = getId();
     if (!mFsUuid.empty()) {
@@ -140,18 +144,11 @@
         return -errno;
     }
 
-    if (mFsType == "vfat") {
-        if (vfat::Mount(mDevPath, mRawPath, false, false, false, AID_ROOT,
-                        (isVisible ? AID_MEDIA_RW : AID_EXTERNAL_STORAGE), 0007, true)) {
-            PLOG(ERROR) << getId() << " failed to mount " << mDevPath;
-            return -EIO;
-        }
-    } else if (mFsType == "exfat") {
-        if (exfat::Mount(mDevPath, mRawPath, AID_ROOT,
-                         (isVisible ? AID_MEDIA_RW : AID_EXTERNAL_STORAGE), 0007)) {
-            PLOG(ERROR) << getId() << " failed to mount " << mDevPath;
-            return -EIO;
-        }
+    if (filesystems::Mount(mFsTypeId, mDevPath, mRawPath, false, false, false,
+                           AID_ROOT, (isVisible ? AID_MEDIA_RW : AID_EXTERNAL_STORAGE),
+                           0007, true)) {
+        PLOG(ERROR) << getId() << " failed to mount " << mDevPath;
+        return -EIO;
     }
 
     if (getMountFlags() & MountFlags::kPrimary) {
@@ -308,33 +305,26 @@
 }
 
 status_t PublicVolume::doFormat(const std::string& fsType) {
-    bool useVfat = vfat::IsSupported();
-    bool useExfat = exfat::IsSupported();
     status_t res = OK;
 
+    status_t (*formatFunction)(const std::string&, unsigned long) = NULL;
+
     // Resolve the target filesystem type
-    if (fsType == "auto" && useVfat && useExfat) {
-        uint64_t size = 0;
-
-        res = GetBlockDevSize(mDevPath, &size);
-        if (res != OK) {
-            LOG(ERROR) << "Couldn't get device size " << mDevPath;
-            return res;
-        }
-
-        // If both vfat & exfat are supported use exfat for SDXC (>~32GiB) cards
-        if (size > 32896LL * 1024 * 1024) {
-            useVfat = false;
-        } else {
-            useExfat = false;
+    if (fsType == "auto") {
+        if (exfat::IsSupported() && exfat::CheckSize(mDevPath, true) == 1) {
+            /* Should format filesystem as exFAT, so we must format the
+             * partition according to SDXC rules. */
+            formatFunction = &exfat::Format;
+        } else if(vfat::IsSupported()) {
+            formatFunction = &vfat::Format;
         }
     } else if (fsType == "vfat") {
-        useExfat = false;
+        formatFunction = vfat::IsSupported() ? &vfat::Format : NULL;
     } else if (fsType == "exfat") {
-        useVfat = false;
+        formatFunction = exfat::IsSupported() ? &exfat::Format : NULL;
     }
 
-    if (!useVfat && !useExfat) {
+    if (!formatFunction) {
         LOG(ERROR) << "Unsupported filesystem " << fsType;
         return -EINVAL;
     }
@@ -343,11 +333,7 @@
         LOG(WARNING) << getId() << " failed to wipe";
     }
 
-    if (useVfat) {
-        res = vfat::Format(mDevPath, 0);
-    } else if (useExfat) {
-        res = exfat::Format(mDevPath);
-    }
+    res = formatFunction(mDevPath, 0);
 
     if (res != OK) {
         LOG(ERROR) << getId() << " failed to format";
diff --git a/model/PublicVolume.h b/model/PublicVolume.h
index 3156b53..0f4a795 100644
--- a/model/PublicVolume.h
+++ b/model/PublicVolume.h
@@ -18,6 +18,7 @@
 #define ANDROID_VOLD_PUBLIC_VOLUME_H
 
 #include "VolumeBase.h"
+#include "fs/Filesystems.h"
 
 #include <cutils/multiuser.h>
 
@@ -71,6 +72,8 @@
     /* Whether to use sdcardfs for this volume */
     bool mUseSdcardFs;
 
+    /* Type ID of filesystem (see Filesystems.h). */
+    FSType mFsTypeId = FSTYPE_UNRECOGNIZED;
     /* Filesystem type */
     std::string mFsType;
     /* Filesystem UUID */