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

No project directory on Android #83

Open
NiklasEi opened this issue Jun 29, 2023 · 14 comments
Open

No project directory on Android #83

NiklasEi opened this issue Jun 29, 2023 · 14 comments

Comments

@NiklasEi
Copy link

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
Copy link
Collaborator

soc commented Jun 30, 2023

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

@NiklasEi
Copy link
Author

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.

@NiklasEi
Copy link
Author

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

@soc
Copy link
Collaborator

soc commented Jun 30, 2023

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?

@NiklasEi
Copy link
Author

NiklasEi commented Jun 30, 2023

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 🥳

@NiklasEi
Copy link
Author

NiklasEi commented Jun 30, 2023

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

@NiklasEi
Copy link
Author

NiklasEi commented Jul 2, 2023

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
Copy link
Collaborator

soc commented Jul 3, 2023

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

@Hellzbellz123
Copy link

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

@tirithen
Copy link

tirithen commented Feb 5, 2024

@NiklasEi here you can see how the tauri project looks up directories on Android https://github.com/tauri-apps/tauri/blob/48b1fd74b1df5c3628d00aaae9371dd094466fe5/core/tauri/src/path/android.rs

@grodin
Copy link

grodin commented Feb 6, 2024

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!

@sbechet
Copy link

sbechet commented Apr 17, 2024

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?

@sbechet
Copy link

sbechet commented Apr 17, 2024

  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.

@sbechet
Copy link

sbechet commented Apr 17, 2024

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants