【问题标题】:How unmount programmatically USB DRIVE in Android 4.2如何在 Android 4.2 中以编程方式卸载 USB 驱动器
【发布时间】:2014-09-07 03:11:02
【问题描述】:

我已经阅读了很多关于这个主题的帖子,但我还没有找到解决方案。 在我的应用程序中,我需要在将文件从 USB 驱动器复制到平板电脑后卸载 USB 驱动器,这样我就可以在不使用设置菜单的情况下安全地删除它。

我现在正在使用这种方法:

Utility.copyDirectory(file,new File(_CURR_FOLDER));
Process su;
su = Runtime.getRuntime().exec("/system/bin/su");
String cmd = "umount" +
             " " + SDPath + "\n" + "exit\n";
             su.getOutputStream().write(cmd.getBytes());

我在存储设置中得到的是:

总空间 0.0 可用 0.0

但 SD 仍然挂载。

提前感谢您的帮助。

第一次编辑:

有人知道如何使用 IMountService 吗?我读过它,也许是解决USB DRIVE卸载的正确方法,但是添加classes-full-debug.jar后我的项目不再编译

【问题讨论】:

    标签: android android-sdcard unmount


    【解决方案1】:

    这是不可能的。许多用户在那里存储他们所有的内容,如歌曲、视频、照片。不允许应用卸载 SD 卡,而是使用它们来存储数据,这是一个很好的安全决定。

    但你可以将用户发送到设置并由用户执行,而不是通过代码

    Intent i = new Intent(android.provider.Settings.ACTION_MEMORY_CARD_SETTINGS);
    startActivity(i);
    

    这会调出那个屏幕...

    我认为这会起作用

    【讨论】:

    • 就我而言,它不是 SD,而是用于自动更新我的应用程序配置的 USB 驱动器。没有用于卸载的 API? @Leon_SFS
    • @user2704214 看看这个:developer.android.com/guide/topics/connectivity/usb/… 可能有帮助,你是否使用正确的权限进行卸载?
    • 请注意,该问题清楚地表明该海报不受 Android 安全模型的约束。
    • 我已经阅读了文档,但没有说明有关卸载 USB DRIVE 的任何内容。我尝试从终端unmount /mnt/usb_storage 运行命令,但结果是一样的。
    • 我读过这个帖子:link,但要使用 IMountService 我必须包含 classes-full-debug.jar,但这会阻止 Android Studio 成功编译项目.有人可以帮助我吗?
    【解决方案2】:

    这是我在 Android 6.0.1 上必须做的事情,希望 4.2 也是如此。

    我必须在编译 android 后将库 SDK/out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes-full-debug.jar 添加到我的应用程序中。 (我刚刚从here 下载了棒棒糖版本,幸运的是它也适用于棉花糖)

    Android Studio 会报出内存不足的错误,这可以通过将以下代码添加到 android 部分的 build.gradle 中来解决。

    dexOptions {
        javaMaxHeapSize "4g"
    }
    

    您还需要通过在 build.gradle 的 defaultConfig 部分中添加以下行来添加 multidex 支持。

    multiDexEnabled true
    

    并在依赖项部分添加以下行。

    compile 'com.android.support:multidex:1.0.0'
    

    并在清单内的应用程序部分添加以下行。

    android:name="android.support.multidex.MultiDexApplication"
    

    并且您的 apk 必须在 /system/priv-app 目录中并具有以下权限。

    <uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE" />
    

    然后下面的代码应该可以工作了。

    private void unmount() {
        IMountService mountService = getMountService();
        try {
            if (mountService != null) {
                mountService.unmountVolume("/mnt/media_rw/8842-89A4", true, false);
                Log.e(TAG,"Unmounted");
            } else {
                Log.e(TAG, "Mount service is null, can't unmount");
            }
        } catch (RemoteException ex) {
            // Not much can be done
        }
    }
    
    private synchronized IMountService getMountService() {
        if (mMountService == null) {
            IBinder service = ServiceManager.getService("mount");
            if (service != null) {
                mMountService = IMountService.Stub.asInterface(service);
            } else {
                Log.e(TAG, "Can't get mount service");
            }
        }
        return mMountService;
    }
    

    【讨论】:

    • 嗨@Habbert,谢谢你的回答。编译后如何添加jar库?
    【解决方案3】:

    我在有权做任何事情的系统应用程序中使用了这些 sn-p 代码。我不确定这是否适用于常规应用程序,即使它具有所有存储权限。

    我知道这已经晚了 7 年,但可能对其他人有所帮助。 StorageManager 类有一个名为unmount 的隐藏函数。因为它不是公共的并且阻塞了调用者线程,所以使用反射来访问它并把它放在一个 AsyncTask 中:

    public static void unmountStorage(Context context, String volId) {
        new AsyncTask<Void, Void, Exception>() {
            @Override
            protected void onPostExecute(Exception e) {
                if (e == null) {
                    Log.i("storageman", "unmounting " + volId + " success!");
                }
                else {
                    Log.e("storageman", "unmounting", e);
                }
            }
    
            @Override
            protected Exception doInBackground(Void... params) {
                try {
                    StorageManager storageManager = context.getSystemService(StorageManager.class);
    
                    Method unmountMethod = StorageManager.class.getMethod("unmount", String.class);
                    unmountMethod.setAccessible(true);
                    unmountMethod.invoke(storageManager, volId);
    
                    return null;
                }
                catch (Exception ex) {
                    return ex;
                }
            }
        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    }
    

    volId 参数有点难以获取。首先,列出可用的卷。 StorageManager 还有一个隐藏的方法来执行此操作,称为getVolumes。然后您可以遍历它们并获取它们的属性,例如卷 ID。此方法为您提供了第一个“外部”存储:

    public static ExternalStorage getExternalStorage(Context context) {
        try {
            StorageManager storageManager = context.getSystemService(StorageManager.class);
    
            Method getVolumes = StorageManager.class.getMethod("getVolumes");
            getVolumes.setAccessible(true);
            List<Object> volumes = (List<Object>) getVolumes.invoke(storageManager);
    
            for (Object volume : volumes) {
                Class<?> volumeInfoClass = Class.forName("android.os.storage.VolumeInfo");
    
                Field idField = volumeInfoClass.getField("id");
                idField.setAccessible(true);
                String volumeId = (String) idField.get(volume);
    
                Field nameField = volumeInfoClass.getField("fsLabel");
                nameField.setAccessible(true);
                String volumeName = (String) nameField.get(volume);
    
                Field stateField = volumeInfoClass.getField("state");
                stateField.setAccessible(true);
                Integer volumeState = (Integer) stateField.get(volume);
    
                Field pathField = volumeInfoClass.getField("path");
                pathField.setAccessible(true);
                String volumePath = (String) pathField.get(volume);
    
                if (volumeId.startsWith("public") && (volumeState == 2 || volumeState == 3 || volumeState == 5)) {
                    return new ExternalStorage(volumeId, volumeName, new File(volumePath));
                }
            }
        }
        catch (Exception ex) {
            Log.e("storagehelper", "getExternalStorage(Context context)", ex);
        }
    
        return null;
    }
    

    我认为这行需要进一步解释:

    if (volumeId.startsWith("public") && (volumeState == 2 || volumeState == 3 || volumeState == 5)) {
    

    正如我在测试过程中所经历的那样,外部驱动器的卷 ID 以“public”开头,这就是我过滤卷的原因。常量 2、3 和 5 表示已安装卷。查看常量HERE

    ExternalStorage 是我编写的一个简单数据类,用于将相关信息保存在一起。

    祝你好运!

    【讨论】:

      猜你喜欢
      • 2012-02-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-03
      • 1970-01-01
      相关资源
      最近更新 更多