Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ability to use usb otg storage in termux #71

Closed
fbartels opened this issue Mar 28, 2016 · 45 comments
Closed

Ability to use usb otg storage in termux #71

fbartels opened this issue Mar 28, 2016 · 45 comments

Comments

@fbartels
Copy link

Hi,

I am using Android 6 (cm13.0) and I have formatted my sd card as internal storage. I have already found https://termux.com/storage.html and when running termux-setup-storage I can acess my internal storage.

I also want to access a usb thumbdrive, which is visible in es explorer and the android storage settings, but will not be displayed beneath ~/storage (the folder external is missing as well).

Is this expected behaviour or is there something wrong on my device?

PS: the drive does show up in /storage btw. But trying to create a file on it will give a "permission denied"

@Neo-Oli
Copy link
Member

Neo-Oli commented Apr 1, 2016

I am on Android 5 and I can write to /storage/usbdisk without getting a "permission denied" error. Can you write to the usbdisk with other apps?

@fbartels
Copy link
Author

fbartels commented Apr 5, 2016

Yes, the behaviour changed in Android 6 a bit for external storage as far as i know. With the first Builds the drive could only be accessed from the storage settings, but starting with an update of es Explorer itmcould be opened directly as well.

@Neo-Oli
Copy link
Member

Neo-Oli commented Nov 18, 2016

@fornwall Is there anything that can be done here?

@fornwall
Copy link
Member

@Neo-Oli I'm not sure, need to test with a usb otg storage.

Perhaps direct file system access is not possible, and an api method could be added instead.

@fornwall
Copy link
Member

fornwall commented Nov 28, 2016

It seems that direct file system access is not possible starting from Android 6.0 - from Android USB media support documentation, as mentioned in this stackoverflow answer:

Multiple external storage devices
---------------------------------
Starting in Android 4.4, multiple external storage devices are surfaced to developers
through Context.getExternalFilesDirs(), Context.getExternalCacheDirs(),
and Context.getObbDirs().

External storage devices surfaced through these APIs must be a semi-permanent
part of the device (such as an SD card slot in a battery compartment).
Developers expect data stored in these locations to be available over long periods
of time. For this reason, transient storage devices (such as USB mass storage
drives) should not be surfaced through these APIs.

The WRITE_EXTERNAL_STORAGE permission must only grant write access to the
primary external storage on a device. Apps must not be allowed to write to
secondary external storage devices, except in their package-specific directories
as allowed by synthesized permissions. Restricting writes in this way ensures the
system can clean up files when applications are uninstalled.

USB media support
-------------------
Android 6.0 supports portable storage devices which are only connected to the
device for a short period of time, like USB flash drives. When a user inserts a new
portable device, the platform shows a notification to let them copy or manage the
contents of that device.

In Android 6.0, any device that is not adopted is considered portable. Because
portable storage is connected for only a short time, the platform avoids heavy
operations such as media scanning. Third-party apps must go through the
Storage Access Framework to interact with files on portable storage; direct
access is explicitly blocked for privacy and security reasons.

However, a command could be created (termux-storage-getfile) which requests a file from the system through a system file dialog (and perhaps outputs it to stdout, so it could be use either in pipes or like termux-storage-getfile > myfile.txt).

Also, it should be possible to write a termux-storage-putfile command, which takes a Termux-accessible file as argument, opens up a system file dialog where the user can choose a directory on storage devices where to put the file.

@omilu
Copy link

omilu commented Feb 19, 2017

The termux-storage-getfile mechanism gives no way to preserve the original filename. Is it possible to implement something to preserve the filename?? For example, I call termux-storage-getfile without a destination filename, and the scripts creates a file with the same name of the file I select from the usb drive, and copies into it.

@zhanglongqi
Copy link

zhanglongqi commented May 31, 2017

My thumb drive is mounted in /data/system/scsi/Disk1. It's owned by system, but I can read/write on it without error.
My android is 5.0.1

@wulvyrn
Copy link

wulvyrn commented Mar 22, 2018

would this be of use:
https://github.com/magnusja/libaums

having access to a usb drive for backup or additional storage would be nice.

@Konard
Copy link

Konard commented Jun 23, 2020

