rk3588 Android 12 添加framework层服务,HAL库,从硬件驱动层到上层APP,实现led灯控

发布于:2025-07-23 ⋅ 阅读:(14) ⋅ 点赞:(0)

系列文章目录

rk3588 Android 12 添加framework层服务,HAL库,从硬件驱动层到上层APP,实现led灯控

一、 驱动适配:

1.设备树

kernel-5.10/arch/arm64/boot/dts/rockchip/rk3588_evb1_*.dtsi

	leds_panel {
		compatible = "pwm-leds";
		status = "okay";
		leds-light {
			pwms = <&pwm6 0 15000 0>;
			default-brightness = <2>;
			max-brightness = <100>;
		};
	};
	
	&pwm6 {
		pinctrl-0 = <&pwm6m2_pins>;
	    status = "okay";
	};

kernel-5.10/drivers/leds/leds-pwm.c

static int set_brightness_perms(struct device *dev, 
                               struct led_classdev *lcdev)
{
    struct kobject *kobj = &lcdev->dev->kobj;
    struct attribute *attr = NULL;
    struct kobj_type *ktype;
    int i;
    int err = -ENOENT;
    
    if (!kobj || !kobj->ktype) 
        return err;
    
    ktype = kobj->ktype;
    
    if (ktype->default_attrs) {
        for (i = 0; ktype->default_attrs[i] != NULL; i++) {
            if (strcmp(ktype->default_attrs[i]->name, "brightness") == 0) {
                attr = ktype->default_attrs[i];
                break;
            }
        }
    }
    
    if (attr) {
        err = sysfs_chmod_file(kobj, attr, 0644);
        if (err) {
            dev_dbg(dev, "Failed to set brightness permissions: %d\n", err);
        }
    }
    
    return err;
}

	led_data->pwm = devm_fwnode_pwm_get(dev, fwnode, NULL);
	if (IS_ERR(led_data->pwm))
		return dev_err_probe(dev, PTR_ERR(led_data->pwm),
				     "unable to request PWM for %s\n",
				     led->name);

	if (!fwnode_property_read_u32(fwnode, "default-brightness", &default_brightness)) 
		led_data->cdev.brightness = default_brightness;
	else 
		led_data->cdev.brightness = 1;

  set_brightness_perms(dev, &led_data->cdev);

2.设置文件权限

--- a/device/rockchip/common/rootdir/init.rk30board.rc
+++ b/device/rockchip/common/rootdir/init.rk30board.rc
@@ -125,7 +125,10 @@ on boot
     # backlight
     chown system system /sys/class/backlight/rk28_bl/brightness
     chown system system /sys/class/backlight/backlight/brightness
-    
+
+	#leds-panle
+	chown system system /sys/devices/platform/leds_panel/leds/leds-light/brightness
+	
     # for hdmi

3、开启CONFIG_LEDS_PWM

