dirs-dev/directories-rs

No project directory on Android

Opened this issue ยท 14 comments

I am calling the following on Android

directories::ProjectDirs::from("me", "nikl", "game");

and get back None. The package identifier is me.nikl.game and the app is running on a real device with Android 12.

Is there anything I need to setup or configure to get a proper project directory on Android?

soc commented

Hi @NiklasEi,

that should work, can you check whether BaseDirs and UserDirs also return None? Using the dirs crate, can you check what dirs::home_dir() returns?

Thanks,

Simon

Hey @soc,
I just checked and yes, both BaseDirs and UserDirs return None. The same goes for dirs::home_dir().
I am testing this on a galaxy S10+ if that's of any help.

I am getting the same response from dirs::home_dir() on two different emulated pixel phones. Should this crate work for android emulators?

soc commented

I suspect that home_dir is the culprit and everything else are just the result of that returning None.

Does Android have any sensible definition of a home directory?

Looking at the implementation, https://github.com/dirs-dev/dirs-sys-rs/blob/main/src/lib.rs#L33, we rely on the environment variable and do not offer a fallback. Can you check whether the env var is set on Android?

Running adb shell with my device connected via USB followed by echo $HOME I get / back, which is not the correct directory for an app to write to or read from.

It seems that the intended way of getting the correct directory is calling Context#getFilesDir, which according to the android stackexchange should point to /data/data/<app>/files or /data/users/<n>/<app>/files depending on your setup.

I tried some paths in my app and managed to write and read from /data/data/me.nikl.game/files ๐Ÿฅณ

I might have found something with env variables: https://cs.android.com/android/platform/superproject/+/refs/heads/master:frameworks/base/core/java/android/os/Environment.java;drc=a3bb1640c5a3422645b8493ee0bb00eab4266c32;l=98
The env variable ANDROID_DATA is set to /data on my device. It still might be an issue to hard code the /data/<identifier>/files in case we should be using /users/<n>/<identifier>/files instead. I haven't understood in what scenario the second path is chosen.

There seem to be multiple possible directories for a given application and I cannot see another way to get the intended one from a simple environment variable. See https://cs.android.com/android/platform/superproject/+/refs/heads/master:frameworks/base/core/java/android/app/ContextImpl.java;l=2950

I ended up using the actual app context via android-activity. Interestingly, this returns /data/user/0/me.nikl.game/files and not /data/data/me.nikl.game/files (which also works though).

soc commented

I think it would make sense to generally use Android-level APIs in the implementation instead of trying to pretend that Android is just another Linux as dirs or std does ... ๐Ÿค”

I might have found something with env variables: cs.android.com/android/platform/superproject/+/refs/heads/master:frameworks/base/core/java/android/os/Environment.java;drc=a3bb1640c5a3422645b8493ee0bb00eab4266c32;l=98 The env variable ANDROID_DATA is set to /data on my device. It still might be an issue to hard code the /data/<identifier>/files in case we should be using /users/<n>/<identifier>/files instead. I haven't understood in what scenario the second path is chosen.

There seem to be multiple possible directories for a given application and I cannot see another way to get the intended one from a simple environment variable. See cs.android.com/android/platform/superproject/+/refs/heads/master:frameworks/base/core/java/android/app/ContextImpl.java;l=2950

iirc some android phones offer multi-user functionality and this is why they have this structure

I would recommend against implementing this in directories. It will require FFI calls to JNI, at a minimum, and will significantly increase the complexity of the library. Android is definitely not just another linux, certainly not in terms of userspace, and definitely doesn't implement the XDG Base Directories spec.

Another point against this is that the actual location that an app can write to on Android is an implementation detail. I'm pretty sure it's not guaranteed anywhere, so it can be altered by the device vendor. Android fragmentation is a massive problem and it's not a maintenance burden that directories should take on, IMHO.

Trying to bypass the Android APIs to get this implemented in directories is just asking for trouble. Google breaks things like this on each new version of Android, and it's painful enough if you are using the offical APIs!

I am also against adding complexity via FFIs.

It's probably better to have something that works on a number of devices than none.

What do you think about trying to detect write access heuristically?

/data/user/0/me.nikl.game/files and not /data/data/me.nikl.game/files (which also works though).

Wouldn't /data/data simply be a physical link or a symbolic link to /data/user/0/.... which makes it possible to simplify usage when a person connects in an authorized manner on a android? I haven't checked.

We could start from the existence of ANDROID_DATA:

  1. choose ANDROID_DATA/data or ANDROID_DATA/user as root by simply reading the existence of these folders.

2.1 if "user" loop over the <identifier> in descending order
2.1.1 Check the existence of a folder "me.nickl.game"/file/.directory-rs/ or try to create it? -> OK = path found
2.2 if not "data", Check the existence of a folder "me.nickl.game"/file/.directory-rs or create it? -> OK = path found

This location could then serve as the root for the lib?

What do you think ? Do you see any contraindication?

  1. I see ANDROID_STORAGE and EXTERNAL_STORAGE we can use too.

My guess is we can always write here : $ANDROID_STORAGE/self/primary for shared internal directory

  1. I confirm /data/data has the same inode number than /data/user/0 -> HARD LINK

My guess is we can always write here : $ANDROID_DATA/data/<package identifier>/files for private app directory.

I ask chat-gpt and mixtral 8x7B-32768 about that and AI confirm.

Heuristic detection is certainly usefulness.

Real question is now where to map home_dir() :-) Mixtral answer $ANDROID_DATA/data/<package identifier>/files.

$ANDROID_STORAGE/self/primary can be see like a mount from UNIX point of view.

I have done a small piece of code to review: here