1.先看driver 驱动层:
新增:kernel/drivers/char/virt_led.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/fs.h>
#include <linux/ioport.h>
#include <linux/miscdevice.h>
#include <linux/ioctl.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <asm/uaccess.h>
static int virt_leds_open(struct inode *inode, struct file *file)
{
pr_info("virt_led: virt_leds_open\n");
return 0;
}
static long virt_leds_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
pr_info("virt_led: virt_leds_ioctl [cmd: %u] [args: %lu]\n", cmd, arg);
return 0;
}
static int virt_leds_release(struct inode *inode, struct file *file)
{
pr_info("virt_led: virt_leds_release\n");
return 0;
}
static const struct file_operations virt_leds_fops = {
.owner = THIS_MODULE,
.open = virt_leds_open,
.unlocked_ioctl = virt_leds_ioctl,
.release = virt_leds_release,
};
static struct miscdevice virt_leds_misc = {
.minor = MISC_DYNAMIC_MINOR,
.fops = &virt_leds_fops,
.name = "virt_led",
};
static int __init virt_leds_init(void)
{
int ret = -1;
ret = misc_register(&virt_leds_misc); //注册字符设备
if(ret < 0){
pr_err("misc register error\n");
return -1;
}
return 0;
}
static void __exit virt_leds_exit(void)
{
misc_deregister(&virt_leds_misc);
}
module_init(virt_leds_init);
module_exit(virt_leds_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("mark wan");
MODULE_DESCRIPTION("virl led driver");
驱动下面Makefile的修改:kernel/drivers/char/Makefile
diff --git a/kernel/drivers/char/Makefile b/kernel/drivers/char/Makefile
index d8a7579300..e59fd309ae 100644
--- a/kernel/drivers/char/Makefile
+++ b/kernel/drivers/char/Makefile
@@ -60,3 +60,5 @@ js-rtc-y = rtc.o
obj-$(CONFIG_TILE_SROM) += tile-srom.o
obj-$(CONFIG_XILLYBUS) += xillybus/
+
+obj-y += virt_led.o
\ No newline at end of file
设备节点权限修改:system/core/rootdir/ueventd.rc
diff --git a/system/core/rootdir/ueventd.rc b/system/core/rootdir/ueventd.rc
index 88e642ae6d..d8f548019b 100644
--- a/system/core/rootdir/ueventd.rc
+++ b/system/core/rootdir/ueventd.rc
@@ -134,3 +134,6 @@ subsystem sound
# DVB API device nodes
/dev/dvb* 0660 root system
+
+# virt led
+/dev/virt_led 0777 root root
\ No newline at end of file
2.hardware层:
新增:hardware/libhardware/modules/led/Android.mk
# hardware/libhardware/modules/led/Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := led.default
LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_C_INCLUDES := hardware/libhardware
LOCAL_SRC_FILES := led_hal.c
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_MULTILIB := 64
LOCAL_MODULE_TAGS := optional
LOCAL_CFLAGS += -Wno-unused-parameter
include $(BUILD_SHARED_LIBRARY)
新增:hardware/libhardware/modules/led/led_hal.c
/*
PATH: hardware/libhardware/modules/led/led_hal.c
*/
#define LOG_TAG "LedHal"
#include <hardware/hardware.h>
#include <cutils/log.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <math.h>
#include <utils/Log.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <hardware/led_hal.h>
static int fd = -1;
static int led_close(struct hw_device_t * device)
{
ALOGI("LED_HAL: led_close\n");
if (fd > 0)
{
close(fd);
}
return 0;
}
static int led_open(struct led_device_t * dev)
{
ALOGI("LED_HAL: led_open\n");
fd = open("/dev/virt_led", O_RDWR);
if (fd < 0)
{
ALOGE("LED_HAL: led_open fail, fd=%d\n", fd);
return -1;
}
return 0;
}
static int led_ctrl(struct led_device_t* dev, int which, int status)
{
int ret = -1;
if (fd > 0)
{
ret = ioctl(fd, which, status);
}
ALOGI(" LED_HAL: ledCtrl: %d, %d, %d", which, status, ret);
return ret;
}
struct led_device_t led_dev = {
.common = {
.tag = HARDWARE_DEVICE_TAG,
.close = led_close,
},
.led_open = led_open,
.led_ctrl = led_ctrl,
};
static int led_device_open(const hw_module_t* module, const char* id,
hw_device_t** device)
{
*device = &led_dev;
return 0;
}
static struct hw_module_methods_t led_module_methods = {
.open = led_device_open,
};
struct hw_module_t HAL_MODULE_INFO_SYM = {
.tag = HARDWARE_MODULE_TAG,
.id = "led",
.methods = &led_module_methods,
};
新增:hardware/libhardware/include/hardware/led_hal.h
#ifndef ANDROID_LED_HARDWARE_H
#define ANDROID_LED_HARDWARE_H
/*
PATH: hardware/libhardware/include/hardware/led_hal.h
*/
#include <stdint.h>
#include <sys/cdefs.h>
#include <sys/types.h>
#include <hardware/hardware.h>
__BEGIN_DECLS
struct led_device_t {
struct hw_device_t common;
int (*led_open)(struct led_device_t* dev);
int (*led_ctrl)(struct led_device_t* dev, int which, int status);
};
__END_DECLS
#endif // ANDROID_LED_HARDWARE_H
添加hardware模块到编译中:hardware/libhardware/modules/Android.mk
diff --git a/hardware/libhardware/modules/Android.mk b/hardware/libhardware/modules/Android.mk
index 462081dce8..7708c0e29d 100644
--- a/hardware/libhardware/modules/Android.mk
+++ b/hardware/libhardware/modules/Android.mk
@@ -10,5 +10,7 @@ hardware_modules := \
usbaudio \
usbcamera \
vehicle \
+ led \
vr
+
include $(call all-named-subdir-makefiles,$(hardware_modules))
生成led.default.so库:build/make/target/product/embedded.mk
diff --git a/build/make/target/product/embedded.mk b/build/make/target/product/embedded.mk
index 4d6bb8b923..ec141b3a85 100644
--- a/build/make/target/product/embedded.mk
+++ b/build/make/target/product/embedded.mk
@@ -34,6 +34,7 @@ PRODUCT_PACKAGES += \
dumpsys \
fastboot \
gralloc.default \
+ led.default \
healthd \
hwservicemanager \
init \
3.framewrok层:
JNI代码:
新增:frameworks/base/services/core/jni/com_android_server_LedService.cpp
#define LOG_TAG "LedJNI"
#include "jni.h"
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"
#include <utils/misc.h>
#include <utils/Log.h>
#include <hardware/led_hal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
namespace android
{
static led_device_t* led_device = nullptr;
jint ledOpen(JNIEnv *env, jobject cls)
{
int err;
hw_module_t * module = nullptr;
hw_device_t * device = nullptr;
ALOGE("JNI_LED ledOpen\n");
/*1. hw_get_module*/
err = hw_get_module("led", (hw_module_t const**)&module);
ALOGE("JNI_LED hw_get_module: %d %p\n", err, module);
if((err == 0) && (nullptr != module)){
/*2. get device: module->methods->open*/
ALOGE("hw_get_module ok\n");
err = module->methods->open(module, NULL, &device);
if (err == 0) {
if (nullptr == device)
{
ALOGE("device is null\n");
return -1;
}
led_device = (led_device_t*)device;
/*3. call led_open*/
return led_device->led_open(led_device);
} else {
return -1;
}
}
return -1;
}
void ledClose(JNIEnv *env, jobject cls)
{
ALOGE("JNI_LED ledClose\n");
}
jint ledCtrl(JNIEnv *env, jobject cls, jint which, jint status)
{
ALOGE("JNI_LED ledCtrl : %d, %d\n", which, status);
if (nullptr == led_device)
{
ALOGE("led_device is nullptr\n");
return -1;
}
return led_device->led_ctrl(led_device, which, status);
}
static const JNINativeMethod method_table[] = {
{"native_ledOpen", "()I", (void *)ledOpen},
{"native_ledClose", "()V", (void *)ledClose},
{"native_ledCtrl", "(II)I", (void *)ledCtrl},
};
int register_android_server_LedService(JNIEnv *env)
{
return jniRegisterNativeMethods(env, "com/android/server/LedService",
method_table, NELEM(method_table));
}
};
JNI编译:frameworks/base/services/core/jni/Android.mk
diff --git a/frameworks/base/services/core/jni/Android.mk b/frameworks/base/services/core/jni/Android.mk
index b44362a6ee..59137cfe3a 100644
--- a/frameworks/base/services/core/jni/Android.mk
+++ b/frameworks/base/services/core/jni/Android.mk
@@ -40,6 +40,7 @@ LOCAL_SRC_FILES += \
$(LOCAL_REL_DIR)/com_android_server_VibratorService.cpp \
$(LOCAL_REL_DIR)/com_android_server_PersistentDataBlockService.cpp \
$(LOCAL_REL_DIR)/com_android_server_GraphicsStatsService.cpp \
+ $(LOCAL_REL_DIR)/com_android_server_LedService.cpp \
$(LOCAL_REL_DIR)/onload.cpp
LOCAL_SRC_FILES += \
JNI注册:frameworks/base/services/core/jni/onload.cpp
diff --git a/frameworks/base/services/core/jni/onload.cpp b/frameworks/base/services/core/jni/onload.cpp
index 4d70384299..866eda12d0 100644
--- a/frameworks/base/services/core/jni/onload.cpp
+++ b/frameworks/base/services/core/jni/onload.cpp
@@ -53,6 +53,7 @@ int register_android_server_SyntheticPasswordManager(JNIEnv* env);
int register_android_server_GraphicsStatsService(JNIEnv* env);
int register_android_hardware_display_DisplayViewport(JNIEnv* env);
int register_com_android_server_rkdisplay_RkDisplayModes(JNIEnv* env);
+int register_android_server_LedService(JNIEnv *env);
};
using namespace android;
@@ -100,6 +101,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
register_android_server_GraphicsStatsService(env);
register_android_hardware_display_DisplayViewport(env);
register_com_android_server_rkdisplay_RkDisplayModes(env);
+ register_android_server_LedService(env);
return JNI_VERSION_1_4;
}
4.framework层:
Aidl:
新增:frameworks/base/core/java/android/os/ILedService.aidl
package android.os;
/** {@hide} */
interface ILedService
{
int ledCtrl(int which, int status);
}
aidl的编译:修改frameworks/base/Android.mk
diff --git a/frameworks/base/Android.mk b/frameworks/base/Android.mk
index 3018c4eb30..7951aa194f 100755
--- a/frameworks/base/Android.mk
+++ b/frameworks/base/Android.mk
@@ -276,6 +276,7 @@ LOCAL_SRC_FILES += \
core/java/android/os/IUpdateLock.aidl \
core/java/android/os/IUserManager.aidl \
core/java/android/os/IVibratorService.aidl \
+ core/java/android/os/ILedService.aidl \
core/java/android/os/storage/IStorageManager.aidl \
core/java/android/os/storage/IStorageEventListener.aidl \
core/java/android/os/storage/IStorageShutdownObserver.aidl \
java接口:
新增:frameworks/base/services/core/java/com/android/server/LedService.java
package com.android.server;
import android.util.Log;
import android.util.Slog;
import android.os.ILedService;
public class LedService extends ILedService.Stub{
private static final String TAG = "LedService";
/*call native C function to access hardware*/
public int ledCtrl(int which, int status) throws android.os.RemoteException{
return native_ledCtrl(which, status);
}
public LedService()
{
Slog.e(TAG, "------------LedService--------------\n");
native_ledOpen();
}
public static native int native_ledOpen();
public static native void native_ledClose();
public static native int native_ledCtrl(int which, int status);
}
System_server中添加服务:修改 frameworks/base/services/java/com/android/server/SystemServer.java
diff --git a/frameworks/base/services/java/com/android/server/SystemServer.java b/frameworks/base/services/java/com/android/server/SystemServer.java
index 0ea9f1766c..21f8f10434 100755
--- a/frameworks/base/services/java/com/android/server/SystemServer.java
+++ b/frameworks/base/services/java/com/android/server/SystemServer.java
@@ -681,6 +681,7 @@ public final class SystemServer {
*/
private void startOtherServices() {
final Context context = mSystemContext;
+ LedService mLedService = null;
VibratorService vibrator = null;
IStorageManager storageManager = null;
NetworkManagementService networkManagement = null;
@@ -796,6 +797,13 @@ public final class SystemServer {
ServiceManager.addService("vibrator", vibrator);
traceEnd();
+ /*-------------------------------------添加ledService--------------------------------------*/
+ traceBeginAndSlog("StartLedService");
+ mLedService = new LedService();
+ ServiceManager.addService("led", mLedService);
+ traceEnd();
+ /*-----------------------------------------------------------------------------------------*/
+
if (!disableConsumerIr) {
traceBeginAndSlog("StartConsumerIrService");
consumerIr = new ConsumerIrService(context);
5.APK编写:
MainActivity.java
//这里是直接使用 ServiceManager
package com.example.ledservice;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.Toast;
import android.os.ServiceManager;
import android.os.ILedService;
public class MainActivity extends AppCompatActivity {
private int button_cnt = 0;
private ILedService iLedService = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
iLedService = ILedService.Stub.asInterface(ServiceManager.getService("led"));
Button button2 = (Button)findViewById(R.id.button2);
button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
button_cnt++;
if (0 == button_cnt % 2) {
try {
iLedService.ledCtrl(0,0);
iLedService.ledCtrl(1,0);
} catch (Exception e){
e.printStackTrace();
}
((Button)view).setText("ALL OFF");
Toast.makeText(MainActivity.this, "ALL LED OFF", Toast.LENGTH_SHORT).show();
} else {
try {
iLedService.ledCtrl(0,1);
iLedService.ledCtrl(1,1);
} catch (Exception e){
e.printStackTrace();
}
((Button)view).setText("ALL ON");
Toast.makeText(MainActivity.this, "ALL LED ON", Toast.LENGTH_SHORT).show();
}
}
});
CheckBox checkbox3 = (CheckBox)findViewById(R.id.checkBox3);
checkbox3.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
if (b) {
try {
iLedService.ledCtrl(0,1);
} catch (Exception e){
e.printStackTrace();
}
Toast.makeText(MainActivity.this, "LED1 on", Toast.LENGTH_SHORT).show();
} else {
try {
iLedService.ledCtrl(0,0);
} catch (Exception e){
e.printStackTrace();
}
Toast.makeText(MainActivity.this, "LED1 off", Toast.LENGTH_SHORT).show();
}
}
});
CheckBox checkbox4 = (CheckBox)findViewById(R.id.checkBox4);
checkbox4.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
if (b) {
try {
iLedService.ledCtrl(1,1);
} catch (Exception e){
e.printStackTrace();
}
Toast.makeText(MainActivity.this, "LED2 on", Toast.LENGTH_SHORT).show();
} else {
try {
iLedService.ledCtrl(1,0);
} catch (Exception e){
e.printStackTrace();
}
Toast.makeText(MainActivity.this, "LED2 off", Toast.LENGTH_SHORT).show();
}
}
});
}
@Override
protected void onDestroy() {
try {
iLedService.ledCtrl(0,0);
iLedService.ledCtrl(1,0);
} catch (Exception e){
e.printStackTrace();
}
super.onDestroy();
}
}
/*
//这里是使用的反射的方式
package com.example.ledservice;
import androidx.appcompat.app.AppCompatActivity;
import android.nfc.Tag;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.Toast;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
//import android.os.ServiceManager;
//import android.os.ILedService;
public class MainActivity extends AppCompatActivity {
private int button_cnt = 0;
//private ILedService iLedService = null;
Object proxy = null;
Method ledCtrl = null;
private static final String TAG = "FanShe";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//iLedService = ILedService.Stub.asInterface(ServiceManager.getService("led"));
//iLedService = getSystemService("Led");
Method getService = null;
try {
getService = Class.forName("android.os.ServiceManager").getMethod("getService",String.class);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
IBinder ledService = null;
try {
ledService = (IBinder) getService.invoke(null,"led");
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
Method asInterface = null;
try {
asInterface = Class.forName("android.os.ILedService$Stub").getMethod("asInterface", IBinder.class);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try {
proxy = asInterface.invoke(null,ledService);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
try {
ledCtrl = Class.forName("android.os.ILedService$Stub$Proxy").getMethod("ledCtrl", int.class, int.class);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Button button2 = (Button)findViewById(R.id.button2);
button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
button_cnt++;
if (0 == button_cnt % 2) {
try {
//iLedService.ledCtrl(0,0);
//iLedService.ledCtrl(1,0);
Log.i(TAG, "ALL OFF: ");
ledCtrl.invoke(proxy, 0, 0);
ledCtrl.invoke(proxy, 1, 1);
} catch (Exception e){
e.printStackTrace();
}
((Button)view).setText("ALL OFF");
Toast.makeText(MainActivity.this, "ALL LED OFF", Toast.LENGTH_SHORT).show();
} else {
try {
//iLedService.ledCtrl(0,1);
//iLedService.ledCtrl(1,1);
Log.i(TAG, "ALL ON: ");
ledCtrl.invoke(proxy, 0, 1);
ledCtrl.invoke(proxy, 1, 1);
} catch (Exception e){
e.printStackTrace();
}
((Button)view).setText("ALL ON");
Toast.makeText(MainActivity.this, "ALL LED ON", Toast.LENGTH_SHORT).show();
}
}
});
CheckBox checkbox3 = (CheckBox)findViewById(R.id.checkBox3);
checkbox3.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
if (b) {
try {
//iLedService.ledCtrl(0,1);
Log.i(TAG, "button2: ");
ledCtrl.invoke(proxy, 0, 1);
} catch (Exception e){
e.printStackTrace();
}
Toast.makeText(MainActivity.this, "LED1 on", Toast.LENGTH_SHORT).show();
} else {
try {
//iLedService.ledCtrl(0,0);
ledCtrl.invoke(proxy, 0, 0);
} catch (Exception e){
e.printStackTrace();
}
Toast.makeText(MainActivity.this, "LED1 off", Toast.LENGTH_SHORT).show();
}
}
});
CheckBox checkbox4 = (CheckBox)findViewById(R.id.checkBox4);
checkbox4.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
if (b) {
try {
//iLedService.ledCtrl(1,1);
ledCtrl.invoke(proxy, 1, 1);
} catch (Exception e){
e.printStackTrace();
}
Toast.makeText(MainActivity.this, "LED2 on", Toast.LENGTH_SHORT).show();
} else {
try {
//iLedService.ledCtrl(1,0);
ledCtrl.invoke(proxy, 1, 0);
} catch (Exception e){
e.printStackTrace();
}
Toast.makeText(MainActivity.this, "LED2 off", Toast.LENGTH_SHORT).show();
}
}
});
}
@Override
protected void onDestroy() {
try {
//iLedService.ledCtrl(0,0);
//iLedService.ledCtrl(1,0);
ledCtrl.invoke(proxy, 0, 0);
ledCtrl.invoke(proxy, 1, 0);
} catch (Exception e){
e.printStackTrace();
}
super.onDestroy();
}
}
*/