AndreMiras: Thanks for the bugfix attempt. Obviously unit tests also need to be updated.
I would say if we could narrow it down to only the check you're adding and removing the other change that introduced the bug, the code would be simpler. That's just a suggestion.
However we also need @olivier-boesch to test this method. I guess this environment variable should be always available when built with p4a (do we have other cases). Unless there's something special on his setup dropping some environment variables
inclement: I'd like to propose the tidied up method at https://github.com/kivy/kivy/pull/6853 - in particular it seems sensible to always allow an env var to override the detected platform, it can't hurt as a debug tool. We can also transition p4a to do this as well as setting the P4A_BOOTSTRAP variable, that would seem neater.

I made a PR just to demonstrate because I didn't want to do a big edit to @opacam's proposal, please feel free to go ahead with this one and close mine.
olivier-boesch: Hi everyone,

I will perform some tests later when I have time to but, making a quick verification, I've found a use case when the logic of environment cars doesn't work: if you are working with pydroid3. In this case, no env vars mentionned are set. See output below.

Maybe a mixed approach? First verify env vars and, if needed, when paths?

Output:
[INFO   ] [Logger      ] Record log in /storage/emulated/0/Android/data/ru.iiec.pydroid3/files/.kivy/logs/kivy_20-05-02_2.txt
[INFO   ] [Kivy        ] v1.11.0.dev0, git-8b6af30, 20190320
[INFO   ] [Python      ] v3.7.2 (default, Mar 20 2019, 15:02:54) 
[GCC 8.2.0]
environ({'PATH': '/data/user/0/ru.iiec.pydroid3/files:/data/user/0/ru.iiec.pydroid3/files/bin:/data/user/0/ru.iiec.pydroid3/files/aarch64-linux-android/bin:/busybox-virtual:/sbin:/system/sbin:/system/bin:/system/xbin:/vendor/bin:/vendor/xbin', 'DOWNLOAD_CACHE': '/data/cache', 'ANDROID_BOOTLOGO': '1', 'ANDROID_ROOT': '/system', 'ANDROID_ASSETS': '/system/app', 'ANDROID_DATA': '/data', 'ANDROID_STORAGE': '/storage', 'EXTERNAL_STORAGE': '/sdcard', 'ASEC_MOUNTPOINT': '/mnt/asec', 'BOOTCLASSPATH': '/system/framework/com.qualcomm.qti.camera.jar:/system/framework/QPerformance.jar:/system/framework/core-oj.jar:/system/framework/core-libart.jar:/system/framework/conscrypt.jar:/system/framework/okhttp.jar:/system/framework/bouncycastle.jar:/system/framework/apache-xml.jar:/system/framework/legacy-test.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/telephony-common.jar:/system/framework/voip-common.jar:/system/framework/ims-common.jar:/system/framework/org.apache.http.legacy.boot.jar:/system/framework/android.hidl.base-V1.0-java.jar:/system/framework/android.hidl.manager-V1.0-java.jar:/system/framework/tcmiface.jar:/system/framework/WfdCommon.jar:/system/framework/oem-services.jar:/system/framework/qcom.fmradio.jar:/system/framework/telephony-ext.jar', 'SYSTEMSERVERCLASSPATH': '/system/framework/services.jar:/system/framework/ethernet-service.jar:/system/framework/wifi-service.jar:/system/framework/com.android.location.provider.jar', 'ANDROID_SOCKET_zygote': '9', 'PKG_CONFIG_PATH': '/data/user/0/ru.iiec.pydroid3/files/aarch64-linux-android/lib/pkgconfig', 'SSL_CERT_FILE': '/data/user/0/ru.iiec.pydroid3/files/cert.pem', 'TERMINFO': '/data/user/0/ru.iiec.pydroid3/files/aarch64-linux-android/share/terminfo', 'LD_LIBRARY_PATH': '/data/user/0/ru.iiec.pydroid3/files/aarch64-linux-android/lib', 'TMPDIR': '/data/user/0/ru.iiec.pydroid3/cache', 'SHELL': '/data/user/0/ru.iiec.pydroid3/files/sh', 'CONFIG_SHELL': '/data/user/0/ru.iiec.pydroid3/files/sh', 'LIBRARY_PATH': '/data/user/0/ru.iiec.pydroid3/files/lib/gcc/aarch64-linux-android/8.2.0/', 'XDG_CACHE_HOME': '/data/user/0/ru.iiec.pydroid3/cache', 'APP_PACKAGE': '/data/app/ru.iiec.pydroid3-EdWP4V2iZJ6TydGHILDxKQ``/base.apk', 'LC_ALL': 'en_US.UTF-8', 'JOBLIB_MULTIPROCESSING': '0', 'KERAS_BACKEND': 'theano', 'PYDROID3_LICENSE': 'Accepted', 'PYDROID_RPC': '/data/user/0/ru.iiec.pydroid3/files/RPCServer.socket', 'PYDROID_PACKAGE': 'ru.iiec.pydroid3', 'BROWSER': 'mybrowser %s', 'ANDROID_PRIVATE': '/data/user/0/ru.iiec.pydroid3/files/aarch64-linux-android', 'ANDROID_ARGUMENT': '/storage/emulated/0/Android/data/ru.iiec.pydroid3/files', 'HOME': '/data/user/0/ru.iiec.pydroid3/app_HOME', 'PYDR_STDERROUT': '/data/user/0/ru.iiec.pydroid3/files/pydroid_stderrout_log', 'ANDROID_APP_PATH': '/storage/emulated/0/Android/data/ru.iiec.pydroid3/files', 'ANDROID_ORIGFNAME': '/data/user/0/ru.iiec.pydroid3/files/temp_iiec_codefile.py', 'ANDROID_ENTRYPOINT': '/data/user/0/ru.iiec.pydroid3/files/temp_iiec_codefile.py', 'PYTHONHOME': '/data/user/0/ru.iiec.pydroid3/files/aarch64-linux-android', 'PYTHONPATH': '/data/user/0/ru.iiec.pydroid3/files/aarch64-linux-android:/data/user/0/ru.iiec.pydroid3/files/aarch64-linux-android/lib', 'PYSDL2_DLL_PATH': '/data/user/0/ru.iiec.pydroid3/files/aarch64-linux-android/lib', 'PYTHON_NAME': 'python'})

