Sending an Intent from C++ via JNI - android

I am trying to make an explicit intent call (intent to a specific pkg and class) from C++ via JNI. Everything is fine until the last line where I am actually trying to send the intent:
env->CallVoidMethod(obj, startActivity, intentObject);
I dont get an android error, it is just a full dump/stack trace...which does not give me any helpful info.
Here is the C++ code making the call to start an intent:
JNIEXPORT void JNICALL Java_com_testpkg_test(JNIEnv *java_env, jobject obj) {
jvm->AttachCurrentThread(&java_env, 0);
jclass activityClass = java_env->GetObjectClass(obj);
jmethodID appGetContextId = java_env->GetMethodID(activityClass, "getApplicationContext", "()Landroid/content/Context;");
jobject appContext = java_env->CallObjectMethod(obj, appGetContextId);
//Get an instance of Intent
jclass intentClass = java_env->FindClass("android/content/Intent");
jmethodID newIntent = java_env->GetMethodID(intentClass, "<init>", "()V");
jobject intentObject = java_env->NewObject(intentClass, newIntent);
java_env->CallVoidMethod(intentObject, newIntent);
//Get an instance of the ComponentName class
jclass componentClass = java_env->FindClass("android/content/ComponentName");
jmethodID componentMID = java_env->GetMethodID(componentClass, "<init>", "(Ljava/lang/String;Ljava/lang/String;)V");
jstring pkgName =java_env->NewStringUTF("com.testpkg");
jstring clsName =java_env->NewStringUTF("com.testpkg.test");
jobject componentObj = java_env->NewObject(componentClass, componentMID, pkgName, clsName);
java_env->CallVoidMethod(componentObj, componentMID, pkgName, clsName);
//Calling intent.setComponentName passing in pkg+class name
jmethodID setComponentName = java_env->GetMethodID(intentClass, "setComponent","(Landroid/content/ComponentName;)Landroid/content/Intent;");
java_env->CallObjectMethod(intentObject, setComponentName, componentObj);
//Call getapplicationcontext().startActivity(intent)
jmethodID startActivity = java_env->GetMethodID(activityClass, "startActivity", "(Landroid/content/Intent;)V");
env->CallVoidMethod(obj, startActivity, intentObject);
}

The comments I posted still apply, but here's a problem- don't call java_env->CallVoidMethod(intentObject, newIntent). The NewObject call does it for you. You do this twice, its likely to be screwing up Java's memory management.

Related

Android (ndk) multicast lock is acquired but can't receive UDP broadcast packets

I created and acquired multicast, wifi and wake locks and also set the SO_BROADCAST socket option but still can't receive UDP broadcast packets on android devices.
Project is written in C and uses JNI for creating locks.
void android_main(struct android_app* app) {
JavaVM* vm = app->activity->vm;
JNIEnv* env = app->activity->env;
(*vm)->AttachCurrentThread(vm, &env, NULL);
ANativeActivity* activity = app->activity;
jmethodID jtmID;
jclass jNativeClass = (*env)->GetObjectClass(env, activity->clazz);
jtmID = (*env)->GetMethodID(env, jNativeClass, "getApplication", "()Landroid/app/Application;");
jobject jNativeApplication = (jobject)(*env)->CallObjectMethod(env, activity->clazz, jtmID);
jtmID = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, jNativeApplication), "getApplicationContext", "()Landroid/content/Context;");
jobject jNativeContext = (jobject)(*env)->CallObjectMethod(env, jNativeApplication, jtmID);
jfieldID jNativeWIFI_SERVICE_fid = (*env)->GetStaticFieldID(env, (*env)->GetObjectClass(env, jNativeContext), "WIFI_SERVICE", "Ljava/lang/String;");
jstring jNativeSFID_jstr = (jstring)(*env)->GetStaticObjectField(env, (*env)->FindClass(env, "android/content/Context"), jNativeWIFI_SERVICE_fid);
jstring wifiLockjStr = (*env)->NewStringUTF(env, "PROJECT");
jtmID = (*env)->GetMethodID(env, (*env)->FindClass(env, "android/content/Context"), "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;");
jobject jSystemService = (*env)->CallObjectMethod(env, jNativeContext, jtmID, jNativeSFID_jstr);
jclass jWMClass = (*env)->FindClass(env, "android/net/wifi/WifiManager");
jclass jWMMLClass = (*env)->FindClass(env, "android/net/wifi/WifiManager$MulticastLock");
jtmID = (*env)->GetMethodID(env, jWMClass, "createMulticastLock", "(Ljava/lang/String;)Landroid/net/wifi/WifiManager$MulticastLock;");
jobject jMCObj = (*env)->CallObjectMethod(env, jSystemService, jtmID, wifiLockjStr);
jtmID = (*env)->GetMethodID(env, jWMMLClass, "setReferenceCounted", "(Z)V");
(*env)->CallVoidMethod(env, jMCObj, jtmID, 0);
jtmID = (*env)->GetMethodID(env, jWMMLClass, "acquire", "()V");
(*env)->CallVoidMethod(env, jMCObj, jtmID);
jtmID = (*env)->GetMethodID(env, jWMMLClass, "isHeld", "()Z");
jboolean isheld = (*env)->CallBooleanMethod(env, jMCObj, jtmID);
if (isheld) {
printf("MulticastLock acquired\n");
}
else {
printf("MulticastLock is not acquired\n");
}
... (Create and set socket then start listening)
}
isheld value is true but multicast lock doesn't seem to work. After this code block udp socket is created for broadcast and socket option SO_BROADCAST is set. Socket part is cross platform and can receive broadcast messages on windows,linux,etc. but can not on android.
Make sure that you are requesting the following two permissions in your Android manifest:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
I had the same issue, and adding them fixed it for me.

