英文:
Why is passing java long as pointer to struct in c++ library crashing app?
问题
package com.AndroidCPP;
import android.app.Activity;
import android.widget.TextView;
import android.os.Bundle;
import android.util.Log;
public class AndroidCPP extends Activity
{
private static final String TAG = "AndroidCPP";
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
boolean testingHandle = true;
if(testingHandle)
{
DynamicLib newLib = new DynamicLib();
newLib.Init();
newLib.CleanUp();
}
int libNum = DynamicLib.GetNumber(3);
String ipAddress = DynamicLib.GetLocalIPv4();
String serialNumber = DynamicLib.GetSerialNumber();
TextView tv = new TextView(this);
String textViewString = String.format("Here is a number that was the cause of addition in a C++ library: %d \n", libNum);
textViewString += String.format("Here is the IP Address Pulled from the DL: %s", ipAddress);
textViewString += "\n";
textViewString += "Here is the IP Address Pulled from Java Utils: " + Utils.getIPAddress(true);
textViewString += "\n";
textViewString += String.format("Here is the serial Number pulled from DL: %s", serialNumber);
tv.setText(textViewString);
Log.v(TAG, "");
Log.v(TAG, "***************");
Log.v(TAG, "JAVA ip: " + Utils.getIPAddress(true));
Log.v(TAG, "C++ ip: " + ipAddress);
Log.v(TAG, "JAVA MAC: " + Utils.getMACAddress("wlan0"));
Log.v(TAG, "Serial Number: " + serialNumber);
setContentView(tv);
}
}
package com.AndroidCPP;
class DynamicLib
{
static {
System.loadLibrary("DynamicLib");
}
long testHandle = 0;
public void Init()
{
testHandle = CreateMemory();
}
public void CleanUp()
{
FreeMemory(testHandle);
}
public native long CreateMemory();
public native void FreeMemory(long ptr);
public static native int GetNumber(int testParameter);
public static native String GetLocalIPv4();
public static native String GetSerialNumber();
}
#include <jni.h>
#include <android/log.h>
#include "TestClass.h"
#include "IPFetch.h"
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "DynamicLib", __VA_ARGS__))
#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "DynamicLib", __VA_ARGS__))
extern "C" {
JNIEXPORT jlong JNICALL Java_com_AndroidCPP_DynamicLib_CreateMemory(JNIEnv* env, jobject obj)
{
DynamicLib::testStruct* newPtr = new DynamicLib::testStruct();
return (jlong)newPtr;
}
JNIEXPORT void JNICALL Java_com_AndroidCPP_DynamicLib_FreeMemory(JNIEnv* env, jobject obj, jlong ptr)
{
DynamicLib::testStruct* tempStructPtr = (DynamicLib::testStruct*)ptr;
delete tempStructPtr;
}
JNIEXPORT int JNICALL Java_com_AndroidCPP_DynamicLib_GetNumber(JNIEnv* env, jobject obj, int testParameter)
{
LOGI("Calling Get Number From Dynamic Lib With Test Parameter %d", testParameter);
DynamicLib::TestClass testClass;
return testClass.AddTwoNumbers(testParameter, 2);
}
JNIEXPORT jstring JNICALL Java_com_AndroidCPP_DynamicLib_GetLocalIPv4(JNIEnv* env, jobject obj)
{
DynamicLib::IPFetch ipFetch;
jstring returnString = env->NewStringUTF(ipFetch.FetchLocalIPv4().c_str());
return returnString;
}
JNIEXPORT jstring JNICALL Java_com_AndroidCPP_DynamicLib_GetSerialNumber(JNIEnv* env, jobject obj)
{
DynamicLib::IPFetch ipFetch;
return env->NewStringUTF(ipFetch.FetchSerialNumber().c_str());
}
}
Please note that I've provided the translated code only and removed any additional text or context.
英文:
I am trying to hold a reference in a c++ libary through java follwing along the steps outlined in this thread: https://stackoverflow.com/questions/1632367/passing-pointers-between-c-and-java-through-jni
However, when I run the application it instantly crashes. Can someone please take a look and see what I may be doing wrong? Been pulling my hair too long...
EDIT:
Added full code and stack trace at request of super user michael. The code runs fine if the testingHandle bool is set to false. Crashes if it is set to true
Edit 2: And, it was a typo... fixed below
application code:
package com.AndroidCPP;
import android.app.Activity;
import android.widget.TextView;
import android.os.Bundle;
import android.util.Log;
public class AndroidCPP extends Activity
{
//Set Activity tag for logging (adb command: adb logcat *:s AndroidCPP:V)
private static final String TAG = "AndroidCPP";
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
boolean testingHandle = true;
if(testingHandle)
{
DynamicLib newLib = new DynamicLib();
newLib.Init();
newLib.CleanUp();
}
//pull device info from lib
int libNum = DynamicLib.GetNumber(3);
String ipAddress = DynamicLib.GetLocalIPv4();
String serialNumber = DynamicLib.GetSerialNumber();
//Textview will only work on regular android device, you'll be in the black void if run on a quest
TextView tv = new TextView(this);
String textViewString = String.format("Here is a number that was the cause of addition in a C++ library : %d \n", libNum);
textViewString += String.format("Here is the IP Adrress Pulled from the DL: %s", ipAddress);
textViewString += "\n";
textViewString += "Here is the IP Address Pulled from Java Utils: " + Utils.getIPAddress(true);
textViewString += "\n";
textViewString += String.format("Here is the serial Number pulled from DL: %s", serialNumber);
tv.setText(textViewString);
//Logcat Log
Log.v(TAG, "");
Log.v(TAG, "***************");
Log.v(TAG, "JAVA ip: " + Utils.getIPAddress(true));
Log.v(TAG, "C++ ip :" + ipAddress);
Log.v(TAG, "JAVA MAC : " + Utils.getMACAddress("wlan0"));
Log.v(TAG, "Serial Number : " + serialNumber);
setContentView(tv);
}
}
java side:
package com.AndroidCPP;
class DynamicLib
{
static{
System.loadLibrary("DynamicLib");
}
long testHandle = 0;
public void Init()
{
testHandle = CreateMemory();
}
public void CleanUp()
{
FreeMemory(testHandle);
}
public native long CreateMemory();
public native void FreeMemory(long ptr);
public static native int GetNumber(int testParameter);
public static native String GetLocalIPv4();
public static native String GetSerialNumber();
}
CPP side:
#include <jni.h>
#include <android/log.h>
#include "TestClass.h"
#include "IPFetch.h"
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "DynamicLib", __VA_ARGS__))
#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "DynamicLib", __VA_ARGS__))
extern "C" {
JNIEXPORT jlong JNICALL Java_com_AndroidCPP_DynamicLib_CreateMemory(JNIEnv* env, jobject obj)
{
DynamicLib::testStruct* newPtr = new DynamicLib::testStruct();
return (jlong)newPtr;
}
JNIEXPORT void JNICALL Java_com_AndroidCPP_DynamicLib_FreeMemory(JNIEnv* env, jobject obj, jlong ptr)
{
DynamicLib::testStruct* tempStructPtr = (DynamicLib::testStruct*)ptr;
delete tempStructPtr;
}
JNIEXPORT int JNICALL Java_com_AndroidCPP_DynamicLib_GetNumber(JNIEnv* env, jobject obj, int testParameter)
{
LOGI("Calling Get Number From Dynamic Lib With Test Parameter %d", testParameter);
DynamicLib::TestClass testClass;
return testClass.AddTwoNumbers(testParameter, 2);
}
JNIEXPORT jstring JNICALL Java_com_AndroidCPP_DynamicLib_GetLocalIPv4(JNIEnv* env, jobject obj)
{
DynamicLib::IPFetch ipFetch;
jstring returnString = env->NewStringUTF(ipFetch.FetchLocalIPv4().c_str());
return returnString;
}
JNIEXPORT jstring JNICALL Java_com_AndroidCPP_DynamicLib_GetSerialNumber(JNIEnv* env, jobject obj)
{
DynamicLib::IPFetch ipFetch;
return env->NewStringUTF(ipFetch.FetchSerialNumber().c_str());
}
}
separate headers/cpp (not part of handle, but functioning like they should
namespace DynamicLib {
struct testStruct {
int x = 10;
int y = 10;
};
class TestClass
{
public:
TestClass() = default;
~TestClass();
int AddTwoNumbers(int a, int b);
};
}
#include <string.h>
#include <iostream>
namespace DynamicLib
{
class IPFetch
{
public:
IPFetch() = default;
~IPFetch();
std::string FetchLocalIPv4();
std::string FetchSerialNumber();
};
}
#include "IPFetch.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <stdio.h>
#include <dlfcn.h>
#include <android/log.h>
#include <string>
#include <sstream>
using namespace DynamicLib;
IPFetch::~IPFetch()
{
}
std::string IPFetch::FetchLocalIPv4()
{
int s;
struct ifreq ifr;
char stringBuffer[16];
const char *ipCast = "%d.%d.%d.%d";
s = socket(AF_INET, SOCK_DGRAM, 0);
strcpy(ifr.ifr_name, "wlan0");
ioctl(s, SIOCGIFADDR, &ifr);
unsigned char *ip = (unsigned char*)(&ifr.ifr_addr.sa_data[2]);
close(s);
snprintf(stringBuffer, sizeof(stringBuffer), ipCast, ip[0], ip[1], ip[2], ip[3]);
return std::string(stringBuffer);
}
std::string IPFetch::FetchSerialNumber()
{
typedef int(*PFN_SYSTEM_PROP_GET)(const char *, char *);
#if (__ANDROID_API__ >= 21)
static PFN_SYSTEM_PROP_GET __real_system_property_get = NULL;
if (!__real_system_property_get) {
// libc.so should already be open, get a handle to it.
void *handle = dlopen("libc.so", RTLD_NOLOAD);
if (!handle) {
__android_log_print(ANDROID_LOG_ERROR, "foobar", "Cannot dlopen libc.so: %s.\n", dlerror());
}
else {
__real_system_property_get = (PFN_SYSTEM_PROP_GET)dlsym(handle, "__system_property_get");
}
if (!__real_system_property_get) {
__android_log_print(ANDROID_LOG_ERROR, "foobar", "Cannot resolve __system_property_get(): %s.\n", dlerror());
}
}
char buff[64];
std::ostringstream stm;
stm << ((*__real_system_property_get)("ro.boot.serialno", buff));
std::string returnVal = stm.str();
return std::string(buff);
#endif // __ANDROID_API__ >= 21
return "-1";
}
Error output/stack trace, you can see it is failing to execute the CreateMemory() function
05-05 00:49:39.831 11430 11430 I chatty : uid=10297(com.AndroidCPP) identical 2 lines
05-05 00:49:40.031 11430 11430 I System.out: waiting for debugger to settle...
05-05 00:49:40.231 11430 11430 I System.out: debugger has settled (1306)
05-05 00:49:40.244 1503 2852 E InputDispatcher: Window handle Window{b5ce578 u0 Waiting For Debugger: com.AndroidCPP} has no registered input channel
05-05 00:49:40.523 11430 11430 I com.AndroidCPP: The ClassLoaderContext is a special shared library.
05-05 00:49:41.116 11430 11430 E com.AndroidCPP: No implementation found for long com.AndroidCPP.DynamicLib.CreateMemory() (tried Java_com_AndroidCPP_DynamicLib_CreateMemory and Java_com_AndroidCPP_DynamicLib_CreateMemory__)
05-05 00:49:41.117 11430 11430 D AndroidRuntime: Shutting down VM
05-05 00:49:41.141 11430 11430 E AndroidRuntime: FATAL EXCEPTION: main
05-05 00:49:41.141 11430 11430 E AndroidRuntime: Process: com.AndroidCPP, PID: 11430
05-05 00:49:41.141 11430 11430 E AndroidRuntime: java.lang.UnsatisfiedLinkError: No implementation found for long com.AndroidCPP.DynamicLib.CreateMemory() (tried Java_com_AndroidCPP_DynamicLib_CreateMemory and Java_com_AndroidCPP_DynamicLib_CreateMemory__)
05-05 00:49:41.141 11430 11430 E AndroidRuntime: at com.AndroidCPP.DynamicLib.CreateMemory(Native Method)
05-05 00:49:41.141 11430 11430 E AndroidRuntime: at com.AndroidCPP.DynamicLib.Init(DynamicLib.java:14)
05-05 00:49:41.141 11430 11430 E AndroidRuntime: at com.AndroidCPP.AndroidCPP.onCreate(AndroidCPP.java:26)
05-05 00:49:41.141 11430 11430 E AndroidRuntime: at android.app.Activity.performCreate(Activity.java:7825)
05-05 00:49:41.141 11430 11430 E AndroidRuntime: at android.app.Activity.performCreate(Activity.java:7814)
05-05 00:49:41.141 11430 11430 E AndroidRuntime: at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1306)
05-05 00:49:41.141 11430 11430 E AndroidRuntime: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3245)
05-05 00:49:41.141 11430 11430 E AndroidRuntime: at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409)
05-05 00:49:41.141 11430 11430 E AndroidRuntime: at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
05-05 00:49:41.141 11430 11430 E AndroidRuntime: at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
05-05 00:49:41.141 11430 11430 E AndroidRuntime: at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
05-05 00:49:41.141 11430 11430 E AndroidRuntime: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
05-05 00:49:41.141 11430 11430 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:107)
05-05 00:49:41.141 11430 11430 E AndroidRuntime: at android.os.Looper.loop(Looper.java:214)
05-05 00:49:41.141 11430 11430 E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:7356)
05-05 00:49:41.141 11430 11430 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
05-05 00:49:41.141 11430 11430 E AndroidRuntime: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
05-05 00:49:41.141 11430 11430 E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
05-05 00:49:41.157 1503 11483 I DropBoxManagerService: add tag=data_app_crash isTagEnabled=true flags=0x2
05-05 00:49:41.157 1503 2991 W ActivityTaskManager: Force finishing activity com.AndroidCPP/.AndroidCPP
05-05 00:49:41.182 11430 11430 I Process : Sending signal. PID: 11430 SIG: 9
05-05 00:49:41.184 1503 1579 E libprocessgroup: set_timerslack_ns write failed: No such process
05-05 00:49:41.218 1503 3340 I ActivityManager: Process com.AndroidCPP (pid 11430) has died: vis+99 TOP
05-05 00:49:41.220 937 937 I Zygote : Process 11430 exited due to signal 9 (Killed)
答案1
得分: 2
"找不到 long com.AndroidCPP.DynamicLib.CreateMemory 的实现"
你的代码中有一个拼写错误:Java_com_AndroidCPP_DynamciLib_CreateMemory
应该是:Java_com_AndroidCPP_DynamicLib_CreateMemory
同样的情况也适用于 FreeMemory
。_
英文:
"No implementation found for long com.AndroidCPP.DynamicLib.CreateMemory"
You've got a typo in your code: Java_com_AndroidCPP_DynamciLib_CreateMemory
That should be: Java_com_AndroidCPP_DynamicLib_CreateMemory
Same thing for FreeMemory
.
答案2
得分: 0
你好!以下是您要翻译的内容:
你的 C++ 中的 **long** 有多长?
在 C++ 中,它的大小是与具体实现相关的,唯一的要求是它至少为 32 位。一些编译器将 **long** 和 **int** 设置为 32 位,而指针为 64 位。
在 C++ 代码中最好使用类似 **uint64_t** 的数据类型。
英文:
How long is your C++ long?
The size in C++ is implementation-specific, and the only requirement is that it be at least 32 bits. Some compilers have long and int be 32 bits, with pointers being 64 bits.
Best to use something like uint64_t in the C++ code.
答案3
得分: 0
这一行有问题:
return (long)newPtr;
long
和 jlong
不是相同的数据类型,后者可能更宽。改为转换为 jlong
:
return (jlong)newPtr;
英文:
This line is problematic:
return (long)newPtr;
long
and jlong
are not the same datatype, the latter might be wider. Cast to jlong
instead.
return (jlong)newPtr;
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论