I need access to the OTG usb drive.

@locuturus
Copy link

This should be fixable by requesting the new permission known as "all files access" or "manage_external_storage" available from Android 11. USB drives would be available under /mnt/media_rw/abcd-1234

@analoginterface0
Copy link

analoginterface0 commented Jan 8, 2023

Greetings,

I've just tried-out my external SSD (NTFS formatted, one among total of two partitions, the other one is FAT16 ESP) manually linked to ~/storage/media-0 (an arbitrary folder) from termux 0.118.0 on my Xiaomi sweet MIUI 13 (Redmi Note 10 Pro global). Before doing that, I've allowed "All files access" from the Security app as @locuturus suggested: Privacy Protection => Special Permissions => All Files Access => Termux => toggle permission. And it works!

EDIT: my phone's not rooted, didn't use adb/wireless debugging for the purpose, nor do I have enabled 'adb security permissions' - as Xiaomi states it.

@sylirre
Copy link
Member

sylirre commented Jan 8, 2023

@analoginterface0 On AOSP or analogs it is not possible to grant full write access to all files on external disks (SD or USB) except the stored under directory Android/data/com.termux.

The suggestion made by @locuturus also not correct either. All files access permission doesn't work in such way, it only provides a way for application to opt-out from scoped storage (where it can access only given type, e.g. photos) in favor of full access. Such behavior is specific to Android 10 and higher.

Xiaomi, Samsung and other manufacturers who customize Android may change permission behavior. I'm not saying about custom ROMs where permissions can be messed up even more. If something works for you, this doesn't mean same works for everyone.

The storage behavior is well tested by Termux devs and so far there is no proper solution for this issue. Though we have set of Termux:API commands like termux-saf-ls, termux-saf-write, etc which can be a partial workaround.

@locuturus
Copy link

@sylirre I don't think you have that quite right. The documentation clearly states that All Files Access provides raw file path to apps with that permission. It is not just an escape from Scoped Storage restrictions it actually for the first time in modern Android history grants real file path to any directory you can reach with SAF and that includes USB. AOSP and Pixels and the like work just fine.

There is another app, Syncthing Fork, which cannot use SAF because the real work is done in Go and that cannot use the SAF API so there was no way to access USB drives without root. But now that the app has All Files Access you can manually give it file paths to any USB directory and it works.

I'm a little confused by @analoginterface0 situation, it reads to me like MIUI 13 can grant All Files Access to apps below the API level normally required. But for the rest of us AOSP folks I stand by what I wrote. Test it for yourself with Syncthing Fork, use the web interface, determine the real path to the USB you're testing and type it in there.

@agnostic-apollo
Copy link
Member

The MANAGE_EXTERNAL_STORAGE is not engaged or grantable unless app is targeting android 11+ (api 30+) and is the same as if legacy WRITE_EXTERNAL_STORAGE permission is granted. Termux already requests both in current github actions builds but its not being used since termux official builds use targetSdkVersion 28. As for whether removable sd or USB drives are accessible (both internally different, former is considered persistent storage by android), it depends on the build/vendor, some allow, some don't. Android 13 avd allows access to removable sd if WRITE_EXTERNAL_STORAGE is granted with termux using targetSdkVersion 28 and if MANAGE_EXTERNAL_STORAGE is granted with termux using targetSdkVersion 33. Termux cannot do anything more. If removable sd or USB access is required and storage permission does not allow it, then termux-api SAF apis will need to be used.

9eeb2ba

@agnostic-apollo
Copy link
Member

Quoting https://developer.android.com/training/data-storage/manage-all-files

The MANAGE_EXTERNAL_STORAGE permission grants the following:

  • Read and write access to all files within shared storage.
    Note: The /sdcard/Android/media⁠ directory is part of shared storage.
  • Access to the root directory of both the USB on-the-go (OTG) drive and the SD card.
  • Write access to all internal storage directories⁠, except for /Android/data/, /sdcard/Android, and most subdirectories of /sdcard/Android. This write access includes direct file path access.

Note that it ONLY says "direct file path access" for internal storages.

@locuturus
Copy link

Quoting https://developer.android.com/training/data-storage/manage-all-files

