Getting OS version with NDK in C
Asked Answered
A

6

11

I'm writing a C program which I want to execute on my Desktop running Linux and also on an Android device.
I have to make some Desktop specific things and some Android specific things.
My question is, is there a way to get the OS version in C so I can handle if the program is executed on the Desktop or on the Android device?

Abysmal answered 14/10, 2013 at 8:0 Comment(1)
if you just want to check if you are using android you could always use c/c++ preprocessor macros to check, #if defined(__unix__) && __ANDROID__ #define PLATFORM_ANDROID #endif if you want to check the API version for android this way use do #if defined(__unix__) && __ANDROID__ #include <android/api-level.h> #if defined(__ANDROID__) && __ANDROID_API__ == 0x00000001 #defined ANDROID_API_1 #endif #endifAlembic
C
12

In your native code, you could use property_get(), something like this:

#include <cutils/properties.h>

// ...

int myfunction() {
    char sdk_ver_str[PROPERTY_VALUE_MAX] = "0";
    property_get("ro.build.version.sdk", sdk_ver_str, "0");
    sdk_ver = atoi(sdk_ver_str);
    // ...   
}

On desktop, property_get() should return empty string.

Note that in starting from Android 6, <cutils/properties.h> is not available in SDK, use __system_property_get as follows:

#include <sys/system_properties.h>

// ...

int myfunction() {
    char sdk_ver_str[PROPERTY_VALUE_MAX];
    if (__system_property_get("ro.build.version.sdk", sdk_ver_str)) {
        sdk_ver = atoi(sdk_ver_str);
    } else {
        // Not running on Android or SDK version is not available
        // ...
    }
    // ...   
}

You can use adb shell getprop to see all possible Android properties. But, be aware that not all of them are supported by all devices.


UPDATE: If you don't need OS version, but simply want to tell if your C/C++ code is running on Android, very simple way to tell is to check if environment variable ANDROID_PROPERTY_WORKSPACE exists (on Android 7 or older), or if socket /dev/socket/property_service exists (Android 8 or newer), something like this:

include <stdlib.h>
include <unistd.h>
// ...

if (getenv("ANDROID_PROPERTY_WORKSPACE")) {
    // running under Android 7 or older
} else if (access("/dev/socket/property_service", F_OK) == 0) {
    // running under Android 8 or newer
} else {
    // running on desktop
}
Characteristically answered 14/10, 2013 at 8:16 Comment(6)
I couldn't find <cutils/properties.h> in my NDK, but using __system_property_get from <sys/system_properties.h> worked.Adar
@Adar please send this comment as an answerBotheration
property_get is from cutils, which is not part of the NDK: https://mcmap.net/q/1013313/-cutils-not-included-in-ndk I don't think cutils is meant for app development and the implementation in /system/lib/libcutils.so on your user's device could be incompatible to the <cutils/properties.h> you used at compile time.Nikolaus
@vulcanraven, updated with solution for recent Android versionsCharacteristically
what can I do if the getenv returns null?Coakley
@RitobrotoGanguly: unfortunately, since this commit ANDROID_PROPERTY_WORKSPACE is not present in Android 8 (Oreo) and later. it means you have to use __system_property_get() methodCharacteristically
A
13

property_get() did not work for me, instead I used __system_property_get().

#include <sys/system_properties.h>

void foo() {
    char osVersion[PROP_VALUE_MAX+1];
    int osVersionLength = __system_property_get("ro.build.version.release", osVersion);
}

ro.build.version.release is a string like "6.0". You can also get ro.build.version.sdk to get the sdk level, which is a string like "23".

Adar answered 20/4, 2016 at 0:41 Comment(1)
I think you don't need the +1 in the char array length because __system_property_get is "copying [the] value and a \0 terminator to the provided pointer. The total bytes copied will be no greater than PROP_VALUE_MAX." android.googlesource.com/platform/bionic/+/…Nikolaus
C
12

In your native code, you could use property_get(), something like this:

#include <cutils/properties.h>

// ...

int myfunction() {
    char sdk_ver_str[PROPERTY_VALUE_MAX] = "0";
    property_get("ro.build.version.sdk", sdk_ver_str, "0");
    sdk_ver = atoi(sdk_ver_str);
    // ...   
}

On desktop, property_get() should return empty string.

Note that in starting from Android 6, <cutils/properties.h> is not available in SDK, use __system_property_get as follows:

