Why (bind) mounts in /storage/emulated/0 are not visible in apps? I mounted a directory into another directory with:

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


I do this at boot completion with Tasker. I can see the mounted files in adb shell and in Termux, even as non-root user.
But I can not see these files in apps like Total Commander or my Music Player.

I use Lineage 7.1.2.

In this thread, a solution is to switch off "mount namespaces" in SuperSU. Unfortunately, I have the LineageOS default SU app which does not seem to provide such option. Any suggestions?
I have been using bind mounts without disabling mount namespaces on Android for a while - Marshmallow (Android 6) and Nougat (Android 7.1, LineageOS 14.1).

The bind mount is not visible to other apps because /storage/sdcard/ itself is also a layer of indirection. For example, when you run mount, you can see that the emulated "internal" SD card is not located at /storage/emulated, but at /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)


These three mountpoints in /mnt/runtime are documented at Storage, Runtime permissions:


  Android 6.0 introduces a new runtime permissions model where apps request capabilities when needed at runtime. Because the new model includes the READ/WRITE_EXTERNAL_STORAGE permissions, the platform needs to dynamically grant storage access without killing or restarting already-running apps. It does this by maintaining three distinct views of all mounted storage devices:
  
  
  /mnt/runtime/default is shown to apps with no special storage permissions, and to the root namespace where adbd and other system components live.
  /mnt/runtime/read is shown to apps with READ_EXTERNAL_STORAGE
  /mnt/runtime/write is shown to apps with WRITE_EXTERNAL_STORAGE
  


So to make a directory visible to all other apps, you need to create the mounts in these places:

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


To unmount:

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


In your question, the source and target are at the same filesystem, so the above will probably work as-is and show dir2 to other apps.

You can verify that the bind mounts are "visible" as intended by looking up the process ID of the desired app, and then checking the list of mounts from that app's point of view:

# cat /proc/(process ID here)/mountinfo


Debugging tips

If you cannot access the contents of the bind mount (i.e. "Permission denied" or something similar), then you should check whether the original file has the right UNIX permissions/ownership AND a SELinux label that matches the context. The latter can be debugged by looking for "avc: denied" errors in logcat-color (or just adb logcat). In some cases this can be fixed by using restorecon or chcon.

For example, I used to get the following error when I tried to access /sdcard/DCIM (which is a bind mount to a directory on external SD card).


  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


And fixed that one by observing that the SELinux label is wrong (the tcontext in the error message already told me so):

# 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 .


and changed that (recursively) to a label which is allowed by the default policy on LineageOS:

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


This worked for me, because /sepolicy has a rule that states that priv_app can access media_rw_data_file files. Those who have a different situation/ROM can use setools-android to parse their /sepolicy file to see their options.