inclement: In this case the `ANDROID_ARGUMENT` env var that was originally removed from kivy's check is present - which makes sense because pydroid3 is ensuring kivy will work.

We should definitely leave the ANDROID_ARGUMENT check in for backwards compatibility, with a comment about the fact that it used to be what we reliably used. @opacam could you add that back in as an alternative to P4A_BOOTSTRAP being present?

I'm not against adding other checks for being in an android environment, if necessary. Perhaps we should be using pyjnius to query the android api.
opacam: > We should definitely leave the ANDROID_ARGUMENT check in for backwards compatibility, with a comment about the fact that it used to be what we reliably used. @opacam could you add that back in as an alternative to P4A_BOOTSTRAP being present?

Yes, no problem
diff --git a/kivy/utils.py b/kivy/utils.py
index 628c30598..7afbde0e0 100644
--- a/kivy/utils.py
+++ b/kivy/utils.py
@@ -424,15 +424,17 @@ def format_bytes_to_human(size, precision=2):
 
 def _get_platform():
     # On Android sys.platform returns 'linux2', so prefer to check the
-    # existence of system specific commands and files
-    if (
-            path.exists('/default.prop')
-            and path.exists('/system/bin/logcat')
-            and path.exists('/system/xbin')
-    ):
+    # existence of environ variables set during Python initialization
+    kivy_build = environ.get('KIVY_BUILD', '')
+    if kivy_build in {'android', 'ios'}:
+        return environ['KIVY_BUILD']
+    elif 'P4A_BOOTSTRAP' in environ:
+        return 'android'
+    elif 'ANDROID_ARGUMENT' in environ:
+        # We used to use this method to detect android platform,
+        # leaving it here to be backwards compatible with `pydroid3`
+        # and similar tools outside kivy's ecosystem
         return 'android'
