Android -- get MEID from JNI - android

I'm working in Android, writing some JNI code, and I'm looking for a way to query the Mobile Equipment Identifier (MEID) from the device.
http://en.wikipedia.org/wiki/Mobile_equipment_identifier
I'm trying to write C or C++ code that can run by itself on an Android device, so I don't think I can use Java (i.e., get MEID from TelephonyManager).
A search of StackOverflow finds: Is there an android shell or adb command that I could use to get a device's IMEI/MEID?
Okay great, dumpsys iphonesubinfo can get the info I need. And it works!
I couldn't find the source for dumpsys except as part of the source for Android. So I downloaded that... my hard disk filled up before the download finished, but I did get the source code to dumpsys. It is a surprisingly short C++ file. All it does is query Android's IBinder interface.
So, my questions:
0) Is there any way I can write a query against IBinder using just the stuff in the NDK? The include files used by dumpsys.cpp are not in the NDK, and grep in the NDK directory didn't find IBinder in any include files or code samples, so my guess is "no" (but I would like to be wrong).
1) Is there any other good way to get the MEID?
I'm seriously thinking I should just use system("dumpsys iphonesubinfo > /tmp/myprogname_dumpsys.tmp" and then open the resulting file and parse it. That should work, but I would hardly call it elegant... and I'm not sure if dumpsys is available on every Android device or not.
EDIT: The idea of using system() to run dumpsys will not work, because dumpsys needs android.permission.DUMP and Android no longer allows non-system apps to have that permission.
Dumpsys permission denial in java

I believe Dalvik implements all the same JNI interfaces that the JVM does, so while it's a bit fiddly, it's perfectly possible to make calls from native code through JNI to arbitrary Java classes and methods.
/* assuming you already have */
JNIEnv *env;
jobject context;
/* then call (with error-checking) */
jclass cls = (*env)->FindClass(env, "android/context/Context");
jmethodId mid = (*env)->GetMethodID(env, context_cls, "getSystemService",
"(Ljava/lang/String;)Ljava/lang/Object;");
jfieldID fid = (*env)->GetStaticFieldID(env, cls, "TELEPHONY_SERVICE",
"Ljava/lang/String;");
jstring str = (*env)->GetStaticObjectField(env, cls, fid);
jobject telephony = (*env)->CallObjectMethod(env, context, mid, str);
cls = (*env)->FindClass(env, "android/telephony/TelephonyManager");
mid =(*env)->GetMethodID(env, cls, "getDeviceId", "()Ljava/lang/String;");
str = (*env)->CallObjectMethod(env, telephony, mid);
jsize len = (*env)->GetStringUTFLength(env, str);
char* deviceId = calloc(len + 1, 1);
(*env)->GetStringUTFRegion(env, str, 0, len, deviceId);
(*env)->DeleteLocalRef(env, str);
/* to get a string in deviceId */

Retrieve the MEID on the Java side, then pass into your JNI function as a jstring parameter. It'll be cleaner than calling back to Java from C.
As to how to retrieve that, see Abhilasha's answer.

Related

JNI called with jstring parameters, but one of them becomes NULL

