简体   繁体   English

Android NDK - 在本机函数中引用C ++类

[英]Android NDK - referencing C++ classes in native functions

I'm really new to Android NDK, and have the following issue. 我是Android NDK的新手,有以下问题。

I have a file within my JNI folder named 'get-raw-image.cpp' (trying to integrate from here ), and within it I've made a function to call natively with the Java android code. 我的JNI文件夹中有一个名为'get-raw-image.cpp'的文件(试图从这里集成),在其中我已经创建了一个用Java android代码本机调用的函数。

extern "C"{
    void Java_com_example_ndksetup_MainActivity_testTest(JNIEnv * env, jobject ths){
        __android_log_print(ANDROID_LOG_DEBUG, "LOG_TAG", "Testing");

        ScreenshotClient screenshot;
        //screenshot.update();
    }
}

I'm trying to reference the ScreenshotClient class (within this same file) and create a new instance of it, but keep getting this error when I build/compile: 我正在尝试引用ScreenshotClient类(在同一个文件中)并创建它的新实例,但在构建/编译时不断收到此错误:

"undefined reference to 'android::ScreenshotClient::ScreenshotClient()' collect2: ld returned 1 exit status" “未定义引用'android :: ScreenshotClient :: ScreenshotClient()'collect2:ld返回1退出状态”

Here is what the ScreenshotClient class looks like, any help is appreciated, thanks. 这是ScreenshotClient类的样子,感谢任何帮助。

class ScreenshotClient {
    /*
    sp<IMemoryHeap> mHeap;
    uint32_t mWidth;
    uint32_t mHeight;
    PixelFormat mFormat;
    */
    char data[1024]; //android 4.2 embed CpuConsumer::LockedBuffer here which cause more space
public:
    ScreenshotClient();

#if defined(TARGET_ICS)
    // frees the previous screenshot and capture a new one
    int32_t update();
#endif
#if defined(TARGET_JB)
    // frees the previous screenshot and capture a new one
    int32_t update(const sp<IBinder>& display);
#endif
    // pixels are valid until this object is freed or
    // release() or update() is called
    void const* getPixels() const;

    uint32_t getWidth() const;
    uint32_t getHeight() const;
    uint32_t getStride() const; //base + getStride()*bytesPerPixel will get start address of next row
    int32_t getFormat() const;
    // size of allocated memory in bytes
    size_t getSize() const;
};

#if defined(TARGET_JB)
class SurfaceComposerClient {
public:
    //! Get the token for the existing default displays.
    //! Possible values for id are eDisplayIdMain and eDisplayIdHdmi.
    static sp<IBinder> getBuiltInDisplay(int32_t id);
};
#endif

class ProcessState {
    char data[1024]; //please adjust this value when you copy this definition to your real source!!!!!!!!!!!!!!!!!!!!!!!
public:
    static sp<ProcessState> self();
    void startThreadPool();
};

} //end of namespace android

using android::ScreenshotClient;
using android::sp;
using android::IBinder;
#if defined(TARGET_JB)
using android::SurfaceComposerClient;
#endif
using android::ProcessState;

#endif //} end of "if defined(TARGET_ICS) || defined(TARGET_JB)"

edit: I made the native function static in the extern "C" section and now have the following errors when I call it, but it is compiling now at least. 编辑:我在extern“C”部分中使本机函数静态,现在我调用它时会出现以下错误,但它现在至少在编译。

