¿Por qué los montajes (vinculados) en /storage/emulated/0 no están visibles en las aplicaciones?

Monté un directorio en otro directorio con:

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

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

Yo uso Lineage 7.1.2.

En este hilo, una solución es desactivar "montar espacios de nombres" en SuperSU. Desafortunadamente, tengo la aplicación SU predeterminada de LineageOS que no parece ofrecer esa opción. ¿Alguna sugerencia?

Respuestas (1)

He estado usando 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 direccionamiento indirecto. Por ejemplo, cuando ejecuta mount, puede ver que la tarjeta SD "interna" emulada no se encuentra en /storage/emulated, sino en /data/media:

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

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

Android 6.0 presenta un nuevo modelo de permisos de tiempo de ejecución en el que las aplicaciones solicitan capacidades cuando es necesario en tiempo de ejecución. Debido a que el nuevo modelo incluye los permisos READ/WRITE_EXTERNAL_STORAGE, la plataforma debe otorgar acceso de almacenamiento de forma dinámica sin eliminar o reiniciar las aplicaciones que ya se están ejecutando. Lo hace manteniendo tres vistas distintas de todos los dispositivos de almacenamiento montados:

  • /mnt/runtime/defaultse muestra a las aplicaciones sin permisos de almacenamiento especiales y al espacio de nombres raíz donde residen adbd y otros componentes del sistema.
  • /mnt/runtime/readse muestra a las aplicaciones conREAD_EXTERNAL_STORAGE
  • /mnt/runtime/writese muestra a las aplicaciones conWRITE_EXTERNAL_STORAGE

Entonces, para hacer que un directorio sea visible para todas las demás aplicaciones, debe 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 su pregunta, la fuente y el destino están en el mismo sistema de archivos, por lo que lo anterior probablemente funcionará tal cual y mostrará dir2 a otras aplicaciones.

Puede verificar que los montajes de vinculación sean "visibles" según lo previsto buscando 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/(process ID here)/mountinfo

Sugerencias de depuración

Si no puede acceder al contenido del montaje de vinculación (es decir, "Permiso denegado" o algo similar), entonces debe verificar si el archivo original tiene los permisos/propiedad UNIX correctos Y una etiqueta SELinux que coincida con el contexto. Este último se puede depurar buscando errores "avc: denegados" en logcat-color (o simplemente adb logcat). En algunos casos, esto se puede arreglar usando restorecono chcon.

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

avc: denegado {escribir} para comm=... name="Cámara" dev="dm-1" ino=3547138 scontext=u:r:priv_app:s0:c512,c768 tcontext=u:object_r:mnt_media_rw_file:s0 tclass =dir permisivo=0

Y lo arreglé observando que la etiqueta SELinux está mal (el tcontextmensaje 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 (recursivamente) 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 /sepolicytiene una regla que establece que priv_apppuede acceder a media_rw_data_filelos archivos. Aquellos que tienen una situación/ROM diferente pueden usar setools-android para analizar su /sepolicyarchivo y ver sus opciones.

Gracias por esta genial explicación. Lo intentaré en cuanto tenga tiempo para ello. Por cierto. Usé el mismo sistema de archivos en la pregunta, pero en realidad traté de montar un directorio desde mi SD externa a la SD interna.
Esta declaración es engañosa: he estado usando montajes de enlace sin deshabilitar los espacios de nombres de montaje . Debe estar en el espacio de nombres de montaje raíz antes de crear montajes de enlace. De lo contrario, el directorio de origen solo será visible dentro del espacio de nombres de montaje aislado, no para todas las aplicaciones. También /mnt/runtime/{default,read,write}/dir2es el mismo directorio, por lo que no necesita hacer mkdiry rmdiren todos por separado. Además, el montaje en uno se propaga automáticamente a los otros dos, por lo que mounty umounttambién se requieren solo en cualquiera de los tres.