使用Android studio开发 native代码,通过文件操作函数open()
、close()
、write()
直接访问LED的设备节点,控制LED的亮灭。本文涉及到的源码我已释放到github上面:https://github.com/LuciferZhu/LedControlNDK,请查阅。
在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();
}
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
按键后,点鼠标右键并点击如下图中的选项。
然后执行命令:javah com.example.lowlevel.LedNative
如下所示;此操作在app\build\intermediates\javac\debug\compileDebugJavaWithJavac\classes
下生成了与LedNative.java对接的native方法头文件com_example_lowlevel_LedNative.h
① 剪切com_example_lowlevel_LedNative.h
到新目录LedControlNDK\app\src\main\jni
下面,接下来需要实现头文件中的接口。在该目录下新建C++源文件com_example_lowlevel_LedNative.cpp
:
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
① 在目录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
如下图所示,点击按钮Link C++ Project with Gradle
:
在弹出的窗口中指定使用ndk-build
(需要提前装好ndk工具并指定路径),并指定刚才定义好的Android.mk
后按OK
:
u:r:untrusted_app:s0
,受 selinux 的权限控制,是不允许访问虚拟文件系统sysfs
的,所以通过 如下adb命令控制手机 selinux 进入宽容模式。正常生产状态开启 selinux ,要想该app运行正常,需要对该 app 使用 platform key签名,然后配置 selinux 给予platform_app 访问 sysfs文件系统的权限。hikey960:/ # setenforce 0
[1] guaju. Android Studio 生成 so 文件,Your project contains C++ files but it is not using a supported native [EB/OL].简书,2019.03.19