06-17 16:47:09.365: E/AndroidRuntime(18566): FATAL EXCEPTION: main 06-17 16:47:09.365: E/AndroidRuntime(18566): java.lang.IllegalStateException: Could not execute method of the activity 06-17 16:47:09.365: E/AndroidRuntime(18566): at android.view.View$1.onClick(View.java:3699) 06-17 16:47:09.365: E/AndroidRuntime(18566): at android.view.View.performClick(View.java:4223) 06-17 16:47:09.365: E/AndroidRuntime(18566): at android.view.View$PerformClick.run(View.java:17281) 06-17 16:47:09.365: E/AndroidRuntime(18566): at android.os.Handler.handleCallback(Handler.java:615) 06-17 16:47:09.365: E/AndroidRuntime(18566): at android.os.Handler.dispatchMessage(Handler.java:92) 06-17 16:47:09.365: E/AndroidRuntime(18566): at android.os.Looper.loop(Looper.java:137) 06-17 16:47:09.365: E/AndroidRuntime(18566): at android.app.ActivityThread.main(ActivityThread.java:4898) 06-17 16:47:09.365: E/AndroidRuntime(18566): at java.lang.reflect.Method.invokeNative(Native Method) 06-17 16:47:09.365: E/AndroidRun 06-17 16:47:09.365:E / AndroidRuntime(18566):FATAL EXCEPTION:main 06-17 16:47:09.365:E / AndroidRuntime(18566):java.lang.IllegalStateException:无法执行活动06的方法-17 16:47:09.365:E / AndroidRuntime(18566):在android.view.View $ 1.onClick(View.java:3699)06-17 16:47:09.365:E / AndroidRuntime(18566):在android。 view.View.performClick(View.java:4223)06-17 16:47:09.365:E / AndroidRuntime(18566):at android.view.View $ PerformClick.run(View.java:17281)06-17 16: 47:09.365:E / AndroidRuntime(18566):在android.os.Handler.handleCallback(Handler.java:615)06-17 16:47:09.365:E / AndroidRuntime(18566):在android.os.Handler.dispatchMessage (Handler.java:92)06-17 16:47:09.365:E / AndroidRuntime(18566):在android.os.Looper.loop(Looper.java:137)06-17 16:47:09.365:E / AndroidRuntime (18566):在android.app.ActivityThread.main(ActivityThread.java:4898)06-17 16:47:09.365:E / AndroidRuntime(18566):at java.lang.reflect.Method.invokeNative(Native Method)06 -17 16:47:09.365:E / AndroidRun time(18566): at java.lang.reflect.Method.invoke(Method.java:511) 06-17 16:47:09.365: E/AndroidRuntime(18566): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1008) 06-17 16:47:09.365: E/AndroidRuntime(18566): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:775) 06-17 16:47:09.365: E/AndroidRuntime(18566): at dalvik.system.NativeStart.main(Native Method) 06-17 16:47:09.365: E/AndroidRuntime(18566): Caused by: java.lang.reflect.InvocationTargetException 06-17 16:47:09.365: E/AndroidRuntime(18566): at java.lang.reflect.Method.invokeNative(Native Method) 06-17 16:47:09.365: E/AndroidRuntime(18566): at java.lang.reflect.Method.invoke(Method.java:511) 06-17 16:47:09.365: E/AndroidRuntime(18566): at android.view.View$1.onClick(View.java:3694) 06-17 16:47:09.365: E/AndroidRuntime(18566): ... 11 more 06-17 16:47:09.365: E/AndroidRuntime(18566): Caused by: java.lang.UnsatisfiedLinkError: Native method not found: com.example.ndksetup.MainActivity.testTest: time(18566):at java.lang.reflect.Method.invoke(Method.java:511)06-17 16:47:09.365:E / AndroidRuntime(18566):at com.android.internal.os.ZygoteInit $ MethodAndArgsCaller .run(ZygoteInit.java:1008)06-17 16:47:09.365:E / AndroidRuntime(18566):at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:775)06-17 16:47 :09.365:E / AndroidRuntime(18566):at dalvik.system.NativeStart.main(Native Method)06-17 16:47:09.365:E / AndroidRuntime(18566):引起:java.lang.reflect.InvocationTargetException 06- 17 16:47:09.365:E / AndroidRuntime(18566):at java.lang.reflect.Method.invokeNative(Native Method)06-17 16:47:09.365:E / AndroidRuntime(18566):at java.lang.reflect .Method.invoke(Method.java:511)06-17 16:47:09.365:E / AndroidRuntime(18566):在android.view.View $ 1.onClick(View.java:3694)06-17 16:47: 09.365:E / AndroidRuntime(18566):... 11更多06-17 16:47:09.365:E / AndroidRuntime(18566):引起:java.lang.UnsatisfiedLinkError:找不到本机方法:com.example.ndksetup。 MainActivity.testTest: ()V 06-17 16:47:09.365: E/AndroidRuntime(18566): at com.example.ndksetup.MainActivity.testTest(Native Method) 06-17 16:47:09.365: E/AndroidRuntime(18566): at com.example.ndksetup.MainActivity.t(MainActivity.java:72) 06-17 16:47:09.365: E/AndroidRuntime(18566): ... 14 more ()V 06-17 16:47:09.365:E / AndroidRuntime(18566):at com.example.ndksetup.MainActivity.testTest(Native Method)06-17 16:47:09.365:E / AndroidRuntime(18566):at com.example.ndksetup.MainActivity.t(MainActivity.java:72)06-17 16:47:09.365:E / AndroidRuntime(18566):... 14更多

Here is my Android.mk make file: 这是我的Android.mk make文件:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_LDLIBS := -llog

LOCAL_MODULE    := ndksetup
LOCAL_MODULE := libgui 
LOCAL_SRC_FILES := fake_libgui.cpp
LOCAL_SRC_FILES := get-raw-image.cpp
LOCAL_SHARED_LIBRARIES += libgui

