Android Studio开发NDK代码

目录

    • 基本环境
    • 演示场景
    • 一、JAVA声明native接口
    • 二、实现native代码
      • 1.生成与java对接的C/C++函数
      • 2.实现自动生成的函数
      • 3.定义编译规则
      • 4. 链接C++动态库到APK包
      • 5. 编译工程按 build project。
    • 三、在机器上执行测试
    • 参考文献

基本环境

  • 开发板:hikey960
  • 代码:aosp,Android R
  • 开发环境:Windows 10 Pro,Android Studio 3.4

演示场景

使用Android studio开发 native代码,通过文件操作函数open()close()write()直接访问LED的设备节点,控制LED的亮灭。本文涉及到的源码我已释放到github上面:https://github.com/LuciferZhu/LedControlNDK,请查阅。

一、JAVA声明native接口

在java中添加如下 native 代码的声明,待会我们将 native 代码输出动态库全名为libled_ndkjni.so,所以在下面这个类中静态区执行System.loadLibrary("led_ndkjni"),从而在 ART 中主动加载该动态库。

/* app\src\main\java\com\example\lowlevel\LedNative.java */
package com.example.lowlevel;

public class LedNative {
    static {
        System.loadLibrary("led_ndkjni");
    }

    public native int openDev();
    public native int closeDev();
    public native int devOn();
    public native int devOff();
}

二、实现native代码

1.生成与java对接的C/C++函数

ART寻找 native 的实现有两种方式:i. 将JNINativeMethod定义的JNI映射表注册到 ART;ii. 寻找方法 JNIEXPORT [返回类型] JNICALL Java_[包名]_[native声明类]_[类中的方法名]。本文介绍方法②的函数名如何生成。
 ① 先在Android studio执行“Make Project”,使其将文件LedNative.java编译生成app\build\intermediates\javac\debug\compileDebugJavaWithJavac\classes\com\example\lowlevelLedNative.class
 ② 在目录app\build\intermediates\javac\debug\compileDebugJavaWithJavac\classes下打开 cmd ,win10的操作方法是先按住Shift按键后,点鼠标右键并点击如下图中的选项。
         Android Studio开发NDK代码_第1张图片
然后执行命令:javah com.example.lowlevel.LedNative如下所示;此操作在app\build\intermediates\javac\debug\compileDebugJavaWithJavac\classes下生成了与LedNative.java对接的native方法头文件com_example_lowlevel_LedNative.h
在这里插入图片描述

2.实现自动生成的函数

 ① 剪切com_example_lowlevel_LedNative.h到新目录LedControlNDK\app\src\main\jni下面,接下来需要实现头文件中的接口。在该目录下新建C++源文件com_example_lowlevel_LedNative.cpp
Android Studio开发NDK代码_第2张图片com_example_lowlevel_LedNative.cpp源码实现如下所示:

/* LedControlNDK\app\src\main\jni\com_example_lowlevel_LedNative.cpp */
#include 
#define LOG_TAG "ledNative.cpp"
#include 

#ifdef __cplusplus
extern "C" {
#endif

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "com_example_lowlevel_LedNative.h"

#define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define ALOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)

static const char *ledDevNode = "/sys/devices/platform/leds/leds/user_led3/brightness";
static int fd;

/*
 * Class:     com_example_lowlevel_LedNative
 * Method:    openDev
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_com_example_lowlevel_LedNative_openDev
  (JNIEnv *, jobject)
{
    ALOGD("------%s", __FUNCTION__);

    fd = open(ledDevNode, O_RDWR);
    if (fd < 0) {
        ALOGE("open: %s", strerror(errno));
        return -1;
    }
    ALOGD("------%s() return", __FUNCTION__);
    return 0;
}

/*
 * Class:     com_example_lowlevel_LedNative
 * Method:    closeDev
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_com_example_lowlevel_LedNative_closeDev
  (JNIEnv *, jobject)
{
    ALOGD("------%s", __FUNCTION__);

    close(fd);
    return 0;
}

/*
 * Class:     com_example_lowlevel_LedNative
 * Method:    devOn
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_com_example_lowlevel_LedNative_devOn
  (JNIEnv *, jobject)
{
    jint ret;
    ALOGD("------%s, fd=%d", __FUNCTION__, fd);

    ret = write(fd, "255", 4);
    if (ret < 0) {
        ALOGE("write: %s", strerror(errno));
        return -1;
    }
    return 0;
}

/*
 * Class:     com_example_lowlevel_LedNative
 * Method:    devOff
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_com_example_lowlevel_LedNative_devOff
  (JNIEnv *, jobject)
{
    jint ret;
    ALOGD("------%s, fd=%d", __FUNCTION__, fd);

    ret = write(fd, "0", 2);
    if (ret < 0) {
        ALOGE("write: %s", strerror(errno));
        return -1;
    }
    return 0;
}

#ifdef __cplusplus
}
#endif

3.定义编译规则

 ① 在目录LedControlNDK\app\src\main\jni新增文件Android.mk,其内容如下:

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE_TAGS := optional
LOCAL_MODULE:= libled_ndkjni
LOCAL_SRC_FILES:= \
    com_example_lowlevel_LedNative.cpp
LOCAL_LDLIBS := -llog
LOCAL_STATIC_LIBRARIES :=
LOCAL_CFLAGS := -Wall -Werror

include $(BUILD_SHARED_LIBRARY)

 ② 在同样的目录下新增文件Application.mk,其内容如下:

APP_ABI := all

4. 链接C++动态库到APK包

如下图所示,点击按钮Link C++ Project with Gradle
           Android Studio开发NDK代码_第3张图片
在弹出的窗口中指定使用ndk-build(需要提前装好ndk工具并指定路径),并指定刚才定义好的Android.mk后按OK
           Android Studio开发NDK代码_第4张图片

5. 编译工程按 build project。

三、在机器上执行测试

  1. 关闭seLinux。通过AS来调试app,它的域名为u:r:untrusted_app:s0,受 selinux 的权限控制,是不允许访问虚拟文件系统sysfs的,所以通过 如下adb命令控制手机 selinux 进入宽容模式。正常生产状态开启 selinux ,要想该app运行正常,需要对该 app 使用 platform key签名,然后配置 selinux 给予platform_app 访问 sysfs文件系统的权限。
hikey960:/ # setenforce 0
  1. 使用Android Studio进行调试:
               在这里插入图片描述
  2. Android机器弹出app主界面如下所示,至此控制 LED 亮灭成功。
    Android Studio开发NDK代码_第5张图片

参考文献

  [1] guaju. Android Studio 生成 so 文件,Your project contains C++ files but it is not using a supported native [EB/OL].简书,2019.03.19

你可能感兴趣的:(Android)