4 votos

¿Por qué (enlace) los montajes en /storage/emulated/0 no son visibles en las aplicaciones?

Monté un directorio en otro directorio con:

mount --bind "/storage/sdcard/dir1" "/storage/sdcard/dir2"

Hago esto al completarse el arranque con Tasker. Puedo ver los archivos montados en adb shell y en Termux, incluso como usuario sin privilegios de root. Pero no puedo ver estos archivos en aplicaciones como Total Commander o mi reproductor de música.

Estoy usando Lineage 7.1.2.

En este hilo, una solución es apagar "namespaces de montaje" en SuperSU. Desafortunadamente, tengo la aplicación SU predeterminada de LineageOS que no parece proporcionar esa opción. ¿Alguna sugerencia?

0 votos

5voto

Rob W Puntos 151

He estado utilizando montajes de enlace sin deshabilitar los espacios de nombres de montaje en Android durante un tiempo - Marshmallow (Android 6) y Nougat (Android 7.1, LineageOS 14.1).

El montaje de enlace no es visible para otras aplicaciones porque /storage/sdcard/ en sí mismo también es una capa de indirección. Por ejemplo, cuando ejecutas mount, puedes ver que la tarjeta SD "interna" emulada no se encuentra en /storage/emulated, sino en /data/media:

/data/media en /mnt/runtime/default/emulated tipo sdcardfs (rw,nosuid,nodev,noexec,noatime,uid=1023,gid=1023,multiuser)
/data/media en /storage/emulated tipo sdcardfs (rw,nosuid,nodev,noexec,noatime,uid=1023,gid=1023,multiuser)
/data/media en /mnt/runtime/read/emulated tipo sdcardfs (rw,nosuid,nodev,noexec,noatime,uid=1023,gid=1023,multiuser)
/data/media en /mnt/runtime/write/emulated tipo sdcardfs (rw,nosuid,nodev,noexec,noatime,uid=1023,gid=1023,multiuser)

Estos tres puntos de montaje en /mnt/runtime están documentados en Almacenamiento, Permisos de ejecución:

Android 6.0 introduce un nuevo modelo de permisos de ejecución donde las aplicaciones solicitan capacidades cuando se necesitan en tiempo de ejecución. Debido a que el nuevo modelo incluye los permisos READ/WRITE_EXTERNAL_STORAGE, la plataforma necesita otorgar acceso al almacenamiento dinámicamente sin matar o reiniciar aplicaciones que ya están en funcionamiento. Hace esto manteniendo tres vistas distintas de todos los dispositivos de almacenamiento montados:

  • /mnt/runtime/default se muestra a las aplicaciones sin permisos especiales de almacenamiento, y al espacio de nombres root donde adbd y otros componentes del sistema viven.
  • /mnt/runtime/read se muestra a las aplicaciones con READ_EXTERNAL_STORAGE
  • /mnt/runtime/write se muestra a las aplicaciones con WRITE_EXTERNAL_STORAGE

Entonces, para hacer un directorio visible para todas las demás aplicaciones, necesitas crear los montajes en estos lugares:

mkdir /mnt/runtime/{default,read,write}/dir2
mount -o bind /mnt/runtime/default/sdcard/dir1 /mnt/runtime/default/sdcard/dir2
mount -o bind /mnt/runtime/read/sdcard/dir1 /mnt/runtime/read/sdcard/dir2
mount -o bind /mnt/runtime/write/sdcard/dir1 /mnt/runtime/write/sdcard/dir2

Para desmontar:

umount /mnt/runtime/default/dir2
umount /mnt/runtime/read/dir2
umount /mnt/runtime/write/dir2
rmdir /mnt/runtime/{default,read,write}/dir2

En tu pregunta, la fuente y el objetivo están en el mismo sistema de archivos, por lo que lo anterior probablemente funcionará tal como está y mostrará dir2 a otras aplicaciones.

Puedes verificar que los montajes de enlace son "visibles" como se pretende mirando el ID de proceso de la aplicación deseada, y luego revisando la lista de montajes desde el punto de vista de esa aplicación:

# cat /proc/(aquí el ID de proceso)/mountinfo

Consejos de depuración

Si no puedes acceder al contenido del montaje de enlace (es decir, "Permiso denegado" o algo similar), entonces debes verificar si el archivo original tiene los permisos/propietario UNIX correctos Y una etiqueta SELinux que coincida con el contexto. Lo segundo se puede depurar buscando errores "avc: denied" en logcat-color (o simplemente adb logcat). En algunos casos, esto se puede solucionar usando restorecon o chcon.

Por ejemplo, solía recibir el siguiente error cuando intentaba acceder a /sdcard/DCIM (que es un montaje de enlace a un directorio en la tarjeta SD externa).

avc: denied { write } for comm=... name="Camera" dev="dm-1" ino=3547138 scontext=u:r:priv_app:s0:c512,c768 tcontext=u:object_r:mnt_media_rw_file:s0 tclass=dir permissive=0

Y lo solucioné observando que la etiqueta SELinux es incorrecta (el tcontext en el mensaje de error ya me lo dijo):

# ls -Z /mnt/media_rw/myextcard/my_DCIM_directory
drwxrwx--x  4 media_rw media_rw  u:object_r:mnt_media_rw_file:s0  4096 2018-06-08 12:34 .

y cambié eso (de forma recursiva) a una etiqueta que está permitida por la política predeterminada en LineageOS:

# chcon -R u:object_r:media_rw_data_file:s0:c512,c768 /mnt/media_rw/myextcard/my_DCIM_directory

Esto funcionó para mí, porque /sepolicy tiene una regla que establece que priv_app puede acceder a archivos de media_rw_data_file. Aquellos que tengan una situación/ROM diferente pueden usar setools-android para analizar su archivo /sepolicy y ver sus opciones.

0 votos

Gracias por esta increíble explicación. Voy a intentarlo tan pronto como tenga tiempo para hacerlo. PD. Usé el mismo sistema de archivos en la pregunta, pero en realidad intenté montar un directorio de mi SD externa en la SD interna.

1 votos

Esta declaración es engañosa: He estado utilizando montajes de enlaces sin deshabilitar los espacios de nombres de montajes. Necesitas estar en el espacio de nombres de montaje root antes de crear montajes de enlaces. De lo contrario, el directorio de origen solo será visible dentro del espacio de nombres de montaje aislado, no para todas las aplicaciones. Además, /mnt/runtime/{default,read,write}/dir2 es el mismo directorio, por lo que no necesitas hacer mkdir y rmdir en todos por separado. Además, montar en uno automáticamente se propaga a los otros dos, por lo que mount y umount también son necesarios solo en uno de los tres.

PreguntAndroid.com

PreguntAndroid es una comunidad de usuarios de Android en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X