#include <sys/system_properties.h>

// ...

int myfunction() {
    char sdk_ver_str[PROPERTY_VALUE_MAX];
    if (__system_property_get("ro.build.version.sdk", sdk_ver_str)) {
        sdk_ver = atoi(sdk_ver_str);
    } else {
        // Not running on Android or SDK version is not available
        // ...
    }
    // ...   
}

You can use adb shell getprop to see all possible Android properties. But, be aware that not all of them are supported by all devices.


UPDATE: If you don't need OS version, but simply want to tell if your C/C++ code is running on Android, very simple way to tell is to check if environment variable ANDROID_PROPERTY_WORKSPACE exists (on Android 7 or older), or if socket /dev/socket/property_service exists (Android 8 or newer), something like this:

include <stdlib.h>
include <unistd.h>
// ...

if (getenv("ANDROID_PROPERTY_WORKSPACE")) {
    // running under Android 7 or older
} else if (access("/dev/socket/property_service", F_OK) == 0) {
    // running under Android 8 or newer
} else {
    // running on desktop
}
Characteristically answered 14/10, 2013 at 8:16 Comment(6)
I couldn't find <cutils/properties.h> in my NDK, but using __system_property_get from <sys/system_properties.h> worked.Adar
@Adar please send this comment as an answerBotheration
property_get is from cutils, which is not part of the NDK: https://mcmap.net/q/1013313/-cutils-not-included-in-ndk I don't think cutils is meant for app development and the implementation in /system/lib/libcutils.so on your user's device could be incompatible to the <cutils/properties.h> you used at compile time.Nikolaus
@vulcanraven, updated with solution for recent Android versionsCharacteristically
what can I do if the getenv returns null?Coakley
@RitobrotoGanguly: unfortunately, since this commit ANDROID_PROPERTY_WORKSPACE is not present in Android 8 (Oreo) and later. it means you have to use __system_property_get() methodCharacteristically
T
6

NDK provide direct api to get app target sdk version or api level

android_get_device_api_level
android_get_application_target_sdk_version

See the ndk official document.

Tomekatomes answered 30/11, 2020 at 9:14 Comment(1)
This should be at the top.Veda
S
5

If you use the java native interface, you can use the java function to get the sdk version number, which is less dependent on android version.

int api_version( struct android_app *app ) {

    JNIEnv* env;
    app->activity->vm->AttachCurrentThread( &env, NULL );

    // VERSION is a nested class within android.os.Build (hence "$" rather than "/")
   jclass versionClass = env->FindClass("android/os/Build$VERSION" );
   jfieldID sdkIntFieldID = env->GetStaticFieldID(versionClass, "SDK_INT", "I" );

   int sdkInt = env->GetStaticIntField(versionClass, sdkIntFieldID );
   app->activity->vm->DetachCurrentThread();
   return sdkInt;
}
Sledgehammer answered 27/7, 2015 at 18:4 Comment(3)
This will give exact same result as property_get("ro.build.version.sdk"), but is much more complicatedCharacteristically
At least in my development environment (nVidia AndroidWorks, Visual Studio 2013), property_get is not readily available as it is not part of the stock android ndk. I assume I could find the source for property_get and add it to my project. However, after 10 minutes into that project, I realized JNI would do nicely. I post my answer here not to say that people can't or shouldn't use your answer, but to give people more options.Sledgehammer
Thanks for sharing. Remember to also call env->DeleteLocalRef(versionClass)Mullock
N
4

How about using AConfiguration_getSdkVersion() API?

#include <android/configuration.h>
...
auto apilevel = AConfiguration_getSdkVersion(app->config);
LOGI("Device API Level %d", apilevel);
Nonperformance answered 28/4, 2016 at 3:35 Comment(3)
Where do you get the app variable from?Nikolaus
@SimonWarta I think you need to build native apps to access this android_app.Nakada
developer.android.com/ndk/reference/group/…Seismoscope
P
0
#if defined(__linux__)
// Linux-based OS

#if defined(__ANDROID__)
// Android OS
#else
// other Linux-based OS
#endif

#endif

See this for reference. The caveat is that any linux system sets __linux__, and Android sets that and __ANDROID__. For windows it's _WIN32 for most use cases.~

You can also use /path/to/your/ndk/compiler -dM -E - < /dev/null to see all the flags available to you.

Plesiosaur answered 11/9, 2023 at 17:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.