The MANAGE_EXTERNAL_STORAGE permission grants the following:

  • Read and write access to all files within shared storage.
    Note: The /sdcard/Android/media⁠ directory is part of shared storage.
  • Access to the root directory of both the USB on-the-go (OTG) drive and the SD card.
  • Write access to all internal storage directories⁠, except for /Android/data/, /sdcard/Android, and most subdirectories of /sdcard/Android. This write access includes direct file path access.

Note that it ONLY says "direct file path access" for internal storages.

There are many features of the various file access methods not detailed in that paragraph. You can get file path from media store DATA column but that is not mentioned either. I would not read very far into every omission. Using TermOne Plus I demonstrate on Sony Xperia 5 iii Android 13 stock ROM how to discover and read and write USB attached storage. This is what MANAGE_EXTERNAL_STORAGE permission makes possible in AOSP:
Screenshot_20230222-141054

I understand the other factors keeping Termux on API 28 but I want to set the record straight -- All Files Access is what every dev has been wanting all these years: real file paths to user accessable storage (aside from *Android/data).

@elvisisvan
Copy link

Quoting https://developer.android.com/training/data-storage/manage-all-files

The MANAGE_EXTERNAL_STORAGE permission grants the following:

  • Read and write access to all files within shared storage.
    Note: The /sdcard/Android/media⁠ directory is part of shared storage.
  • Access to the root directory of both the USB on-the-go (OTG) drive and the SD card.
  • Write access to all internal storage directories⁠, except for /Android/data/, /sdcard/Android, and most subdirectories of /sdcard/Android. This write access includes direct file path access.

Note that it ONLY says "direct file path access" for internal storages.

There are many features of the various file access methods not detailed in that paragraph. You can get file path from media store DATA column but that is not mentioned either. I would not read very far into every omission. Using TermOne Plus I demonstrate on Sony Xperia 5 iii Android 13 stock ROM how to discover and read and write USB attached storage. This is what MANAGE_EXTERNAL_STORAGE permission makes possible in AOSP: Screenshot_20230222-141054

I understand the other factors keeping Termux on API 28 but I want to set the record straight -- All Files Access is what every dev has been wanting all these years: real file paths to user accessable storage (aside from *Android/data).

how do you allow this MANAGE_EXTERNAL_STORAGE permission for termux?

@agnostic-apollo
Copy link
Member

After further investigation for changes in Android >= 12...

MANAGE_EXTERNAL_STORAGE permission is declared in AndroidManifest.xml of the Termux app, but currently only available for GitHub action builds, but not F-Droid or GitHub release builds and will be available for them in next release. Currently, termux uses targetSdkVersion 28. F-Droid and GitHub release builds will not show All files access and GitHub action builds will show both Files and All fIles access.

WRITE_EXTERNAL_STORAGE vs MANAGE_EXTERNAL_STORAGE

Enabling Android Settings -> Apps -> Termux -> Permissions -> Files will only grant legacy WRITE_EXTERNAL_STROAGE permission and enabling Android Settings -> Apps -> Special app access -> All files access -> Termux will only grant MANAGE_EXTERNAL_STORAGE permission. They are two different permissions, but access to primary external storage permission should still be available with either under the /storage/emulated/<user_id> or /sdcard paths.

However, granting MANAGE_EXTERNAL_STORAGE should additionally grant access to unreliable/removable volumes like USB OTG devices under the /mnt/media_rw/XXXX-XXXX paths on Android >= 12, check below. The termux-setup-storage command only requests the WRITE_EXTERNAL_STROAGE if the Termux app is using targetSdkVersion < 30, which is 28 currently for F-Droid and GitHub releases.

Storage Permissions Visibility

Assuming READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE permissions and requestLegacyExternalStorage="true" attributes are declared in AndroidManifest.xml of the app like Termux app does and app is running on Android 12 (older versions have different (broken) logic), then permissions will show as per following logic.

How does MANAGE_EXTERNAL_STORAGE grant unreliable/removable volume access?

