| 540 | "AndroidVer", "release api_level manufacturer model device is_emulator") |
| 541 | |
| 542 | def android_ver(release="", api_level=0, manufacturer="", model="", device="", |
| 543 | is_emulator=False): |
| 544 | if sys.platform == "android": |
| 545 | try: |
| 546 | from ctypes import CDLL, c_char_p, create_string_buffer |
| 547 | except ImportError: |
| 548 | pass |
| 549 | else: |
| 550 | # An NDK developer confirmed that this is an officially-supported |
| 551 | # API (https://stackoverflow.com/a/28416743). Use `getattr` to avoid |
| 552 | # private name mangling. |
| 553 | system_property_get = getattr(CDLL("libc.so"), "__system_property_get") |
| 554 | system_property_get.argtypes = (c_char_p, c_char_p) |
| 555 | |
| 556 | def getprop(name, default): |
| 557 | # https://android.googlesource.com/platform/bionic/+/refs/tags/android-5.0.0_r1/libc/include/sys/system_properties.h#39 |
| 558 | PROP_VALUE_MAX = 92 |
| 559 | buffer = create_string_buffer(PROP_VALUE_MAX) |
| 560 | length = system_property_get(name.encode("UTF-8"), buffer) |
| 561 | if length == 0: |
| 562 | # This API doesn’t distinguish between an empty property and |
| 563 | # a missing one. |
| 564 | return default |
| 565 | else: |
| 566 | return buffer.value.decode("UTF-8", "backslashreplace") |
| 567 | |
| 568 | release = getprop("ro.build.version.release", release) |
| 569 | api_level = int(getprop("ro.build.version.sdk", api_level)) |
| 570 | manufacturer = getprop("ro.product.manufacturer", manufacturer) |
| 571 | model = getprop("ro.product.model", model) |
| 572 | device = getprop("ro.product.device", device) |
| 573 | is_emulator = getprop("ro.kernel.qemu", "0") == "1" |
| 574 | |
| 575 | return AndroidVer( |
| 576 | release, api_level, manufacturer, model, device, is_emulator) |
| 577 | |
| 578 | |
| 579 | ### System name aliasing |