为什么传递 java long 作为指向 C++ 库中结构的指针会导致应用程序崩溃?

Why is passing java long as pointer to struct in c++ library crashing app?

我正在尝试通过 java 遵循此线程中概述的步骤在 C++ 库中保留引用:Passing pointers between C and Java through JNI

但是,当我 运行 应用程序时,它立即崩溃了。有人可以看看我做错了什么吗?把我的头发拉得太长了...

编辑: 应超级用户迈克尔的要求添加了完整的代码和堆栈跟踪。如果 testingHandle bool 设置为 false,则代码 运行 没问题。如果设置为 true

则崩溃

编辑 2:而且,这是一个打字错误...已在下方修复

申请代码:

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 边:

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());
    }
}

单独 headers/cpp(不是句柄的一部分,但功能正常

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";
}

错误output/stack跟踪,可以看到是执行CreateMemory()函数失败

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)

你的C++有多长long?

C++ 中的大小是特定于实现的,唯一的要求是至少为 32 位。一些编译器 longint 是 32 位,指针是 64 位。

最好在 C++ 代码中使用类似 uint64_t 的东西。

这一行有问题:

return (long)newPtr;

longjlong 不是相同的数据类型,后者可能更宽。改为 jlong

return (jlong)newPtr;

"No implementation found for long com.AndroidCPP.DynamicLib.CreateMemory"

您的代码有错别字:Java_com_AndroidCPP_DynamciLib_CreateMemory

应该是:Java_com_AndroidCPP_DynamicLib_CreateMemory

FreeMemory 也一样。