diff --git a/kernel-5.10/arch/arm64/boot/dts/rockchip/rk3588s.dtsi b/kernel-5.10/arch/arm64/boot/dts/rockchip/rk3588s.dtsi
index b4f9bcc214a..944c4b5345c 100644
--- a/kernel-5.10/arch/arm64/boot/dts/rockchip/rk3588s.dtsi
+++ b/kernel-5.10/arch/arm64/boot/dts/rockchip/rk3588s.dtsi
@@ -5005,7 +5005,7 @@ hdmi0: hdmi@fde80000 {
 		reset-names = "ref", "hdp";
 		power-domains = <&power RK3588_PD_VO1>;
 		pinctrl-names = "default";
-		pinctrl-0 = <&hdmim0_tx0_cec &hdmim0_tx0_hpd &hdmim0_tx0_scl &hdmim0_tx0_sda>;
+		pinctrl-0 = <&hdmim0_tx0_hpd &hdmim0_tx0_scl &hdmim0_tx0_sda>;
 		reg-io-width = <4>;
 		rockchip,grf = <&sys_grf>;
 		rockchip,vo1_grf = <&vo1_grf>;
diff --git a/kernel-5.10/arch/arm64/configs/rockchip_defconfig b/kernel-5.10/arch/arm64/configs/rockchip_defconfig
index 4e943597127..1e8cb97119a 100755
--- a/kernel-5.10/arch/arm64/configs/rockchip_defconfig
+++ b/kernel-5.10/arch/arm64/configs/rockchip_defconfig
@@ -1018,3 +1018,5 @@ CONFIG_BUG_ON_DATA_CORRUPTION=y
 CONFIG_ENABLE_DEFAULT_TRACERS=y
 # CONFIG_RUNTIME_TESTING_MENU is not set
 CONFIG_ROCKCHIP_LT9211=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_PWM=y

二、HAL层

1.引入库

hardware/libhardware/modules/light_panel/Android.bp

// Copyright (C) 2013 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

cc_library_shared {
   
   
    name: "light_panel.default",
    relative_install_path: "hw",
    proprietary: true,
    srcs: ["light_panel.c"],
    cflags: ["-Wall", "-Werror"],
    header_libs: ["libhardware_headers"],
    shared_libs: ["liblog"],
}

hardware/libhardware/modules/light_panel/light_panel.c

/*
 * Copyright (C) 2014, 2017-2018 The  Linux Foundation. All rights reserved.
 * Not a contribution
 * Copyright (C) 2008 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


// #define LOG_NDEBUG 0

#include <errno.h>
#include <malloc.h>
#include <stdint.h>
#include <string.h>
#include <log/log.h>
#include <hardware/light_panel.h>
#include <hardware/hardware.h>
#include <cutils/properties.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>

#include <sys/ioctl.h>
#include <sys/types.h>

char const*const LIGHT_PANEL_BRIGHTNESS_CONTROL
        = "/sys/devices/platform/leds_panel/leds/leds-light/brightness";

static int
write_int(char const* path, int value)
{
   
   
    int fd;
    static int already_warned = 0;
	ALOGD("leds write_int!!!\n");
    fd = open(path, O_WRONLY);
	ALOGD("open file%s\n",strerror(errno));
    if (fd >= 0) {
   
   
        char buffer[20];
        int bytes = snprintf(buffer, sizeof(buffer), "%d\n", value);
        ssize_t amt = write(fd, buffer, (size_t)bytes);
        close(fd);
        return amt == -1 ? -errno : 0;
    } else {
   
   
        if (already_warned == 0) {
   
   
            ALOGE("write_int failed to open %s\n", path);
            already_warned = 0;
        }
        return -errno;
    }
}

/** Close the lights device */
static int
close_led(struct light_panel_device_t *dev)
{
   
   
    if (dev) {
   
   
        free(dev);
    }
    return 0;
}

int set_light_brightness(struct light_panel_device_t* dev,int brightness)
{
   
   
    int err = 0;
    if(!dev) {
   
   
        return -1;
    }
	if(brightness > 255){
   
   
		err = write_int(LIGHT_PANEL_BRIGHTNESS_CONTROL, 255);
	}else if(brightness < 0){
   
   
		err = write_int(LIGHT_PANEL_BRIGHTNESS_CONTROL, 0);
	}else {
   
   
		err = write_int(LIGHT_PANEL_BRIGHTNESS_CONTROL, brightness);
	}
	
    return err;
}

static int light_panel_device_open(const struct hw_module_t* module, const char* name,
	struct hw_device_t** device)
{
   
   
	ALOGD("Hello: light_panel_device_open name = %s",name);

    struct light_panel_device_t *dev = malloc(sizeof(struct light_panel_device_t));
    if(!dev)
        return -ENOMEM;
    memset(dev, 0, sizeof(*dev));

	//HAL must init property
	dev->common.tag= HARDWARE_DEVICE_TAG;
	dev->common.version = 0;
	dev->common.module= (hw_module_t*)module;
	dev->common.close = (int (*)(struct hw_device_t*))close_led;; 
	dev->set_light_brightness= set_light_brightness;
  
	// 
	//*device = (struct hw_device_t*)dev;
	*device = &(dev->common);
	return 0;
}


static struct hw_module_methods_t light_panel_module_methods = {
   
   
    .open = light_panel_device_open  
};

/*
 * The led Module
 */
struct hw_module_t HAL_MODULE_INFO_SYM = {
   
   
    .tag = HARDWARE_MODULE_TAG,
    .version_major = 1,
    .version_minor = 0,
    .id = LIGHT_PANEL_HARDWARE_MODULE_ID,
    .name = "light_panel HAL module",
    .author = "vendor_light_panel, Inc.",
    .methods = &light_panel_module_methods,
};

2.打包hal库

/build/make/target/product/full_base.mk

 #   audio.a2dp.default is a system module. Generic system image includes
 #   audio.a2dp.default to support A2DP if board has the capability.
 PRODUCT_PACKAGES += \
-    audio.a2dp.default
+    audio.a2dp.default \
+	light_panel.default
diff --git a/hardware/libhardware/modules/Android.mk b/hardware/libhardware/modules/Android.mk
index 9d934c5f9ca..eeedc46678e 100644
--- a/hardware/libhardware/modules/Android.mk
+++ b/hardware/libhardware/modules/Android.mk
@@ -1,5 +1,6 @@
 hardware_modules := \
     camera \
     gralloc \
-    sensors
+    sensors \
+    light_panel

三、JNI

/frameworks/base/services/core/jni/com_android_server_LightPanelService.cpp

@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "com_android_server_LightPanelService"
+#include "utils/Log.h"
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <assert.h>
+#include <jni.h>
+#include <nativehelper/JNIHelp.h>
+#include <hardware/light_panel.h>
+#include <hardware/hardware.h>
+
+namespace android  {
+
+    static light_panel_device_t *sLightPanelDevice = NULL;
+
+    static jint set_light_brightness(JNIEnv* env, jobject clazz, jint brightness) {
+        int brightness_val = brightness;
+        ALOGD("Hello JNI: set brightness_val %d to device.", brightness_val);
+        if(!sLightPanelDevice) {
+            ALOGD("Hello JNI: device is not open.");
+            return -1;
+        }
+        sLightPanelDevice->set_light_brightness(sLightPanelDevice,brightness_val);
+        return 0;
+    }
+
+    static inline int light_panel_device_open(const hw_module_t* module, struct light_panel_device_t** device) {
+        return module->methods->open(module, LIGHT_PANEL_HARDWARE_MODULE_ID, (struct hw_device_t**)device);
+		//return module->common.methods->open(&(module->common), LIGHT_PANEL_HARDWARE_MODULE_ID,(struct hw_device_t**)&device));
+    }
+
+    static jint light_panel_init(JNIEnv* env,jobject clazz) {
+		light_panel_module_t* module;
+		ALOGE("Initializing LightPanel HAL...");
+		
+		int ret = hw_get_module(LIGHT_PANEL_HARDWARE_MODULE_ID, (const hw_module_t**)&module);
+		if (ret != 0) {
+			ALOGE("Failed to get HAL module (Error %d). Check device HAL implementation.", ret);
+			return -1;
+		}
+
+		ret = light_panel_device_open(&module->common, &sLightPanelDevice);
+		if (ret != 0) {
+			ALOGE("Failed to open device (Error %d). Verify HAL compatibility.", ret);
+			return -1;
+		}
+
+		ALOGE("LightPanel device initialized successfully.");
+        return 0;
+    }
+
+    static const JNINativeMethod method_table[] = {
+        {"init_native", "()I", (void*)light_panel_init},
+        { "set_light_brightness","(I)I",(void*)set_light_brightness},
+    };
+	
+    int register_android_server_LightPanelService(JNIEnv* env) {
+            return jniRegisterNativeMethods(env, "com/android/server/LightPanelService", method_table, NELEM(method_table));
+    }
+};
diff --git a/frameworks/base/services/core/jni/Android.bp b/frameworks/base/services/core/jni/Android.bp
index 57db80bbc7f..9525d8ef596 100644
--- a/frameworks/base/services/core/jni/Android.bp
+++ b/frameworks/base/services/core/jni/Android.bp
@@ -73,6 +73,7 @@ cc_library_static {
         "com_android_server_sensor_SensorService.cpp",
         "com_android_server_rkdisplay_RkDisplayModes.cpp",
         "com_android_server_audio_RkAudioSetting.cpp",
+		"com_android_server_LightPanelService.cpp",
         "rkbox/rklog.cpp",
         "com_android_server_RKBoxService.cpp",
         "onload.cpp",
diff --git a/frameworks/base/services/core/jni/onload.cpp b/frameworks/base/services/core/jni/onload.cpp
index de3526cf361..a8f47a9cc94 100644
--- a/frameworks/base/services/core/jni/onload.cpp
+++ b/frameworks/base/services/core/jni/onload.cpp
@@ -66,6 +66,7 @@ int register_android_server_sensor_SensorService(JavaVM* vm, JNIEnv* env);
 int register_com_android_server_rkdisplay_RkDisplayModes(JNIEnv* env);
 int register_com_android_server_audio_RkAudioSetting(JNIEnv* env);
 int register_com_android_server_RKBoxManagementService(JNIEnv* env);
+int register_android_server_LightPanelService(JNIEnv* env);
 };
 
 using namespace android;
@@ -125,5 +126,6 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
     register_com_android_server_rkdisplay_RkDisplayModes(env);
     register_com_android_server_audio_RkAudioSetting(env);
     register_com_android_server_RKBoxManagementService(env);
+    register_android_server_LightPanelService(env);
     return JNI_VERSION_1_4;
 }