Access is granted based on DAC and not SeLinux itself despite the search access given to app domains.

  • Unreliable/Removable volumes like USB OTG devices that are only available on the /mnt/media_rw paths with their own filesystem (vfat/exfat) are assigned the root (0) owner and external_storage (1077) group.
  • The reliable/adoptable volumes like SD cards that are backed with FUSE or sdcardfs filesystems for normal apps to access that are bind mounted under /storage from their initial /mnt/media_rw mount path are assigned the root (0) owner and media_rw (1023) group.

If an app has been granted the MANAGE_EXTERNAL_STORAGE permission, then the external_storage (1077) group is added to list of groups that are assigned to the app process when its forked from zygote, allowing it to access unreliable/removable volumes with the external_storage (1077) group, but not the media_rw (1023) group.

App process groups can be checked with cat /proc/self/status | grep ^Groups:. Path group can be checked with stat /mnt/media/XXXX-XXXX, where XXXX-XXXX is the volume UUID.

@KurtGokhan
Copy link

KurtGokhan commented Mar 10, 2024

@agnostic-apollo I installed the Termux from Github Actions build. "All files access" permission did finally appear for Termux and I granted it. But when I check for groups in Termux, I still don't have external_storage group and I can't access external storage. Am I missing something? I do have root access too, if it can help me setup the external storage in Termux.

Android 11
Termux v0.118.0+8e3a898-apt-android-7-github-debug_arm64-v8a

@agnostic-apollo
Copy link
Member

However, granting MANAGE_EXTERNAL_STORAGE should additionally grant access to unreliable/removable volumes like USB OTG devices under the /mnt/media_rw/XXXX-XXXX paths on Android >= 12, check below

@KurtGokhan
Copy link

Indeed. I installed an Android 14 ROM and after rooting, termux seems to have external_storage group. To make the external storage access work better, I had to enable FUSE passthrough as in these instructions. It seems to work well so far (although feels a bit slow but maybe that is related to my OTG cable).

@agnostic-apollo
Copy link
Member

cool, although fuse passthrough would not apply to otg as that won't be emulated...

@ED4free
Copy link

ED4free commented Mar 27, 2024

On Android 12, I plug an OTG USB C dongIe formated exFat.
Installed the Termux from Github Actions build. After launching it, I called termux-setup-storage and grant the access. I verified in setting menu that "Manage all files" was granted.
Nevertheless, if I make : ls -l /mnt/media_rw/ or ls -l /mnt/media_rw/8678-0073/ I get permission denies.

With another app, having the same right MANAGE_EXTERNAL_STORAGE, this command works. It is with this app that I know that 8678-0073 is the identifier of my USB Key.

@agnostic-apollo
Copy link
Member

agnostic-apollo commented Mar 27, 2024

termux-setup-storage grants WRITE_EXTERNAL_STORAGE. Disable it manually and grant All files access.

Enabling Android Settings -> Apps -> Termux -> Permissions -> Files will only grant legacy WRITE_EXTERNAL_STROAGE permission and enabling Android Settings -> Apps -> Special app access -> All files access -> Termux will only grant MANAGE_EXTERNAL_STORAGE permission.

I may have to rethink logic for requesting permission, unless there are other advantages of legacy storage.

@ED4free
Copy link

ED4free commented Mar 27, 2024

Thank you @agnostic-apollo , it works.
Another question : I have the right on /mnt/media_rw/XXXX-XXXX , but not on /mnt/media_rw/
So do you know how to know the value of XXXX-XXXX ?
Thierry

@ED4free
Copy link

ED4free commented Mar 27, 2024

And thanks for telling me in which file are manage permission.
I think I'll add something link this,which work on my other app :

        if (ContextCompat.checkSelfPermission(this, MANAGE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            Log.d("Thierry", "Request MANAGE_EXTERNAL_STORAGE");
            ActivityCompat.requestPermissions(this, new String[]{MANAGE_EXTERNAL_STORAGE}, 1);
        } 

@agnostic-apollo
Copy link
Member

Following should probably work, i haven't tested, check if it returns /mnt/media_rw path. You may need to check primary/emulated/removable state. I am not sure what external sd card that's inserted into sd card slot would return, it probably returns /storage path instead. You could probably also use mount command if it needs to be done in shell, but checking for /mnt/media_rw mount will also return the initial mount of external sd card if user has inserted that and you will then have to check if there is no mount for it's uuid under /storage as well, as usb otg should not.

https://developer.android.com/reference/android/os/storage/StorageManager#getStorageVolumes()

https://developer.android.com/reference/android/os/storage/StorageVolume#getDirectory()

As for requesting permission, check following, should only call it for Android >= 12.

* Request user to grant {@link Manifest.permission#MANAGE_EXTERNAL_STORAGE} permission to the app.

@ED4free
Copy link

ED4free commented Mar 27, 2024

Good idea mount for finding the path of USB storage, this works fine :
mount | grep -ho '/mnt/media_rw/[-0-9]*'

@agnostic-apollo
Copy link
Member

agnostic-apollo commented Mar 27, 2024

Best use grep -E "^[^ ]+ /mnt/media_rw/[A-Z0-9]{4}-[A-Z0-9]{4} " /proc/mounts | cut -d' ' -f2 instead.

/proc/mounts format is specified by the kernel, mount command is a user space utility and has a different format.

We match the first two fields in the regex and then get the second one with cut. The space character before and after the second /mnt field ensures we are matching a mount destination and on the directory itself and not a mount on a subdirectory, the space character in paths itself is replaced with \040 octal value in /proc/mounts file so that it does not interfere with space field separator. Your regex would also match entries where the mount source is under /mnt, like for a loop ext4 image in sd card mounted at some other path. My regex starts with ^ to ensure that start of line, i.e first field is matched.

However, like I said, this will still return more that one entry if both a usb drive and an external sd card is mounted. You will then have to find for which entry grep -qE "^[^ ]+ /storage/$(basename "$entry") " /proc/mounts does not exit with exit code 0.

@locuturus
Copy link

locuturus commented Mar 27, 2024

If I'm in the shell already I like df | grep vold to quickly find USB drive paths.

Edit: works for removable sdcard too, and remember with hubs you can attach multiple USB drives so it'll be tricky to parse any output for exactly 1 drive reliably.

@ED4free
Copy link

ED4free commented Mar 28, 2024

Thanks a lot @agnostic-apollo , this command works perfectly, and it is surely more reliable than mine. You are rignt, on my device their are only number, but it can be A-Z letter also. I keep your command for my initialization script. It search for external storage (SD or USB), if it found one it search on it the configuration script with a find.
Greate news : it works both for SD card and USB dongle !

@locuturus , on my Android 12 device, the USB storage SOMETIMES also appears in df command. But sometimes not.

@ED4free
Copy link

ED4free commented Mar 28, 2024

@agnostic-apollo , about the permission "Manage all files", I apologize because I have made something probably very dirty, but which makes what I need :

    class TermuxActivityBroadcastReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent == null) return;

            if (mIsVisible) {
                fixTermuxActivityBroadcastReceiverIntent(intent);

                switch (intent.getAction()) {
                    case TERMUX_ACTIVITY.ACTION_NOTIFY_APP_CRASH:
                        Logger.logDebug(LOG_TAG, "Received intent to notify app crash");
                        TermuxCrashUtils.notifyAppCrashFromCrashLogFile(context, LOG_TAG);
                        return;
                    case TERMUX_ACTIVITY.ACTION_RELOAD_STYLE:
                        Logger.logDebug(LOG_TAG, "Received intent to reload styling");
                        reloadActivityStyling(intent.getBooleanExtra(TERMUX_ACTIVITY.EXTRA_RECREATE_ACTIVITY, true));
                        return;
                    case TERMUX_ACTIVITY.ACTION_REQUEST_PERMISSIONS:
                        Logger.logDebug(LOG_TAG, "Received intent to request storage permissions");
                        requestStoragePermission(false);

                        /// Ajout Thierry

                        if (ContextCompat.checkSelfPermission(TermuxActivity.this, MANAGE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                            ActivityCompat.requestPermissions(TermuxActivity.this, new String[]{MANAGE_EXTERNAL_STORAGE}, 1);
                        }

                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                            if (!Environment.isExternalStorageManager()) {
                                Intent intent2 = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
                                String name = getPackageName();
                                Uri uri = Uri.fromParts("package", name, null);
                                intent2.setData(uri);
                                startActivity(intent2);
                            }
                        }
                        ///// Fin ajouts Thierry

                        return;
                    default:
                }
            }
        }
    }

I tried to add this piece of code in requestStoragePermission() but in this case it was called twice, I didn't understand why.
The same if I call PermissionUtils.requestManageStorageExternalPermission()

NB : the authorization require a restart of Termux-app to be taken into account. Is there a way to restart within the shell ? something like : kill $(ps -ef | grep 'com.termux' | grep -v 'grep' | grep -v 'com.termux.' |awk '{ print $2 }'); am start -n com.termux/.HomeActivity; exit
(except that this does not work becaus the kill stop the command)

@locuturus
Copy link

@locuturus , on my Android 12 device, the USB storage SOMETIMES also appears in df command. But sometimes not.

Ok, good to know it's not reliable across devices and/or OS versions. A little strange though - I picked this for myself a while ago because it actually does work on an A13 Samsung Tab S6 tablet and I was having trouble with that device.

@agnostic-apollo
Copy link
Member

You can use this function in bash shell to find the most recently connected usb otg drive on Android >= 11. For Android 7, there is a mount on both /mnt and /storage paths for usb otg, so cannot distinguish between usb otg (unreliable) and external sd card (reliable). I don't know which android version removed mounting at /storage path for usb otg, but its likely android 11 as it added MANAGE_EXTERNAL_STORAGE too, so possibly related. Note that if multiple usb otg drives are attached like with a usb hub or possibly multiple partitions exist in the same usb, then only the latest mount will be returned. This is done by checking matched entries of /proc/mounts in reverse order, as latest mount would come in the end.

You can paste the function in terminal or add to ~/.bashrc or your scripts, etc.