include $(BUILD_SHARED_LIBRARY)

second attempt : You cannot declare a JNI method static , because it must be "visible" to dynamic loader. 第二次尝试 :您不能将JNI方法声明为静态 ,因为它必须对动态加载器“可见”。

first attempt : On ICS or later, class ScreenshotClient is part of libgui.so (earlier versions had this class in the system library called libsurfaceflinger_client.so ) You can pull it from your device or emulator, with command 第一次尝试 :在ICS或更高版本上,类ScreenshotClientlibgui.so一部分(早期版本在系统库中有一个名为libsurfaceflinger_client.so )您可以使用命令从设备或模拟器中提取它

adb pull /system/lib/libgui.so c:\android\libs\libgui.so

Now in your Android.mk , add LOCAL_LDFLAGS += c:/android/libs/libgui.so to your module. 现在在Android.mk ,将LOCAL_LDFLAGS += c:/android/libs/libgui.so到您的模块中。

You will see a warning from ndk-build : 您将看到来自ndk-build的警告:

Android NDK: WARNING:jni/Android.mk: non-system libraries in linker flags: c:/android/libs/libgui.so Android NDK:警告:jni / Android.mk:链接器标志中的非系统库:c:/android/libs/libgui.so

This is the price of using non-public APIs in ndk-build . 这是在ndk-build中使用非公共API的代价。

expecting the future questions : Make sure that your app has all relevant permissions to access the screen. 期待未来的问题 :确保您的应用具有访问屏幕的所有相关权限。 See How to use ScreenShotClient in my android application for related discussion. 请参阅如何在我的Android应用程序中使用ScreenShotClient进行相关讨论。

UPDATE UPDATE

The referenced GitHub uses fake libs instead of pulling them from the device. 引用的GitHub使用伪lib而不是从设备中提取它们。 It is easy to implement this with Android.mk . 使用Android.mk很容易实现这一点。 Get fake_libbinder.cpp to LOCAL_PATH directory, and add the following section into your Android.mk : 获取fake_libbinder.cppLOCAL_PATH目录,并添加以下部分到你的Android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE   := libibgui
LOCAL_SRC_FILES := fake_gui.cpp
include $(BUILD_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_LDLIBS := -llog
LOCAL_MODULE    := ndksetup
LOCAL_SRC_FILES := get-raw-image.cpp
LOCAL_SHARED_LIBRARIES += libgui
include $(BUILD_SHARED_LIBRARY)

Now add LOCAL_SHARED_LIBRARIES += libgui to your main module. 现在将LOCAL_SHARED_LIBRARIES += libgui添加到主模块。

You will probably need same for the fake libbinder . 伪造的libbinder你可能需要相同的libbinder Still, your app will use the real libbinder and libgui libraries from the device /system/lib . 不过,您的应用程序将使用设备/system/lib真实 libbinder和libgui库。 Still, it depends on system calls not being changed. 仍然,它取决于系统调用没有被更改。

I am the author of 'get-raw-image.cpp'. 我是'get-raw-image.cpp'的作者。 About your question, 1: You should be aware that your app will failed due to ScreenshotClient::update method require FRAME_BUFFER_ACCESS permission which normal java app does not have this permission. 关于你的问题,1:你应该知道你的应用程序会因为ScreenshotClient :: update方法失败而需要FRAME_BUFFER_ACCESS权限,而普通的java应用程序没有这个权限。 (Adb shell user is OK). (Adb shell用户可以)。

2: These native code need be linked to libgui.so and libbinder.so, but unfortunately, gcc will ask you for a lot of *.so referenced by them, I failed to do that, so i made a fake libgui.so, libbinder.so and link to get-raw-image. 2:这些本机代码需要链接到libgui.so和libbinder.so,但不幸的是,gcc会要求你提供很多* .so引用它们,我没有这样做,所以我做了一个假的libgui.so, libbinder.so并链接到get-raw-image。 You can use my make file https://github.com/sjitech/sji-android-screen-capture/blob/master/src/android/ffmpeg/1_build_get-raw-image.sh to make these fake so files. 您可以使用我的make文件https://github.com/sjitech/sji-android-screen-capture/blob/master/src/android/ffmpeg/1_build_get-raw-image.sh来制作这些假文件。 (You need remove "rm libgui.so libbinder.so" in the script, then make, then extract so files). (您需要在脚本中删除“rm libgui.so libbinder.so”,然后生成,然后解压缩文件)。

Finally, you add libgui.so libbinder.so to your Android.mk for link. 最后,将libgui.so libbinder.so添加到Android.mk中以获取链接。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM