如何在Android 7.0+中检索SD卡的序列号?

22
注意:这个问题是关于物理SD卡的序列号,而不是已挂载卷的UUID。这两个数据是独立的。
在一些Android版本和其他Linux变体中,可以获取已挂载SD卡的序列号,例如通过读取/sys/class/mmc_host/mmc0/mmc0:0001/serial或/sys/block/mmcblk0/device/serial(具体数字可能会有所变化)。在我的测试中,只要SD卡插入内置SD卡插槽中(而不是通过USB适配器挂载),这种方法就相当可靠。
但是截至Android 7.0 Nougat,据说操作系统正在阻止访问此信息,至少在某些设备上是如此。我通过在新的Alcatel A30 GSM(Android 7.0)上运行测试应用程序进行了测试,事实上以上方法失败并显示权限错误。
java.io.FileNotFoundException: /sys/block/mmcblk0/device/serial (Permission denied)
at java.io.FileInputStream.open(Native Method)

为了以后参考,我们(在adb shell中进行测试)有权限执行以下命令:ls -ld

  • /sys/class/mmc_host 但没有权限对/sys/class/mmc_host/mmc0执行该命令。
  • /sys/block 但没有权限对/sys/block/mmcblk0执行该命令。

由于以上方法不再适用,是否有其他方法可以在Android 7.0或更高版本中获取挂载SD卡的序列号?
如果没有,那么谷歌有没有提供或不提供此功能的计划文件或其他声明?我在Android 问题跟踪器中没有找到任何信息,但可能是因为我的搜索方式不正确。
为了确保问题清晰,我说的是一个普通(非系统)应用程序在非root设备上运行时可以做什么,具有应用程序通常可以请求和接收的任何权限。
FYI,/sbin目录似乎不可读,因此像/sbin/udevadm这样的命令不是一个选项。

1
我能想到的唯一相关的事情是StorageVolume上的getUuid()。你可以从StorageManager获取StorageVolume对象。然而,我不知道UUID是否与序列号有关。 - CommonsWare
1
供日后参考,这里是结果:我测试的设备给出了一个UUID为“76DE-3B41”...值得注意的是它只有8个数字。这是针对序列号为“000fec46”的芯片的。当我们使用不同的芯片调用“getUuid()”时,卷UUID没有改变。因此,UUID肯定不是芯片序列号。@Commonsware谢谢你的想法...这比我之前拥有的信息更多。 - LarsH
2
@LarsH 我怀疑这些是selinux配置的更改,我已经将您的问题转发到这里:https://issuetracker.google.com/issues/37091475 - marcinj
1
@marcinj:FYI,我在https://issuetracker.google.com/issues/37705442创建了一个单独的错误报告,以便专注于这个较窄的问题,并因此希望避免打开关于安全的大问题。 - LarsH
1
@LarsH 我已经把它变成了一个答案,并放置了我发现的所有信息。我还打算在你的错误报告中添加评论。 - marcinj
显示剩余13条评论
5个回答

5
在Android N中,访问/sys和/proc的权限被大幅限制。这是为了提供更严格的沙盒环境,以便应用程序运行。在https://issuetracker.google.com/issues/37091475中解释了这一点,并明确表示这是有意为之的。事实上,并未表示/sys中的所有数据都无法访问,Google也愿意允许访问此位置下的其他文件:

如果您认为/sys中的特定文件应该对应用程序可用,但实际上不可用,请提交一个新的错误报告,以便进行评估。例如,/sys/devices/system/cpu对所有进程都可用,因此说/sys的所有内容都受到限制是不准确的。

我有一种不好的预感,谷歌正在进行类似苹果的更改,即不允许获取硬件ID。如果无法解决,则解决方案是使用谷歌账户ID。但是我知道这并非总是可行的,需要在业务逻辑(许可证等)方面进行重大更改。
希望您的错误报告能够得到积极考虑。
另外,我找到了一个相关的SO:Android Nougat中的文件系统更改

感谢您在该错误报告中的评论:您所说的正是需要说的。 - LarsH
你能告诉我你在哪些安卓7设备上看到了这个问题吗?我只有Alcatel A30这一台nougat设备,我想知道这个问题有多普遍。 - LarsH
1
我们目前只在索尼Z5上看到了这个问题。 - marcinj
1
我已在索尼开发者论坛上发布了问题,也许他们会在这个主题中给出一些官方回复:https://talk.sonymobile.com/t5/General-Discussion/Serial-number-of-SD-Card-is-no-longer-accessible-on-7-0-devices/m-p/1219885#U1219885 - marcinj
1
FYI,我没有收到任何关于澄清请求或您对我提交的Android问题的评论的答复。因此,我提交了一个新问题,并明确引用了“如果您认为/sys中应该向应用程序提供特定文件但未提供,请提交一个新错误报告,以便我们评估请求。”:https://issuetracker.google.com/issues/38492944 - LarsH