-    elif environ.get('KIVY_BUILD', '') == 'ios':
-        return 'ios'
     elif _sys_platform in ('win32', 'cygwin'):
         return 'win'
     elif _sys_platform == 'darwin':

Platform linux on some android devices
<!--
The issue tracker is a tool to address bugs.
Please use the Disord community or Stack Overflow for support questions,
more information at https://github.com/kivy/python-for-android#support

Before opening a new issue, make sure you do the following:
    * check that your issue isn't already filed: https://github.com/kivy/python-for-android/issues
    * prepare a short, runnable example that reproduces the issue
    * make sure to have `log_level = 2` in your `buildozer.spec`
    * reproduce the problem with the latest development version (`p4a.branch = master`)
    * double-check that the issue is indeed a bug and not a support request
    * please use backticks to format code or logs
-->

### Versions

* Kivy: master (2.0.0rc1)

### Description

Last week I had to rebuild a kivy app that was working in many android devices. I normally do it with buildozer docker image.
I was able to create the apk again and it works as expected ... in some devices! In other ones the app crashes during splash screen due to a PermissionError. 
After debugging with adb logcat I noticed kivy is not recognizing the platform correctly as it return 'linux' instead of 'android'.
This causes that [ANDROID_APP_PATH is not used](https://github.com/kivy/kivy/blob/b6eddbb2fcf97a21b7f0c4cfbf0d8ccdb74fb3ec/kivy/__init__.py#L339) and it tries to write on /data/ path.

I'm using kivy==master on buildozer.spec.

### Logs

```
04-27 14:54:56.946  7788  7807 I python  : Android kivy bootstrap done. name is main
04-27 14:54:56.946  7788  7807 I python  : AND: Ran string
04-27 14:54:56.946  7788  7807 I python  : Run user program, change dir and execute entrypoint
04-27 14:54:57.303  7788  7807 I python  :  Traceback (most recent call last):
04-27 14:54:57.303  7788  7807 I python  :    File "/home/user/hostcwd/.buildozer/android/app/main.py", line 10, in <module>
04-27 14:54:57.304  7788  7807 I python  :    File "/home/user/hostcwd/.buildozer/android/app/app.py", line 4, in <module>
04-27 14:54:57.305  7788  7807 I python  :    File "/home/use
r/hostcwd/.buildozer/android/platform/build-armeabi-v7a/build/python-installs/myapp/kivy/__init__.py", line 351, in <module>
04-27 14:54:57.306  7788  7807 I python  :  PermissionError: [Errno 13] Permission denied: '/data/.kivy'
04-27 14:54:57.306  7788  7807 I python  : Python for android ended.
```

diff --git a/kivy/tests/test_utils.py b/kivy/tests/test_utils.py
index 0e5ad781c..afe18c8c7 100644
--- a/kivy/tests/test_utils.py
+++ b/kivy/tests/test_utils.py
@@ -191,21 +191,19 @@ class UtilsTest(unittest.TestCase):
         assert first == second
 
     def test_Platform_android(self):
-        # modified os.path.exists function
-        # for test purpose
-        def modified_path_exists(p):
-            valid_paths = ['/default.prop',
-                           '/system/bin/logcat',
-                           '/system/xbin']
-            if p in valid_paths:
-                return True
-            return False
-
-        with patch(target='os.path.exists',
-                   side_effect=modified_path_exists):
-            pf = _get_platform()
-            self.assertTrue(pf == 'android')
-        self.assertFalse(os.path.exists('/default.prop'))
+        with patch.dict('os.environ', {'KIVY_BUILD': 'android'}):
+            self.assertEqual(_get_platform(), 'android')
+        self.assertNotIn('KIVY_BUILD', os.environ)
+
+    def test_Platform_android_with_p4a(self):
+        with patch.dict('os.environ', {'P4A_BOOTSTRAP': 'sdl2'}):
+            self.assertEqual(_get_platform(), 'android')
+        self.assertNotIn('P4A_BOOTSTRAP', os.environ)
+
+    def test_Platform_android_with_android_argument(self):
+        with patch.dict('os.environ', {'ANDROID_ARGUMENT': ''}):
+            self.assertEqual(_get_platform(), 'android')
+        self.assertNotIn('ANDROID_ARGUMENT', os.environ)
 
     def test_Platform_ios(self):
         with patch.dict('os.environ', {'KIVY_BUILD': 'ios'}):

pip install -e .[dev,full]
parse_log_pytest
pytest
pytest pytest-cov pytest-xdist pytest-mock pytest-asyncio
apt-get update apt-get install -y libsdl2-dev libsdl2-ttf-dev libsdl2-image-dev libsdl2-mixer-dev libgstreamer1.0-dev gstreamer1.0-alsa gstreamer1.0-plugins-base libsmpeg-dev libswscale-dev libavformat-dev libavcodec-dev libjpeg-dev libtiff5-dev libx11-dev libmtdev-dev build-essential libgl1-mesa-dev libgles2-mesa-dev xvfb pulseaudio xsel
3.9
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
actdiag==3.0.0
alabaster==0.7.16
altgraph==0.17.4
babel==2.17.0
blockdiag==3.0.0
certifi==2025.1.31
charset-normalizer==3.4.1
coverage==7.8.0
docutils==0.21.2
exceptiongroup @ file:///croot/exceptiongroup_1706031385326/work
execnet==2.1.1
flake8==7.2.0
funcparserlib==2.0.0a0
idna==3.10
imagesize==1.4.1
importlib_metadata==8.6.1
iniconfig @ file:///home/linux1/recipes/ci/iniconfig_1610983019677/work
Jinja2==3.1.6
-e git+https://github.com/kivy/kivy.git@b6eddbb2fcf97a21b7f0c4cfbf0d8ccdb74fb3ec#egg=Kivy
Kivy-Garden==0.1.5
MarkupSafe==3.0.2
mccabe==0.7.0
nwdiag==3.0.0
packaging @ file:///croot/packaging_1734472117206/work
pillow==11.1.0
pluggy @ file:///croot/pluggy_1733169602837/work
pycodestyle==2.13.0
pyflakes==3.3.2
Pygments==2.19.1
pyinstaller==6.12.0
pyinstaller-hooks-contrib==2025.2
pytest @ file:///croot/pytest_1738938843180/work
pytest-asyncio==0.26.0
pytest-cov==6.0.0
pytest-mock==3.14.0
pytest-timeout==2.3.1
pytest-xdist==3.6.1
requests==2.32.3
seqdiag==3.0.0
snowballstemmer==2.2.0
Sphinx==7.4.7
sphinxcontrib-actdiag==3.0.0
sphinxcontrib-applehelp==2.0.0
sphinxcontrib-blockdiag==3.0.0
sphinxcontrib-devhelp==2.0.0
sphinxcontrib-htmlhelp==2.1.0
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-nwdiag==2.0.0
sphinxcontrib-qthelp==2.0.0
sphinxcontrib-seqdiag==3.0.0
sphinxcontrib-serializinghtml==2.0.0
tomli @ file:///opt/conda/conda-bld/tomli_1657175507142/work
typing_extensions==4.13.0
urllib3==2.3.0
webcolors==24.11.1
zipp==3.21.0

name: kivy
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - exceptiongroup=1.2.0=py39h06a4308_0
  - iniconfig=1.1.1=pyhd3eb1b0_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - packaging=24.2=py39h06a4308_0
  - pip=25.0=py39h06a4308_0
  - pluggy=1.5.0=py39h06a4308_0
  - pytest=8.3.4=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tomli=2.0.1=py39h06a4308_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - actdiag==3.0.0
      - alabaster==0.7.16
      - altgraph==0.17.4
      - babel==2.17.0
      - blockdiag==3.0.0
      - certifi==2025.1.31
      - charset-normalizer==3.4.1
      - coverage==7.8.0
      - docutils==0.21.2
      - execnet==2.1.1
      - flake8==7.2.0
      - funcparserlib==2.0.0a0
      - idna==3.10
      - imagesize==1.4.1
      - importlib-metadata==8.6.1
      - jinja2==3.1.6
      - kivy==2.0.0rc2
      - kivy-garden==0.1.5
      - markupsafe==3.0.2
      - mccabe==0.7.0
      - nwdiag==3.0.0
      - pillow==11.1.0
      - pycodestyle==2.13.0
      - pyflakes==3.3.2
      - pygments==2.19.1
      - pyinstaller==6.12.0
      - pyinstaller-hooks-contrib==2025.2
      - pytest-asyncio==0.26.0
      - pytest-cov==6.0.0
      - pytest-mock==3.14.0
      - pytest-timeout==2.3.1
      - pytest-xdist==3.6.1
      - requests==2.32.3
      - seqdiag==3.0.0
      - snowballstemmer==2.2.0
      - sphinx==7.4.7
      - sphinxcontrib-actdiag==3.0.0
      - sphinxcontrib-applehelp==2.0.0
      - sphinxcontrib-blockdiag==3.0.0
      - sphinxcontrib-devhelp==2.0.0
      - sphinxcontrib-htmlhelp==2.1.0
      - sphinxcontrib-jsmath==1.0.1
      - sphinxcontrib-nwdiag==2.0.0
      - sphinxcontrib-qthelp==2.0.0
      - sphinxcontrib-seqdiag==3.0.0
      - sphinxcontrib-serializinghtml==2.0.0
      - typing-extensions==4.13.0
      - urllib3==2.3.0
      - webcolors==24.11.1
      - zipp==3.21.0
prefix: /opt/conda/envs/kivy

kivy/tests/test_utils.py::UtilsTest::test_Platform_android kivy/tests/test_utils.py::UtilsTest::test_Platform_android_with_android_argument kivy/tests/test_utils.py::UtilsTest::test_Platform_android_with_p4a
kivy/tests/test_utils.py::UtilsTest::test_Platform_cygwin kivy/tests/test_utils.py::UtilsTest::test_Platform_darwin kivy/tests/test_utils.py::UtilsTest::test_Platform_freebsd kivy/tests/test_utils.py::UtilsTest::test_Platform_ios kivy/tests/test_utils.py::UtilsTest::test_Platform_linux2 kivy/tests/test_utils.py::UtilsTest::test_Platform_unknown kivy/tests/test_utils.py::UtilsTest::test_Platform_win32 kivy/tests/test_utils.py::UtilsTest::test_QueryDict kivy/tests/test_utils.py::UtilsTest::test_SafeList_clear kivy/tests/test_utils.py::UtilsTest::test_SafeList_iterate kivy/tests/test_utils.py::UtilsTest::test_SafeList_iterate_reverse kivy/tests/test_utils.py::UtilsTest::test_boundary kivy/tests/test_utils.py::UtilsTest::test_deprecated kivy/tests/test_utils.py::UtilsTest::test_difference kivy/tests/test_utils.py::UtilsTest::test_escape_markup kivy/tests/test_utils.py::UtilsTest::test_format_bytes_to_human kivy/tests/test_utils.py::UtilsTest::test_get_color_from_hex_alpha kivy/tests/test_utils.py::UtilsTest::test_get_color_from_hex_noalpha kivy/tests/test_utils.py::UtilsTest::test_get_hex_from_color_alpha kivy/tests/test_utils.py::UtilsTest::test_get_hex_from_color_noalpha kivy/tests/test_utils.py::UtilsTest::test_get_random_color_fixed_alpha kivy/tests/test_utils.py::UtilsTest::test_get_random_color_random_alpha kivy/tests/test_utils.py::UtilsTest::test_interpolate_multi kivy/tests/test_utils.py::UtilsTest::test_interpolate_solo kivy/tests/test_utils.py::UtilsTest::test_intersection kivy/tests/test_utils.py::UtilsTest::test_is_color_transparent kivy/tests/test_utils.py::UtilsTest::test_reify kivy/tests/test_utils.py::UtilsTest::test_strtotuple
kivy/utils.py
kivy/utils.py