I'm calling native function from Java:
String pathTemp = Environment.getExternalStorageDirectory().getAbsolutePath()+Const.PATH_TEMP
String pathFiles = Environment.getExternalStorageDirectory().getAbsolutePath()+Const.PATH_FILES
engine.init(someInt, pathTemp, pathFiles);
And I have the native function:
extern "C" JNIEXPORT void Java_com_engine_init(JNIEnv *env, jobject __unused obj, jint someInt, jstring pathTemp, jstring pathFiles) {
const char *pathTemp_ = env->GetStringUTFChars(pathTemp, JNI_FALSE);
const char *pathFiles_ = env->GetStringUTFChars(pathFiles, JNI_FALSE); // <-- CRASH
// More init code
env->ReleaseStringUTFChars(pathTemp, pathTemp_);
env->ReleaseStringUTFChars(pathRecording, pathRecording_);
}
The problem: pathTemp is arriving good, but pathFiles==NULL in native function.
Rechecked, and confirmed - both strings are non NULL in java.
One more strange thing - The problem is on LG-G3 (android 6.0).
On Meizu PRO 5 (android 7.0) - everything works good - both strings are intact.
What is this JNI magic? Any clue?
I had the same problem as this and while I can't guarantee this is the same, I found a better solution than re-ordering the parameters.
tldr; Ensure the code works for 32bit and 64bit platforms as pointers have different sizes. I was running 32bit native code and passed nullptr as a parameter and java expected a long which resulted in all parameters after the nullptr to be invalid.
(JJLjava/lang/String;Z)V -> (final long pCallback, final long pUserPointer, final String id, final boolean b)
pCallback was always set to a valid value (pointer casted to jlong in c++) and pUserPointer was always nullptr. I found this answer and tried switching the order around and it 'just worked' but I knew that fix was never going to be approved.
After looking at the JNI documentation on the Android website again (https://developer.android.com/training/articles/perf-jni) I took note of the "64-bit considerations" section and took a stab at my assumption of the data size. This feature was developed with a 64bit device (Pixel 3) but issues had been reported on a 32bit device (Amazon Fire Phone) so nullptr would be 32bit but the java function still expected a long (64bit).
In my situation the offending parameter was always unused so I could safely remove it and everything "just worked" (including some other parameters which were broken).
An alternative would be to have a define/function/macro for JniLongNullptr which is just 0 casted to jlong.
Not an answer, but workaround. Moved the strings (in parameters) to be before int parameter. Now it's working. I have no idea why is this.

Calling Android debug method from C++

I have spent a ridiculous amount of time trying to figure this out and I am at an absolute loss.
I am working with the JUCE library and have modified one of their sample projects. My goal is to have a very simple Android app that is written in C++ and then ported to Android. I need a function in C++ that I can call that will then call a function on the Android side that will return my heap size and other characteristics to my C++ code so that I can manage memory there.
If anyone has a simple solution that would be amazing. Right now my current snag is this:
char const buf[] = "From JNI";
jstring jstr = env->NewStringUTF(buf);
jclass clazz = env->FindClass("android/os/Debug");
But I keep getting an error saying that 'NewStringUTF' is not a _JNIEnv member... but if I right click on the method and jump to the definition, I see it in my jni.h file... any suggestions? I'm working in Xcode by the way...
Is it plain C, not C++? Perhaps your file has a .c extension.
If it's plain C it should be
JNIEnv* env;
JNI_CreateJavaVM(&jvm, (void **)&env, &args);
(*env)->NewStringUTF(env, buf);

JNIEnv for get ANDROID_ID from native code

I need to get Android unique device ID in my native library. As far as i know, it can be done with Java API and i need to use JNI. I read this, there is similar problem, but different ID is accessed. But this solution needs reference to JNIEnv for getting Java objects/methods. When JNI method called from Java, this is not problem, JNIEnv will be passed from Java. But how i can get JNIEnv for "total" native code?
The entrypoint of your native activity receives a struct android_app* as its argument. android_app contains an ANativeActivity* named activity, which in turn contains a JNIEnv* named env.
To be able to call Android Java API methods from your native code you'll have to attach the current thread to the VM first, i.e.:
JNIEnv *env = state->activity->env;
JavaVM *vm = state->activity->vm;
(*vm)->AttachCurrentThread(vm, &env, NULL);
(where state is the struct android_app*)
I found that JNIEnv can be accessed with JavaVM, which can be created with JNI invocation API. By default in Android NDK this functions not exported to user(from platforms/android-19/arch-arm/usr/include/jni.h):
/*
* VM initialization functions.
*
* Note these are the only symbols exported for JNI by the VM.
*/
#if 0 /* In practice, these are not exported by the NDK so don't declare them */
jint JNI_GetDefaultJavaVMInitArgs(void*);
jint JNI_CreateJavaVM(JavaVM**, JNIEnv**, void*);
jint JNI_GetCreatedJavaVMs(JavaVM**, jsize, jsize*);
#endif
But this functions presented in /system/lib/libdvm.so on my device. After including function definition for JNI_CreateJavaVM in my code and linking to libdvm, copied from device, i got access to creation of JavaVM in Android. This is not recommended, of course, but, if you want it and your device libdvm supports this, you can do it.

Execute Android application from native c code

Continue my previous question, I succeeded to execute a process from an Android application. Now I can see two process like I wanted, they both up and running. Now I need to execute an Android application from the native C code.
Found similar questions (1, 2), but the following solutions did NOT work for me.
1. execl("/system/bin/sh", "sh", "-c", "am start -a android.intent.action.MAIN -n com.android.browser/.BrowserActivity", (char *)NULL);
2. execl("/system/bin/am", "start", "-a", "android.intent.action.MAIN",
"-n", "com.android.settings/.Settings", (char *)NULL);
None of the lines above didn't executed anything.
Even executing execl command with fork as follows did NOT help.
if (!fork()) {
execl...
}
Can you please give me some kind of a clue?
Thanks.
UPDATE: I've manage to print the stdout to the Android log, I'm getting errno
"Exec format error"
message from the execl method. Anybody have an idea how I can resolve this?
Maybe you can write this from the Android/ Java / VM scope and call it from native code using NDK & JNI (Java Native Interface) ?
Example :
From your app:
class MyActivity extends Activity {
public native int nativeMethodName();
public void launchSomeAppMethod() {
// launch some app
Intent LaunchIntent = getPackageManager().getLaunchIntentForPackage("com.package.someapp");
startActivity(LaunchIntent);
}
}
Native :
jint Java_com_yourpackage_appname_MyActivity_nativeMethodName(JNIEnv* env, jobject thiz) {
//....
// do your native work here
// ...
// call your obj instance that can launch another app
jclass cls = (*env)->GetObjectClass(env, thiz);
jmethodID method = (*env)->GetMethodID(env, cls, "launchSomeAppMethod", "()V");
(*env)->CallVoidMethod(env, thiz, method);
}
Hope it helps dude.
The error printed smells like permission problem.
Are you trying to run the application from an SD card? SD Cards by default are mounted without execute permission, you need to remount it.

Obtaining the name of an Android APK using C++ and the NativeActivity class

I'm writing an Android app using the NDK and NativeActivity. My app depends on a few bits of third party code that are shipped as assets. Currently I'm working on trying to extract those assets while keeping the folder structure intact.
I've tried using the AssetManager, but to keep the folder structure intact it seemed like there would a huge amount of code involved, for a simple task such as what I've mentioned. I've since switched focus to try to implement treating the APK as a ZIP file and extract its contents that way. But that requires I find the exact path to the APK.
In a normal Android app one would use getPackageCodePath, but this is an abstract method attached to the Context class. My question is how do I obtain the exact path to the APK when not using a normal Activity?
Also I tried calling getPackageCodePath via JNI, but that crashed the app on account of not being able to find the method.
EDIT:
Is this even possible?
I was actually able to call getPackageCodePath via JNI and get it to work. The following code put at the top of android_main in the native-activity sample in NDK r7 logs the correct path and doesn't crash:
void android_main(struct android_app* state) {
struct engine engine;
ANativeActivity* activity = state->activity;
JNIEnv* env = activity->env;
jclass clazz = (*env)->GetObjectClass(env, activity->clazz);
jmethodID methodID = (*env)->GetMethodID(env, clazz, "getPackageCodePath", "()Ljava/lang/String;");
jobject result = (*env)->CallObjectMethod(env, activity->clazz, methodID);
const char* str;
jboolean isCopy;
str = (*env)->GetStringUTFChars(env, (jstring)result, &isCopy);
LOGI("Looked up package code path: %s", str);
...
}
I feel like this might not be a great solution, though. There are two things that worry me:
Thread safety - there's an ugly warning about only using the env member of ANativeActivity in the main Java thread, and if I understand things correctly, this code is going to get run in the native activity's thread.
ANativeActivity's clazz member appears to be misnamed and is actually the instance of the Java NativeActivity instead of the class object. Otherwise this code wouldn't work. I really hate relying on something that is obviously misnamed like this.
Aside from that, it works, and I'm actually about to use it myself to try to extract the assets out of the .apk using libzip and into the data directory.
Since I just had to search for exactly how to do the attach/detach calls I'll paste the updated version here.
The following seems to get the right location without crashing (after minimal testing)
ANativeActivity* activity = state->activity;
JNIEnv* env=0;
(*activity->vm)->AttachCurrentThread(activity->vm, &env, 0);
jclass clazz = (*env)->GetObjectClass(env, activity->clazz);
jmethodID methodID = (*env)->GetMethodID(env, clazz, "getPackageCodePath", "()Ljava/lang/String;");
jobject result = (*env)->CallObjectMethod(env, activity->clazz, methodID);
const char* str;
jboolean isCopy;
str = (*env)->GetStringUTFChars(env, (jstring)result, &isCopy);
LOGI("Looked up package code path: %s", str);
(*activity->vm)->DetachCurrentThread(activity->vm);
Had to modify it to this in the year 2014.
ANativeActivity* activity = state->activity;
JNIEnv* env=0;
activity->vm->AttachCurrentThread(&env, NULL);
jclass clazz = env->GetObjectClass(activity->clazz);
jmethodID methodID = env->GetMethodID(clazz, "getPackageCodePath", "()Ljava/lang/String;");
jobject result = env->CallObjectMethod(activity->clazz, methodID);
jboolean isCopy;
std::string res = env->GetStringUTFChars((jstring)result, &isCopy);
LOG_DEBUG("Looked up package code path: %s", res.c_str());
activity->vm->DetachCurrentThread();
Did you try to read /proc/self/cmdline from your application?
You should be able to open it as a normal (as far as proc files are normal :-) so you can read from the file until EOF, but not seek) c FILE and read from it.
As an example for the phone app, I can see from ps in android that the name of the applications is the expected app name:
# ps | grep phone
radio 1588 839 1467420 103740 SyS_epoll_ 7f7de374ac S com.android.phone
And checking the cmdline for that pid returns a good app name:
# cat /proc/1588/cmdline
com.android.phone
Call getPackageCodePath() in Java and pass jstring to your C++ app via native method

Categories

Resources