Start new Activity from JNI

I would like use this code from JNI
Intent intent = new Intent(this, TestActivity.class);
startActivity(intent);
So far, i wrote the next code but i'm getting error from the constructor with params i guess ?
jclass intentClass = env->FindClass("android/content/Intent");
jstring actionString =env->NewStringUTF("com.test.package.TestActivity");
jmethodID newIntent = env->GetMethodID(intentClass, "<init>", "(Landroid/content/Context;Ljava/lang/String;)Landroid/content/Intent");
jobject intent = env->NewObject(intentClass,newIntent,context,actionString);
jclass activityClass = env->FindClass("android/app/Activity");
jmethodID startActivity = env->GetMethodID(activityClass,"startActivity", "(Landroid/content/Intent;)V");
env->CallVoidMethod( intent, startActivity);
The error:
JNI DETECTED ERROR IN APPLICATION: JNI NewObjectV called with pending
exception java.lang.NoSuchMethodError: no non-static method
"Landroid/content/Intent;.(Landroid/content/Context;Ljava/lang/String;)Landroid/content/Intent"
The context and actionString params are OK and used somewhere else in code, so could you please help me I'm not familiar with JNI, if i use it , its for security reasons and try to avoid pirac.
Thanks
Thanks to Michael :
The answer working for what i want to do with jobject context from parameter function :
jclass native_context = env->GetObjectClass(context);
jclass intentClass = env->FindClass("android/content/Intent");
jclass actionString = env->FindClass("yourPackage/YourActivity");
jmethodID newIntent = env->GetMethodID(intentClass, "<init>", "(Landroid/content/Context;Ljava/lang/Class;)V");
jobject intent = env->NewObject(intentClass,newIntent,context,actionString);
jmethodID methodFlag = env->GetMethodID(intentClass, "setFlags", "(I)Landroid/content/Intent;");
jobject intentActivity = env->CallObjectMethod(intent, methodFlag, 268435456 );
jmethodID startActivityMethodId = env->GetMethodID(native_context, "startActivity", "(Landroid/content/Intent;)V");
env->CallVoidMethod(context, startActivityMethodId, intentActivity);

Get app signature hash code in jni

i want to get app signature in native with these code: (source)
// For class Context
jclass native_clazz = (*env)->GetObjectClass(env, context);
// Get the getPackageManager method ID
jmethodID methodID_func = (*env)->GetMethodID(env, native_clazz,
"getPackageManager", "()Landroid/content/pm/PackageManager;");
// Access manager application package
jobject package_manager = (*env)->CallObjectMethod(env, thiz, methodID_func);
// For class PackageManager
jclass pm_clazz = (*env)->GetObjectClass(env, package_manager);
// Get the getPackageInfo method ID
jmethodID methodID_pm = (*env)->GetMethodID(env, pm_clazz,
"getPackageInfo", "(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");
// To obtain the application package information
jobject package_info = (*env)->CallObjectMethod(env, package_manager,
methodID_pm, (*env)->NewStringUTF(env, "com.example.hellojni"), 64);
but i got this:
error: 'context' undeclared (first use in this function)
how do i get context in native?
how do i return signature hashcode as string?
You can send the context to JNI in a parameter for example
jstring Java_packagename_stringFromJNI( JNIEnv* env, jobject thiz , jobject context)
And when you call the method in your activity:
public native String stringFromJNI(Context context);
...
Log.d(TAG, "Receive: " + stringFromJNI(this));

Proper way to get string list in JNI

I have a JNI function in C which is getting passed in a Java FILE class which represents a directory listing. I would like to call the list() function and get the list of strings (files in the directory). What is the best way to do this?
Right now I have
static void* my_function(JNIEnv *env, jobject obj, jobject dir){
jarray listRet;
jclass cls = (*env)->GetObjectClass(env, dir);
jmethodID method = (*env)->GetMethodID(env, cls, "list", "()[Ljava/lang/String");
listRet = (*env)->CallObjectMethod(env, cls, method);
jsize stringCount = (*env)->GetArrayLength(env, listRet);
}
However, by adding logging statements, it seems that it never gets past the GetObjectClass call.
So, is this call correct? Further, is the GetMethodID call correct? The return type of list() is a (java) String[].
Is there anywhere else that I'm going wrong?
list is not a static method of File. That is, it belongs to an instance of File (dir in your case), not to the File class.
So instead of:
listRet = (*env)->CallObjectMethod(env, cls, method);
you should be using:
listRet = (*env)->CallObjectMethod(env, dir, method);
Also, you seem to be missing a semicolon in the signature for list. It should be "()[Ljava/lang/String;"

JNI call fail on non static methods

I'm trying to call a non static java method from C++ using the JNI on an Android project, but GetMethodID always return NULL.
this is my code:
void Java_com_kungfu_rabbit_KungFuRabbitActivity_nativeOnCreate(JNIEnv *env, jobject obj)
{
// this code works fine
jclass cls = env->FindClass("com/kungfu/rabbit/KungFuRabbitActivity");
jmethodID mid = env->GetStaticMethodID(cls, "foo", "()V");
env->CallStaticVoidMethod(cls, mid);
// this one fails:
jclass cls = env->GetObjectClass(obj);
jmethodID mid = env->GetMethodID(cls, "foo2", "()V");
env->CallVoidMethod(obj, mid);
}
I'm calling this native function from the class that extends Activity. foo is a public static void function, and foo2 is a public void function.
I can't understand why it fails...
Can anyone help me to understand?
Thanks in advance

Categories

Resources