Воспроизведение файлов ресурсов Android из внутреннего хранилища приводит к тому, что MediaPlayer.prepare предоставляет IOException

Мое приложение воспроизводит файлы аудио ресурсов из внутреннего каталога, предназначенного для моего приложения (/data/data/com...). Кажется, что файлы загружаются в это место в порядке, setDataSource (String path) не генерирует никаких исключений, но MediaPlayer.prepare() выдает IOException. Тот же код работает на SD-карте. Почему это происходит?

EDIT:

Предположим, что это код; это проще, чем мой код, и он вызывает одно и то же исключение:

package com.app.MediaPlayerTest;

public class MediaTest extends Activity {
    MediaPlayer mp;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        DownloadFiles();
        MusicPlay();
    }

    public void DownloadFiles() {
        //Downloads Files
    }

    public void MusicPlay()
    {
            try {
                mp.setDataSource("/data/data/com.app.pronounce/winds.mp3");
            } catch (IllegalArgumentException e1) {
                e1.printStackTrace();
            } catch (IllegalStateException e1) {
                e1.printStackTrace();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        try {
            mp.prepare();
        } catch (IllegalStateException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        mp.setLooping(true);
        mp.start();
    }
}

Что касается трассировки стека:

(mutexes: tll=0 tsl=0 tscl=0 ghl=0 hwl=0 hwll=0)
"main" prio=5 tid=1 NATIVE
  | group="main" sCount=1 dsCount=0 obj=0x4001f1a8 self=0xce48
  | sysTid=338 nice=0 sched=0/0 cgrp=bg_non_interactive handle=-1345006528
  | schedstat=( 151460588 425586896 45 )
  at android.os.BinderProxy.transact(Native Method)
  at android.app.ActivityManagerProxy.handleApplicationCrash(ActivityManagerNative.java:2547)
  at com.android.internal.os.RuntimeInit$UncaughtHandler.uncaughtException(RuntimeInit.java:76)
  at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:854)
  at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:851)
  at dalvik.system.NativeStart.main(Native Method)

"Binder Thread #2" prio=5 tid=8 NATIVE
  | group="main" sCount=1 dsCount=0 obj=0x40512b30 self=0x156e90
  | sysTid=346 nice=0 sched=0/0 cgrp=default handle=1570912
  | schedstat=( 4357682 930487 3 )
  at dalvik.system.NativeStart.run(Native Method)

"Binder Thread #1" prio=5 tid=7 NATIVE
  | group="main" sCount=1 dsCount=0 obj=0x40512a68 self=0x17f578
  | sysTid=345 nice=0 sched=0/0 cgrp=bg_non_interactive handle=604904
  | schedstat=( 6939806 13372136 3 )
  at dalvik.system.NativeStart.run(Native Method)

"Compiler" daemon prio=5 tid=6 VMWAIT
  | group="system" sCount=1 dsCount=0 obj=0x4050eba8 self=0x938c8
  | sysTid=344 nice=0 sched=0/0 cgrp=bg_non_interactive handle=1099136
  | schedstat=( 4770066 33579300 5 )
  at dalvik.system.NativeStart.run(Native Method)

"JDWP" daemon prio=5 tid=5 VMWAIT
  | group="system" sCount=1 dsCount=0 obj=0x4050eaf8 self=0x10c3c0
  | sysTid=343 nice=0 sched=0/0 cgrp=bg_non_interactive handle=1098624
  | schedstat=( 14899224 33240040 20 )
  at dalvik.system.NativeStart.run(Native Method)

"Signal Catcher" daemon prio=5 tid=4 RUNNABLE
  | group="system" sCount=0 dsCount=0 obj=0x4050ea38 self=0x93570
  | sysTid=342 nice=0 sched=0/0 cgrp=bg_non_interactive handle=588000
  | schedstat=( 24278832 4707632 7 )
  at dalvik.system.NativeStart.run(Native Method)

"GC" daemon prio=5 tid=3 VMWAIT
  | group="system" sCount=1 dsCount=0 obj=0x4050e990 self=0x8f720
  | sysTid=341 nice=0 sched=0/0 cgrp=bg_non_interactive handle=1099336
  | schedstat=( 791698 556969 3 )
  at dalvik.system.NativeStart.run(Native Method)

"HeapWorker" daemon prio=5 tid=2 VMWAIT
  | group="system" sCount=1 dsCount=0 obj=0x4050e8d8 self=0x10c740
  | sysTid=340 nice=0 sched=0/0 cgrp=bg_non_interactive handle=1357728
  | schedstat=( 211702049 225986921 9 )
  at dalvik.system.NativeStart.run(Native Method)

Ответ 1

MediaPlayer требует, чтобы файл, который был воспроизведен, имеет доступные для чтения разрешения. Вы можете просмотреть разрешения файла со следующей командой в оболочке adb:

ls -al /data/data/com.mypackage/myfile

Вероятно, вы увидите "-rw ------", что означает, что только владелец (ваше приложение, а не MediaPlayer) имеет права на чтение и запись.

Примечание. Ваш телефон должен быть привязан для использования команды ls без указания файла (во внутренней памяти).

Если ваш телефон укоренен, вы можете добавить разрешения для чтения в оболочке adb с помощью следующей команды:

chmod o+r /data/data/com.mypackage/myfile

Если вам необходимо модифицировать эти разрешения программным способом (требуется встроенный телефон!), вы можете использовать следующую команду в своем коде приложения:

Runtime.getRuntime().exec("chmod o+r /data/data/com.mypackage/myfile");

или

Runtime.getRuntime().exec("chmod 777 /data/data/com.mypackage/myfile");

Это в основном команда linux. Подробнее о chmod см. https://help.ubuntu.com/community/FilePermissions.

EDIT: нашел еще один простой подход здесь (полезно для тех, у кого нет корневых телефонов). Поскольку приложение владеет файлом, оно может создать дескриптор файла и передать его в mediaPlayer.setDataSource():

FileInputStream fileInputStream = new FileInputStream("/data/data/com.mypackage/myfile");
mediaPlayer.setDataSource(fileInputStream.getFD());

Этот подход полностью исключает проблему разрешения.

Ответ 2

Я знаю, что этот вопрос старше, чем грязь, но это помогло мне избавиться от моей проблемы. Следующее прекрасно работает:

      FileOutputStream outStream= openFileOutput("movie.mp4", MODE_WORLD_READABLE);

В мире важна важная составляющая мира.