0

对于那些在Android下查看FAT类型卷的UUID或卷序列号的人,需要注意:包括X-T30(固件1.10)在内的一些富士相机在格式化时不会将卷序列号写入FAT卷中。

在Windows下,CHKDSK根本不显示卷序列号。 在Android上,调用StorageVolume.getUuid()返回“0000-0000”。

这一切都很好,直到你在Android上通过集线器挂载两张富士格式化的卡片。然后就会出现身份冲突,Android操作系统提示用户格式化其中一张卡片。分别它们是可以访问的。

我猜这里有两个问题: 1)富士在格式化时没有写入卷序列号, 2)Android使用卷序列号作为挂载点路径的一部分,导致冲突。

富士和谷歌可能都应该关注这个问题。

编辑:在尼康D810中格式化的卡片也有同样的问题,没有卷序列号。


1
这是有帮助的信息。然而,它并不是关于如何获取SD卡序列号的答案。挂载卷的ID与SD卡的序列号完全不同(请参见评论https://dev59.com/IlcQ5IYBdhLWcg3wA_FA#otvonYgBc1ULPQZFrRUo)。 - LarsH
啊,我的错误。请注意,在FAT标准中包含“UUID”的字段(显然不是真正的唯一标识符,所以这是一个误称)被称为卷序列号(尽管它显然不是序列号,只是一个随机的、希望是伪唯一的ID)。 - Lars V
1
你说得对,有时候它被称为“序列号”。我并不是说这个术语是错误的。它只是与SD卡序列号不同的东西。当媒体重新格式化时,卷UUID可能会改变,但SD卡序列号不应该是可更改的。 - LarsH

0

在从StorageManager获取的StorageVolume上使用StorageVolume.getUuid()

该值是在格式化卡时分配的卷ID,其长度/格式取决于文件系统类型。对于FAT32,它是XXXX-XXXX,对于NTFS,它是更长的十六进制字符串,对于内部大容量存储,它返回null。


谢谢您的想法。这与CommonsWare的评论相同;请查看我在https://dev59.com/IlcQ5IYBdhLWcg3wA_FA#otvonYgBc1ULPQZFrRUo的回复。 - LarsH

0

adb shell cat /sys/class/mmc_host/mmc1/mmc1:*/cid

你也可以尝试使用

sudo hwinfo --disk

来获取有关磁盘(包括SD卡)的信息。

还可以尝试使用

sudo hdparm -I /dev/sdb | more


第一个建议与问题中提到的不起作用,但使用cid代替serial。它遇到了同样的问题:/sys/class/mmc_host/mmc*无法读取。我会在有机会时尝试另外两个建议在Android 7.0上,但当我在6.0下尝试它们时,在adb shell下找不到sudohwinfohdparm - LarsH
我在一个Android 7.0设备上尝试了最后两个建议,结果相同--找不到sudohwinfohdparm - LarsH

0
public String getSDCARDiD()
{
    String sd_cid = null;
    try {

        File file = new File("/sys/block/mmcblk1");
        String memBlk;
        if (file.exists() && file.isDirectory()) {

            memBlk = "mmcblk1";
        } else {
            //System.out.println("not a directory");
            memBlk = "mmcblk0";
        }

        Process cmd = Runtime.getRuntime().exec("cat /sys/block/"+memBlk+"/device/cid");
        BufferedReader br = new BufferedReader(new InputStreamReader(cmd.getInputStream()));
        sd_cid = br.readLine();
        //System.out.println(sd_cid);

    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return sd_cid;
}

试试这个:参考原链接:Android如何以编程方式获取SD卡的ID


这似乎是检索设备ID、SIM序列号和Android ID的过程,但都不是SD卡序列号。您有什么迹象表明它实际上会检索SD卡序列号吗? - LarsH
我已经编辑了我的答案,请点击以下链接查看,并且我也更新了上面的代码。http://stackoverflow.com/questions/9063161/android-get-id-of-sd-card-programmatically 感谢:http://stackoverflow.com/users/1408418/awcroper - Vasudev Vyas
这本质上是我在问题的第一段中描述的方法,但自Android 7以来已不再起作用。CID包括序列号。无法读取serialcid,因为/sys/block/mmcblk0(或相应的/sys/block/mmcblk1)是不可读的。 - LarsH
你用哪个设备进行测试? - Vasudev Vyas
请仅翻译问题的第二段内容。 - LarsH

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接