zoukankan      html  css  js  c++  java
  • Android_ndk_jni_hello-jni_hacking

    /***************************************************************************
     *                      Android_ndk_jni_hello-jni_hacking 
     *  声明:
     *      1. 本文用的是android-2.2_froyo的源代码;
     *      2. 本文仅仅是对Android自带的ndk中的samples中的jni_hello示例的解读;
     *      3. 本文更多的是想通过这个自带的简单示例来了解jni的框架结构,所以没
     *          有提供除此之外的更多的内容解读.  :)
     *
     *                      2015-4-19 周日 晴 深圳 南山 西丽平山村 曾剑锋
     **************************************************************************/
    
            \\\\\\\\\\\\* 目录 */////////////////////////
            |  一. 参考文章:                                        |
            |  二. 分析源码来源及文件结构:                          |
            |  三. 解析流程:                                        |
            |  四. 解析src/com/example/hellojni/HelloJni.java文件:  |
            |  五. 解析jni/Android.mk文件:                          |
            |  六. 解析jni/hello-jni.c文件:                         |
            \\\\\\\\\\\\\\/////////////////////////////
            
    一. 参考文章:
        主要参考ndk自带的文档(ndk根目录下的docs文件夹):
        .
        |-- ANDROID-MK.TXT
        |-- APPLICATION-MK.TXT
        |-- CHANGES.TXT
        |-- CPU-ARCH-ABIS.TXT
        |-- CPU-ARM-NEON.TXT
        |-- CPU-FEATURES.TXT
        |-- DEVELOPMENT.TXT
        |-- HOWTO.TXT
        |-- INSTALL.TXT
        |-- LICENSES.TXT
        |-- NDK-BUILD.TXT
        |-- NDK-GDB.TXT
        |-- OVERVIEW.TXT
        |-- STABLE-APIS.TXT
        `-- SYSTEM-ISSUES.TXT
        
    二. 分析源码来源及文件结构:
        1. 本文是用NDK自带的samples中的hello-jni来分析jni的编写流程;
        2. NDK提供的hello-jni示例文件结构:
            .
            |-- AndroidManifest.xml
            |-- default.properties
            |-- jni
            |   |-- Android.mk                              ---> jni makefile
            |   |-- Android_ndk_jni_hello-jni_hacking.c
            |   `-- hello-jni.c                             ---> jni C文件
            |-- libs
            |   `-- armeabi
            |-- res
            |   `-- values
            |       `-- strings.xml
            `-- src
                `-- com
                    `-- example
                        `-- hellojni
                            `-- HelloJni.java               ---> java源文件
        3. 从文件结构上分析可知,这是一个Android工程项目;
    
    三. 解析流程:
        1. 本文采用java程序-->jni接口-->C程序的解析流程,这也比较符合常规需求分析;
        2. 解析文件流程:
            1. src/com/example/hellojni/HelloJni.java
            2. jni/Android.mk
            3. jni/hello-jni.c
    
    四. 解析src/com/example/hellojni/HelloJni.java文件:
        1. cat src/com/example/hellojni/HelloJni.java
            ......
            package com.example.hellojni;    //javah会利用包名生成jni C函数名
    
            import android.app.Activity;
            import android.widget.TextView;
            import android.os.Bundle;
    
            public class HelloJni extends Activity
            {
                /** Called when the activity is first created. */
                @Override
                public void onCreate(Bundle savedInstanceState)
                {
                    super.onCreate(savedInstanceState);
    
                    /* Create a TextView and set its content.
                     * the text is retrieved by calling a native
                     * function.
                     */
                    TextView  tv = new TextView(this);
                    tv.setText( stringFromJNI() );
                    setContentView(tv);
                }
    
                /* A native method that is implemented by the
                 * 'hello-jni' native library, which is packaged
                 * with this application.
                 */
                /**
                 * 这个本地方法在hello-jni库中已经实现了, 
                 * 并且hello-jni库,已经被打包进这个应用里.
                 */
                public native String  stringFromJNI(); //本地方法声明方式,多加个native
    
                /* This is another native method declaration that is *not*
                 * implemented by 'hello-jni'. This is simply to show that
                 * you can declare as many native methods in your Java code
                 * as you want, their implementation is searched in the
                 * currently loaded native libraries only the first time
                 * you call them.
                 *
                 * Trying to call this function will result in a
                 * java.lang.UnsatisfiedLinkError exception !
                 */
                /**
                 * 这是另一个本地方法,但是没有在hello-jni库中实现,
                 * 这仅仅是为了告诉你,你可以声明很多本地方法在你的Java
                 * 代码中,只有当你调用这个函数的时候,才会去查找这个本地
                 * 是否实现了.
                 *
                 * 如果你去调用这个没有实现的本地方法,你将会得到:
                 * java.lang.UnsatisfiedLinkError异常.
                 */
                public native String  unimplementedStringFromJNI();
    
                /* this is used to load the 'hello-jni' library on application
                 * startup. The library has already been unpacked into
                 * /data/data/com.example.HelloJni/lib/libhello-jni.so at
                 * installation time by the package manager.
                 */
                /**
                 * 在应用程序启动的时候加载hello-jni库.这个库在你的安装这个app的
                 * 时候已经解压放到了/data/data/com.example.HelloJni/lib/libhello-jni.so
                 */
                static {
                    System.loadLibrary("hello-jni");        //本地方法所在的库文件名
                }
            }
        2. 获取jni头文件的方法:
            1. 我们一般会觉得,拿着工程中的.class文件就可以直接获取jni头文件: javah HelloJni,
                经过测试,结果是不行的.
            2. 将HelloJni.class要放在com/example/hellojni文件夹下,在android的工程bin目录下
                是这么放置的,个人猜测是为了得到包名.
            3. 在com目录下的同一级目录下执行: javah com.example.hellojni.HelloJni,这样就可以
                获得文件: com_example_hellojni_HelloJni.h,也就是我们想要的头文件.
    4. 在src目录也是可以直接用javah来获取jni头文件的,尤其是遇到javah 找不到类Android.app.Activity的时候可以一试.
    .
                
    
    五. 解析jni/Android.mk文件:
        1. cat jni/Android.mk
            ......
            /**
             * Android.mk文件,必须在开始就定义LOCAL_PATH变量,指定源文件的目录,
             * my-dir这个宏函数,是由系统提供的,会返回当前文件夹的绝对路径
             */
            LOCAL_PATH := $(call my-dir)
    
            /**
             * CLEAR_VARS是由系统提供的变量,会清空绝大多数的的LOCAL_XXX变量,
             * 但是LOCAL_PATH是一个例外
             */
            include $(CLEAR_VARS)
    
            /**
             * 定义模块名,生成的共享库,会自动加上lib前缀,和.so后缀
             */
            LOCAL_MODULE    := hello-jni
            /**
             * 指定生成模块的所需要的C/C++源文件,不需要列出头文件
             */
            LOCAL_SRC_FILES := hello-jni.c
    
            /**
             * BUILD_SHARED_LIBRARY是由系统提供的变量,这个是用创建出一个动态
             * 共享库的方式,还有一种生成静态库的变量是:BUILD_STATIC_LIBRARY
             */
            include $(BUILD_SHARED_LIBRARY)
    
    六. 解析jni/hello-jni.c文件:
        1. cat jni/hello-jni.c
            ......
            #include <string.h>
            #include <jni.h>
    
            /* This is a trivial JNI example where we use a native method
             * to return a new VM String. See the corresponding Java source
             * file located at:
             *
             *   apps/samples/hello-jni/project/src/com/example/HelloJni/HelloJni.java
             */
            /**
             * 在这个简单的JNI示例中,我们是用了一个本地方法返回一个新的VM字符串
             */
            jstring
            Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
                                                              jobject thiz )
            {
                return (*env)->NewStringUTF(env, "Hello from JNI !");
            }
        2. JNI命名规则:
            1. 前缀:     Java
            2. 类的包名: 上例是---com.example.hellojni
            3. 类名:     上例是---HelloJni
            4. 方法名:   上例是---stringFromJNI
            5. 第一个参数: JNIEnv* env
            6. 第二个参数: jobject thiz
            7. 实际的Java参数: 上例没有
            8. 返回值的参数:   上例没有
        3. 如果第一次写jni函数,尤其是当我们很多时候工作中是复制别人的函数内容的时候,
            很可能会忘记了给自动生成的jni头文件函数声明的参数起名字,您可能回到如下
            错误(这是本人生成另一个共享库犯的低级错误 :) ),错误原因也指出来了:
            APLEX@APLEX-PC /cygdrive/e/android_app/myserial
            $ $NDK/ndk-build
            Android NDK: WARNING: APP_PLATFORM android-18 is larger than android:minSdkVersion 8 in ./AndroidManifest.xml
            [armeabi] Compile thumb  : serialPort <= SerialPort.c
            jni/SerialPort.c: In function 'Java_com_android_aplex_SerialPort_open':
            jni/SerialPort.c:77:3: error: parameter name omitted    ---> 省略了参数名称
               (JNIEnv *, jclass, jstring, jint, jint)
               ^
            jni/SerialPort.c:77:3: error: parameter name omitted
            jni/SerialPort.c:77:3: error: parameter name omitted
            jni/SerialPort.c:77:3: error: parameter name omitted
            jni/SerialPort.c:77:3: error: parameter name omitted
            jni/SerialPort.c: In function 'Java_com_android_aplex_SerialPort_close':
            jni/SerialPort.c:155:3: error: parameter name omitted   ---> 省略了参数名称
               (JNIEnv *, jobject)
               ^
            jni/SerialPort.c:155:3: error: parameter name omitted   ---> 省略了参数名称
            /cygdrive/d/ndk/android-ndk-r10d/build/core/build-binary.mk:455: recipe for target 'obj/local/armeabi/objs/serialPort/SerialPort.o' failed
            make: *** [obj/local/armeabi/objs/serialPort/SerialPort.o] Error 1
  • 相关阅读:
    C# 哈希表
    C# 连接SQL Server数据库的连接字符串<转>
    C# ADO.NET中的五个主要对象<转>
    C# integrated security=SSPI<转>
    C# ADO.NET访问SQL Server数据库<转>
    C# .NET 页面间传值的几种方法<转>
    C# Datatable删除行的Delete和Remove方法
    C# DataTable转json
    CSP2019 爆炸记
    停更通知
  • 原文地址:https://www.cnblogs.com/zengjfgit/p/4441588.html
Copyright © 2011-2022 走看看