I have a requirement for my Android app to be able to receive files from a server and save them in an arbitrary location on my SD card. When I say "SD card", I don't mean the /sdcard/ directory - AKA /storage/emulated/0/, I mean the physical removable SD card.
My initial attempt:
FileOutputStream(File("storage/ABCD-1234", "test_file.txt")).use {
it.write("Hello world!".toByteArray())
}
where "ABCD-1234" is replaced with the actual storage ID string. This gives me an IOException saying permission denied, even though I have the WRITE_EXTERNAL_STORAGE permission granted. Fine, there must just be some restrictions on SD card writing access. So I spent most of today researching around the internet for apps which can already do this. And I come across this one called SSH/SFTP Server, using which I was able to push a file to the device's SD card via WinSCP from a laptop over WiFi. The thing is, I can't figure out how to go about requesting this ability in my app. Can anyone point me in the right direction?
This is targeting Android Q (10), in case it matters at all.
Related
N.B.: This question about the serial number of the physical SD card, not the UUID of the mounted volume. These are two independent pieces of data.
In some versions of Android, and other variants of Linux, it's possible to get the serial number of a mounted SD card, e.g. by reading the contents of /sys/class/mmc_host/mmc0/mmc0:0001/serial or /sys/block/mmcblk0/device/serial (specific numbers may vary). In my testing this has worked pretty reliably, as long as the SD card is inserted in a built-in SD card slot (not mounted via USB adapter).
But as of Android 7.0 Nougat, the OS is said to be blocking access to this information, at least on some devices. I tested this by running a test app on a new Alcatel A30 GSM (Android 7.0), and in fact the above approach fails with a permission error:
java.io.FileNotFoundException: /sys/block/mmcblk0/device/serial (Permission denied)
at java.io.FileInputStream.open(Native Method)
For future reference, we (testing from an adb shell) have permissions to ls -ld the following:
/sys/class/mmc_host but not /sys/class/mmc_host/mmc0
/sys/block but not /sys/block/mmcblk0
Since the above approach no longer works,
Is there another way to obtain the serial number of a mounted SD card in Android 7.0 or later?
Failing that, is there any documentation or other statement from Google on plans for providing or not providing this function? I haven't found anything in the Android issue tracker, but maybe I'm not searching right.
To make sure the question is clear, I'm talking about what an ordinary (non-system) app running on a non-rooted device can do, with any permissions that an app can normally request and receive.
FYI, the /sbin directory doesn't seem to be readable, so commands like /sbin/udevadm aren't an option.
In Android N access to /sys nad /proc was significantly restricted, this was done to provide stricter sandboxes where applications run. This is explained in https://issuetracker.google.com/issues/37091475 as intentional. Actually its not said that all the data in /sys is not accessible, and Google is open to allow access to other files from this location:
If there are specific files in /sys you believe should be available to applications, but are not, please file a new bug where the request can be evaluated. For instance, /sys/devices/system/cpu is available to all processes, so it's inaccurate to say all of /sys is restricted.
I have a bad feeling that google is making changes similar to Apple where it is not allowed to gain hardware id-s. If that is not resolved then the solution is to use google account IDs instead. But I am aware it is not always possible, and will require major changes in business logic (licensing etc.).
Hopefully your bug report will be considered positively.
another related SO I found : File system changes in Android Nougat
Use StorageVolume.getUuid() on StorageVolume which you get from StorageManager.
The value is volume ID assigned during formatting of the card, and its length/format differs depending on file system type. For FAT32 it is XXXX-XXXX, for NTFS it's longer hex string, for Internal mass storage it returns null.
public String getSDCARDiD()
{
String sd_cid = null;
try {
File file = new File("/sys/block/mmcblk1");
String memBlk;
if (file.exists() && file.isDirectory()) {
memBlk = "mmcblk1";
} else {
//System.out.println("not a directory");
memBlk = "mmcblk0";
}
Process cmd = Runtime.getRuntime().exec("cat /sys/block/"+memBlk+"/device/cid");
BufferedReader br = new BufferedReader(new InputStreamReader(cmd.getInputStream()));
sd_cid = br.readLine();
//System.out.println(sd_cid);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return sd_cid;
}
try this: reference original link :Android get id of SD Card programmatically
adb shell cat /sys/class/mmc_host/mmc1/mmc1:*/cid
You can also try
sudo hwinfo --disk
to get information on your disks, including SD Cards.
Also try
sudo hdparm -I /dev/sdb | more
As an FYI to those looking into UUID or volume serial numbers of FAT type volumes under Android: Some Fujifilm cameras, including the X-T30 (Firmware 1.10) do not write a volume serial number into the FAT volume when formatting.
Under Windows, CHKDSK displays no volume serial number at all.
On Android, calling StorageVolume.getUuid() returns "0000-0000".
This is all fine and dandy, until you on Android mount two Fujifilm-formatted cards via a hub. Then there seems to be identity collision, where the Android OS prompts the user to format one of the cards. Separately they are accessible.
I'm guessing there are two combined problems here:
1) Fujifilm is not writing a volume serial number when formatting, and
2) Android uses the volume serial number as part of the mount point path, leading to collision.
Fujifilm and Google might both want to pay attention to this issue.
EDIT: Card formatted in a Nikon D810 also has the same problem, no Volume Serial Number.
I'm trying to create something like file explorer through connected usb devices(via OTG or usb ports on android TV).
All I need for this is a path something like "/storage/sda4" and device identifier, and then I can work with device through simle android class File. Is sounds simple but I can't find any info about this, but all file explorers can do it (for example ESExplorer).
Ok, I find a simple way to get all connected usb devices with identifier
UsbManager usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
usbManager.getDeviceList();
but how can I get an info about path? deviceName contains something like this "/dev/bus/usb/00x" but it can't help me, I need simple emulated android path ("/storage/sda4"). This page https://developer.android.com/guide/topics/connectivity/usb/host.html tells that I need to get UsbInterfaces and make UsbConnection to bulk transfer and other bullshit, I done it all but didn't find path to device or any other info about usb file list.
Ok, I find another way to get (that don't requires permission!) to get path to all connected devices
StorageManager storageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
Method getVolumeListMethod = StorageManager.class.getDeclaredMethod("getVolumeList");
Object[] storageVolumeList = (Object[]) getVolumeListMethod.invoke(storageManager);
and it works but I need to identify a device(because I want to cache files of different usb storages) but all that I can get from volume object is mStorageId, mDescriptionId, mPrimary, mRemovable, mEmulated, mMtpReserveSpace, mAllowMassStorage, mMaxFileSize, mOwner, mUuid, mUserLabel, mState, mSubSystem.
None of this can not identify the device: mDescriptionId and mStorageId are
unique fot usb port, mUuid is null, mUserLabel is not unique.
Environment.getExternalFilesDirs() won't help, it don't provide any device id and works only with one device.
I find a similar question here, but it has no right answer Android list files from USB Drive.
Well, is a simple way to get list of usb devices with path and identifier exists?
All I need for this is a path something like "/storage/sda4" and device identifier, and then I can work with device through simle android class File
No, because you do not have arbitrary access to removable storage, including USB OTG drives, on Android 4.4+.
all file explorers can do it (for example ESExplorer)
Pre-installed "file explorer" apps may have additional rights granted to them by the device manufacturer or custom ROM developer. Otherwise, they too do not have arbitrary access to removable storage.
is a simple way to get list of usb devices with path and identifier exists?
Not with a filesystem path, no. getStorageVolumes() on StorageManager will give you a list of storage volumes, which includes external storage and removable storage. You can then use createAccessIntent() on StorageVolume to ask the user for permission to work with the volume. If they grant permission, you get a Uri back that:
Serves as a temporary identifier for the volume (i.e., will no longer be usable as an identifier if the user ejects the media, but until then, can distinguish one volume from another), and
Lets you work with a portion of the contents of that volume, though using Uri values, not filesystem paths
I want to read the status file of all processes in an Android system. I check the permission of /proc/pid/status files, it is -r-r-r-, seems like it could be read from every user, and I have turn seAndroid off.
In shell, it works fine, but when I read the file in an application (.apk), it always return "no such file". I think maybe it is the permission issue, but I don't know why, what blocks an application from reading this file.
So the app I'm working on is making use of the external files dir to store some downloaded information. The issue I'm running into is, very ocassionally the getExternalFilesDir() method will return null. My understanding of this method might be flawed, but I was under the impression that it would return null under TWO distinct scenarios:
1) The user has an SD card slot but does NOT have an sd card mounted (or the SD card is mounted but plugged into a computer as mass storage option)
2) The app does not actually have read/write permissions
The app has the read/write permissions (it must since it works in most scenarios), and I I'm checking for the first case with the following code:
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()))
{
editor.putBoolean(AUDIO_LOCATION_KEY, true);
subPath = context.getExternalFilesDir(null).getPath();
}
The app is crashing with a null pointer exception from the getExternalFilesDir line. I can't reproduce the crash, Is there something I'm missing? I would've that that if that check passed that we'd be guaranteed to get something back. Any insight would be much appreciated!
Thanks.
Is it possible or is there a way in Android v2.2+ to detect if there is a mass storage, external drive or micro SD inserted in the device?
My objective is, I want to create an app that will be invoked once an external storage like micro SD is inserted in the device?
I want to know if:
1) Is there a standard intent broadcasted once an SD is mounted in the device?
2) Do I have to deal with it in the native driver layer to achieve this?
Any thoughts are highly appreciated.
Thanks
Yes there is a standard intent broadcast, you are probably looking for the ACTION_MEDIA_MOUNTED broadcast.
ACTION_MEDIA_MOUNTED
Since: API Level 1
Broadcast Action: External media is present and
mounted at its mount point. The path to the mount point for the
removed media is contained in the Intent.mData field. The Intent
contains an extra with name "read-only" and Boolean value to indicate
if the media was mounted read only.
Source