四、framework层服务添加

1.framework层服务

diff --git a/frameworks/base/Android.bp b/frameworks/base/Android.bp
index a99cef87938..d69d338edcd 100644
--- a/frameworks/base/Android.bp
+++ b/frameworks/base/Android.bp
@@ -496,7 +496,8 @@ metalava_framework_docs_args = "--manifest $(location core/res/AndroidManifest.x
     "--api-lint-ignore-prefix android.icu. " +
     "--api-lint-ignore-prefix java. " +
     "--api-lint-ignore-prefix junit. " +
-    "--api-lint-ignore-prefix org. "
+    "--api-lint-ignore-prefix org. " +
+	"--api-lint-ignore-prefix android. "
 
 packages_to_document = [
     "android",
diff --git a/frameworks/base/core/api/current.txt b/frameworks/base/core/api/current.txt
index 84e8e5e69ce..8556dd63d8e 100644
--- a/frameworks/base/core/api/current.txt
+++ b/frameworks/base/core/api/current.txt
@@ -5378,6 +5378,26 @@ package android.app {
     field public static final int GAME_MODE_UNSUPPORTED = 0; // 0x0
   }
 
+  public interface ILightPanelService extends android.os.IInterface {
+    method public void setLightPanelBrightness(int) throws android.os.RemoteException;
+    field public static final String DESCRIPTOR = "android.app.ILightPanelService";
+  }
+
+  public static class ILightPanelService.Default implements android.app.ILightPanelService {
+    ctor public ILightPanelService.Default();
+    method public android.os.IBinder asBinder();
+    method public void setLightPanelBrightness(int) throws android.os.RemoteException;
+  }
+
+  public abstract static class ILightPanelService.Stub extends android.os.Binder implements android.app.ILightPanelService {
+    ctor public ILightPanelService.Stub();
+    method public android.os.IBinder asBinder();
+    method public static android.app.ILightPanelService asInterface(android.os.IBinder);
+    method public static android.app.ILightPanelService getDefaultImpl();
+    method public boolean onTransact(int, android.os.Parcel, android.os.Parcel, int) throws android.os.RemoteException;
+    method public static boolean setDefaultImpl(android.app.ILightPanelService);
+  }
+
   public class Instrumentation {
     ctor public Instrumentation();
     method public android.os.TestLooperManager acquireLooperManager(android.os.Looper);
@@ -5533,6 +5553,12 @@ package android.app {
     field @Deprecated public android.content.pm.ResolveInfo resolveInfo;
   }
 
+  public class LightPanelManager {
+    ctor public LightPanelManager(android.content.Context, android.app.ILightPanelService);
+    method public static android.app.LightPanelManager getInstance(android.content.Context);
+    method public void setLightPanelBrightness(int);
+  }
+
   @Deprecated public class ListActivity extends android.app.Activity {
     ctor @Deprecated public ListActivity();
     method @Deprecated public android.widget.ListAdapter getListAdapter();
@@ -10658,6 +10684,7 @@ package android.content {
     field public static final String KEYGUARD_SERVICE = "keyguard";
     field public static final String LAUNCHER_APPS_SERVICE = "launcherapps";
     field @UiContext public static final String LAYOUT_INFLATER_SERVICE = "layout_inflater";
+    field public static final String LIGHTPANEL_SERVICE = "lightpanel";
     field public static final String LOCATION_SERVICE = "location";
     field public static final String MEDIA_COMMUNICATION_SERVICE = "media_communication";
     field public static final String MEDIA_METRICS_SERVICE = "media_metrics";
diff --git a/frameworks/base/core/java/android/app/ILightPanelService.aidl b/frameworks/base/core/java/android/app/ILightPanelService.aidl
new file mode 100755
index 00000000000..54b494a73aa
--- /dev/null
+++ b/frameworks/base/core/java/android/app/ILightPanelService.aidl
@@ -0,0 +1,21 @@
+/**
+ * Copyright (c) 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License. HelloService
+ */
+
+package android.app;
+
+interface ILightPanelService {
+   void setLightPanelBrightness(int brightness);
+}
diff --git a/frameworks/base/core/java/android/app/LightPanelManager.java b/frameworks/base/core/java/android/app/LightPanelManager.java
new file mode 100755
index 00000000000..bb0e6ff8300
--- /dev/null
+++ b/frameworks/base/core/java/android/app/LightPanelManager.java
@@ -0,0 +1,44 @@
+package android.app;
+
+import android.annotation.SdkConstant;
+import android.annotation.SystemApi;
+import android.annotation.SystemService;
+import android.os.ServiceManager;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Build;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.app.ILightPanelService;
+import android.util.Log;
+
+
+@SystemService(Context.LIGHTPANEL_SERVICE)
+public class LightPanelManager {
+    private static final String TAG = "LightPanelManager";
+    private final ILightPanelService mService;
+
+    // 公开构造函数,供系统内部使用
+    public LightPanelManager(Context context, ILightPanelService service) {
+        mService = service;
+    }
+
+    // 提供静态获取方法,无需隐藏
+    public static LightPanelManager getInstance(Context context) {
+        ILightPanelService service = ILightPanelService.Stub.asInterface(
+            ServiceManager.getService(Context.LIGHTPANEL_SERVICE)
+        );
+        return new LightPanelManager(context, service);
+    }
+
+    // 公开亮度设置方法
+    public void setLightPanelBrightness(int brightness) {
+        try {
+            mService.setLightPanelBrightness(brightness);
+        } catch (RemoteException e) {
+            throw new RuntimeException("Failed to set brightness", e);
+        }
+    }
+}
+
diff --git a/frameworks/base/core/java/android/app/SystemServiceRegistry.java b/frameworks/base/core/java/android/app/SystemServiceRegistry.java
index 32ea41b2c75..deb8b0fa0c1 100644
--- a/frameworks/base/core/java/android/app/SystemServiceRegistry.java
+++ b/frameworks/base/core/java/android/app/SystemServiceRegistry.java
@@ -47,6 +47,8 @@ import android.app.usage.IUsageStatsManager;
 import android.app.usage.NetworkStatsManager;
 import android.app.usage.StorageStatsManager;
 import android.app.usage.UsageStatsManager;
+import android.app.ILightPanelService;
+import android.app.LightPanelManager;
 import android.apphibernation.AppHibernationManager;
 import android.appwidget.AppWidgetManager;
 import android.bluetooth.BluetoothManager;
@@ -1469,7 +1471,15 @@ public final class SystemServiceRegistry {
                     public DisplayHashManager createService(ContextImpl ctx) {
                         return new DisplayHashManager();
                     }});
-
+        registerService(Context.LIGHTPANEL_SERVICE, LightPanelManager.class,
+                new CachedServiceFetcher<LightPanelManager>() {
+                @Override
+                public LightPanelManager createService(ContextImpl ctx) {
+                    IBinder b = ServiceManager.getService(Context.LIGHTPANEL_SERVICE);
+                    ILightPanelService service = ILightPanelService.Stub.asInterface(b);
+                    return new LightPanelManager(ctx, service);
+                }});
+				
         sInitializing = true;
         try {
             // Note: the following functions need to be @SystemApis, once they become mainline
diff --git a/frameworks/base/core/java/android/content/Context.java b/frameworks/base/core/java/android/content/Context.java
index 913c3b8a33c..02ae318e9e2 100644
--- a/frameworks/base/core/java/android/content/Context.java
+++ b/frameworks/base/core/java/android/content/Context.java
@@ -3728,6 +3728,7 @@ public abstract class Context {
             //@hide: SPEECH_RECOGNITION_SERVICE,
             UWB_SERVICE,
             MEDIA_METRICS_SERVICE,
+			LIGHTPANEL_SERVICE,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @int

网站公告

今日签到

点亮在社区的每一天
去签到