find_most_recent_unreliable_storage_mount() {

    local return_value

    local i
    local storage_mounts_string
    local storage_mount
    local storage_mount_basename
    local unreliable_storage_mount
    local android_build_version_sdk
    local valid_number_regex='^[0-9]+$'

    local -a storage_mounts_array=()

    # Find android sdk/os version
    # Termux app exports ANDROID__BUILD_VERSION_SDK for `>= v0.119.0`
    if [[ ! "$ANDROID__BUILD_VERSION_SDK" =~ $valid_number_regex ]]; then
        android_build_version_sdk="$(unset LD_LIBRARY_PATH; unset LD_PRELOAD; getprop "ro.build.version.sdk")"
        return_value=$?
        if [ $return_value -ne 0 ] || [[ ! "$android_build_version_sdk" =~ $valid_number_regex ]]; then
            echo "Failure while finding \"ro.build.version.sdk\" property" 1>&2
            echo "ANDROID__BUILD_VERSION_SDK = \"$android_build_version_sdk\"" 1>&2
            if [ $return_value -eq 0 ]; then
                return_value=1
            fi
            return $return_value
        fi
    else
        android_build_version_sdk="$ANDROID__BUILD_VERSION_SDK"
    fi

    # If on Android `< 11`
    if [ "$android_build_version_sdk" -lt 30 ]; then
        echo "Cannot find unreliable storage mounts on Android sdk version '< 30'. Current sdk version is '$android_build_version_sdk'." 1>&2
        return 1
    fi

    storage_mounts_string="$(grep -E "^[^ ]+ /mnt/media_rw/[A-Z0-9]{4}-[A-Z0-9]{4} " /proc/mounts | cut -d' ' -f2)"
    return_value=$?
    if [ $return_value -ne 0 ]; then
        echo "Failure while finding most recent unreliable storage mount" 1>&2
        return $return_value
    fi

    if [ -z "$storage_mounts_string" ]; then
        echo "Failed to find any reliable or unreliable storage mounts" 1>&2
        return 1
    fi

    IFS=$'\n' read -r -d '' -a storage_mounts_array <<< "$storage_mounts_string"

    for (( i=${#storage_mounts_array[@]} - 1; i >= 0; i-- )) ; do
        storage_mount="${storage_mounts_array[i]}"
        storage_mount_basename="${storage_mount##*/}"

        grep -qE "^[^ ]+ /storage/$storage_mount_basename " /proc/mounts
        return_value=$?
        if [ $return_value -eq 1 ]; then
            unreliable_storage_mount="$storage_mount"
            break
        elif [ $return_value -ne 0 ]; then
            echo "Failure while finding if storage mount is unreliable" 1>&2
            return $return_value
        fi
    done

    if [ -z "$unreliable_storage_mount" ]; then
        echo "Failed to find any unreliable storage mounts" 1>&2
        return 1
    fi

    echo "$unreliable_storage_mount"

}

Greate news : it works both for SD card and USB dongle !

The the /mnt grep should work for both. Really depends on what you are trying to do, your use case was usb otg only if I remember correctly.

df | grep vold

/dev/block/vold entry would also exist for external sd cards (reliable) as vold mounts them too. Moreover, usb otg entry is not shown in df output on Android 11, but does on Android 14. Not really reliable to use df and /proc/mount should be preferred for utilities.

@agnostic-apollo
Copy link
Member

I tried to add this piece of code in requestStoragePermission() but in this case it was called twice, I didn't understand why.

You are calling requestStoragePermission(), then requestPermissions(), and then startActivity(), so of course there will be repeats. Moreover, requestStoragePermission() is already called by TermuxActivity twice in master branch, when requesting permission and when result is received. It's best to not mess with that logic. If you want to always request MANAGE_EXTERNAL_STORAGE permission on Android >= 11, it would be better to add following to start of PermissionUtils.checkAndRequestLegacyOrManageExternalStoragePermission() instead.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
    if (Environment.isExternalStorageManager())
        return true;

    errmsg = context.getString(R.string.msg_storage_permission_not_granted);
    Logger.logError(LOG_TAG, errmsg);
    if (showErrorMessage)
        Logger.showToast(context, errmsg, false);

    if (requestCode >= 0)
        requestManageStorageExternalPermission(context, requestCode);

    return false;
}

the authorization require a restart of Termux-app to be taken into account.

You can run kill "$TERMUX_APP__PID" to kill termux app, but it will not restart it, there are ways to trigger a restart from java code with some hacks.

If you just want to kill from java, then can use following. Note the import, java.lang.Process is different and will be used by default.

import android.os.Process;

try {
    finishAffinity();
} catch (Exception e) {
    // Ignore
}

Process.killProcess(Process.myPid());

@ED4free
Copy link

ED4free commented Mar 29, 2024

@agnostic-apollo

it would be better to add following to start of PermissionUtils.checkAndRequestLegacyOrManageExternalStoragePermission() instead.

It works fine, I keep it instead of my changes, thank you.

@ED4free
Copy link

ED4free commented Mar 29, 2024

@agnostic-apollo

The the /mnt grep should work for both. Really depends on what you are trying to do, your use case was usb otg only if I remember correctly.

My use case is : I am looking for existing script called "Eduphone_initTX.sh", I first search in SD card or USB if exists, then in /sdcard in not. If I find this sh I execute it. This task is in a small sh put in profile.d of bootstrap, it does nothing if application directory already exists. The SD card or otg USB contains the whole data for Eduphone installation ( mainly tar.gz of the the working environment, and some apk). Eduphone_initTX.sh make the installation : install the apk (termux-api, termux-widget, a wifi hot-spot for old smartphone, my apk for managing the configuration) and restore the tar.gz
So for me SD card or otg USB is the same.

@agnostic-apollo
Copy link
Member

You are welcome.

By sd card do you mean, "sd card that gets inserted into sd card slot of phone" or "sd card connected with usb otg cable and external sd card reader"?

@ED4free
Copy link

ED4free commented Mar 29, 2024

By sd card I mean "sd card that gets inserted into sd card slot of phone".
I manage in the same way "sd card that gets inserted into sd card slot of phone" and "anything connected with usb otg".

# Search in external storage SD or USB
SEARCH="Eduphone_initTX.sh"
FILE=""
LEXTST=$( grep -E "^[^ ]+ /mnt/media_rw/[A-Z0-9]{4}-[A-Z0-9]{4} " /proc/mounts | cut -d' ' -f2)
    FILE=""
    for EXTST in $(echo "$LEXTST"); do
    CMD="TMPFILE=\$(find $EXTST -maxdepth 3 -type f 2>$LOGFILE | grep -e '.*$SEARCH')"
    if  [ "$EXTST" != "" ]; then eval "$CMD"; fi;
    if [ "$TMPFILE" != "" ]; then FILE="$TMPFILE"; fi;
    echo "FILE=$FILE"
    done

nb : sorry for my poor bash :)

@agnostic-apollo
Copy link
Member

Can you send output for stat /mnt/media_rw/XXXX-XXXX and stat /storage/XXXX-XXXX for the sd card UUID paths? And which phone are you testing on?

Also can you access the sd card with /storage path?

@ED4free
Copy link

ED4free commented Mar 29, 2024

I test on a Samsung A326B

On SD card :

~ $ stat /mnt/media_rw/0B99-1B07
  File: /mnt/media_rw/0B99-1B07
  Size: 32768           Blocks: 64         IO Block: 32768  directory
Device: 179,1   Inode: 1           Links: 19
Access: (0770/drwxrwx---)  Uid: (    0/    root)   Gid: ( 1023/media_rw)
Access: 2024-03-29 22:20:00.000000000 +0100
Modify: 2024-03-29 22:20:00.000000000 +0100
Change: 2024-03-29 22:20:00.000000000 +0100
 Birth: -

~ $ stat /storage/0B99-1B07
  File: /storage/0B99-1B07
  Size: 32768           Blocks: 64         IO Block: 32768  directory
Device: 0,89    Inode: 1           Links: 19
Access: (0770/drwxrwx---)  Uid: (    0/    root)   Gid: ( 9997/everybody)
Access: 2024-03-29 22:20:00.000000000 +0100
Modify: 2024-03-29 22:20:00.000000000 +0100
Change: 2024-03-29 22:20:00.000000000 +0100
 Birth: -
~ $

On otg

~ $ stat /mnt/media_rw/8678-0073
  File: /mnt/media_rw/8678-0073
  Size: 131072          Blocks: 256        IO Block: 131072 directory
Device: 8,49    Inode: 1           Links: 6
Access: (0770/drwxrwx---)  Uid: (    0/    root)   Gid: ( 1077/external_storage)
Access: 2024-03-29 22:22:06.000000000 +0100
Modify: 2024-03-29 22:22:06.000000000 +0100
Change: 2024-03-29 22:22:06.000000000 +0100
 Birth: -

Notice that this point works fine.

@agnostic-apollo
Copy link
Member

Thanks and what's the output of cat /proc/self/status | grep ^Groups:?

@ED4free
Copy link

ED4free commented Mar 29, 2024

~ $ cat /proc/self/status | grep ^Groups:
Groups: 1077 3003 9997 20396 50396

@agnostic-apollo
Copy link
Member

Are you on Android 12 on this device as stated before?

@ED4free
Copy link

ED4free commented Mar 29, 2024

Android 12

agnostic-apollo added a commit that referenced this issue Jun 17, 2024
…`>= 11` when running `termux-setup-storage`

Requesting `MANAGE_EXTERNAL_STORAGE` should additionally grant access to unreliable/removable volumes like USB OTG devices under the `/mnt/media_rw/XXXX-XXXX` paths on `Android >= 12`, so request that if possible. Check #71 (comment) for more info.

Fixes issue on Android `14`, where using `targetSdkVersion=28`, that requests the legacy `WRITE_EXTERNAL_STORAGE` will actually request the `photos, music, video, and other files` permissions (`READ_MEDIA_AUDIO`/`READ_MEDIA_IMAGES`/`READ_MEDIA_VIDEO`) and apparently access to full external storage `/sdcard` is not available for some users, maybe because `READ_EXTERNAL_STORAGE` and `WRITE_EXTERNAL_STORAGE` permissions are not granted for those device automatically in addition to `READ_MEDIA_*` permission. The issue is not reproducible on Android `13-15` avd. To solve this, we request the singular `MANAGE_EXTERNAL_STORAGE` permission instead so that full access is always available.

Related: #3647 (comment)

See also:
- https://developer.android.com/training/data-storage/shared/media#access-other-apps-files
- https://developer.android.com/reference/android/Manifest.permission#READ_MEDIA_IMAGES
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests