软件平台:Android9.0
硬件平台:Mtk8175
近日开发了一个产品需求,APP端需要控制硬件LED灯,由于是多个APP需要调用,固计划将控制接口做成System Service级别的服务,APP可以通过跨进程调用相关的方法,话不多说,开干:
1、在frameworks/base/core/java/android/app/目录添加aidl接口文件,内容如下:
/**
* Lamp brightness controller
*/
package android.app;
interface IGeninLampManager {
String getLampBrightness();
void setLampSwitch(boolean switchOn);
void setLampBrightness(int brightness);
void setLampMode(int mode);
}
2、将该文件引入mk编译:
diff --git a/Android.bp b/Android.bp
index 282206126bc..1c2dadd6624 100644
--- a/Android.bp
+++ b/Android.bp
@@ -105,6 +105,7 @@ java_library {
"core/java/android/app/usage/ICacheQuotaService.aidl",
"core/java/android/app/usage/IStorageStatsManager.aidl",
"core/java/android/app/usage/IUsageStatsManager.aidl",
+ "core/java/android/app/IGeninLampManager.aidl",
":libbluetooth-binder-aidl",
"core/java/android/content/IClipboard.aidl",
"core/java/android/content/IContentService.aidl",
3、创建注册系统级服务:
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 149af262441..4e016d92adb 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -31,6 +31,7 @@ import android.app.usage.IUsageStatsManager;
import android.app.usage.NetworkStatsManager;
import android.app.usage.StorageStatsManager;
import android.app.usage.UsageStatsManager;
+import android.app.GeninLampManager;
import android.appwidget.AppWidgetManager;
import android.bluetooth.BluetoothManager;
import android.companion.CompanionDeviceManager;
@@ -1002,6 +1003,16 @@ public final class SystemServiceRegistry {
}
});
+ registerService(Context.LAMP_MANAGER_SERVICE, GeninLampManager.class,
+ new CachedServiceFetcher<GeninLampManager>() {
+ @Override
+ public GeninLampManager createService(ContextImpl ctx) {
+ IBinder b = ServiceManager.getService(Context.LAMP_MANAGER_SERVICE);
+ IGeninLampManager service = IGeninLampManager.Stub.asInterface(b);
+ return new GeninLampManager(ctx, service);
+ }});
+
+
registerService(Context.SLICE_SERVICE, SliceManager.class,
new CachedServiceFetcher<SliceManager>() {
@Override
4、在frameworks/base/core/java/android/app/目录创建GeninLampManager.java
/**
* Lamp brightness controller
*/
package android.app;
import android.content.Context;
import android.os.RemoteException;
import android.util.Slog;
public class GeninLampManager {
Context mContext;
IGeninLampManager mService;
static final String TAG = "GeninLampManager";
public GeninLampManager(Context context, IGeninLampManager service) {
mContext = context;
mService = service;
if (mService != null)
Slog.d(TAG, " mService not null");
}
public String getLampBrightness() {
if (mService != null) {
try {
//Slog.d(TAG, " Will return getLampBrightness");
return mService.getLampBrightness();
} catch (RemoteException e) {
Slog.d(TAG, "RemoteException " + e);
return null;
}
}
return null;
}
public void setLampSwitch(boolean switchOn) {
if (mService != null) {
try {
//Slog.d(TAG, " Will setLampSwitch======");
mService.setLampSwitch(switchOn);
} catch (RemoteException e) {
Slog.d(TAG, "RemoteException " + e);
}
}
}
public void setLampMode(int mode) {
if (mService != null) {
try {
//Slog.d(TAG, " Will setLampMode======");
mService.setLampMode(mode);
} catch (RemoteException e) {
Slog.d(TAG, "RemoteException " + e);
}
}
}
public void setLampBrightness(int brightness) {
if (mService != null) {
try {
//Slog.d(TAG, " Will setLampBrightness======");
mService.setLampBrightness(brightness);
} catch (RemoteException e) {
Slog.d(TAG, "RemoteException " + e);
}
}
}
}
同aidl文件声明的方法相对应,并实现;
5、在Context.java文件添加Service的注册名称,APP通过这个名称获取远程调用代理:
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 90a94ee7608..1e2328419fe 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -4199,6 +4199,8 @@ public abstract class Context {
*/
public static final String CROSS_PROFILE_APPS_SERVICE = "crossprofileapps";
+ public static final String LAMP_MANAGER_SERVICE = "lampmanager";
+
/**
* Use with {@link #getSystemService} to retrieve a
* {@link android.se.omapi.ISecureElementService}
6、实现Service服务实体类:
frameworks/base/services/core/java/com/android/server/GeninLampManagerService.java:
package com.android.server;
import android.app.IGeninLampManager;
import android.content.Context;
import android.os.Build;
import android.util.Slog;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.FileReader;
import java.io.IOException;
public class GeninLapManagerService extends IGeninLampManager.Stub {
private Context mContext;
static final String TAG = "GeninLampManagerService";
private boolean Debug = false;
private final int LEISURE_MODE = 1;
private final int WRITE_MODE = 2;
private final int NETWORK_MODE = 3;
// 台灯控制节点
static public final String LMAP_SWITCH_PATH = "/sys/bus/i2c/drivers/as9072/3-0011/as9072_debug/power"; //写1关灯,写2开灯
static public final String LMAP_MODE_PATH = "/sys/bus/i2c/drivers/as9072/3-0011/as9072_debug/mode"; //写1 休闲模式;2 书写模式 ,3网课模式
static public final String LMAP_BRIGHTNESS_PATH = "/sys/bus/i2c/drivers/as9072/3-0011/as9072_debug/brightness_level"; //写0x1-0xd 13个亮度级别;
public GeninLampManagerService(Context context) {
mContext = context;
}
@Override
public String getLampBrightness() {
String brightness = null;
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(LMAP_BRIGHTNESS_PATH));
brightness = reader.readLine();
if (Debug) {
Slog.e("======", "read lamp brightness: " + brightness);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(reader != null){
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return brightness;
}
@Override
public void setLampBrightness(int brightness) {
BufferedWriter bufWriter = null;
try {
bufWriter = new BufferedWriter(new FileWriter(LMAP_BRIGHTNESS_PATH));
if (Debug)
Slog.e(TAG,"write brightness:" + String.valueOf(brightness));
bufWriter.write(String.valueOf(brightness));
bufWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void setLampMode(int mode) {
BufferedWriter bufWriter = null;
try {
bufWriter = new BufferedWriter(new FileWriter(LMAP_MODE_PATH));
if (mode == LEISURE_MODE) {
if (Debug)
Slog.e(TAG,"Go to 1 mode.");
bufWriter.write("1");
} else if (mode == WRITE_MODE){
if (Debug)
Slog.e(TAG,"Go to 2 mode.");
bufWriter.write("2");
} else if (mode == NETWORK_MODE) {
if (Debug)
Slog.e(TAG,"Go to 3 mode.");
bufWriter.write("3");
}
bufWriter.close();
} catch (IOException e) {
e.printStackTrace();
Slog.e(TAG,"can't write the " + LMAP_MODE_PATH);
}
}
@Override
public void setLampSwitch(boolean switchOn) {
BufferedWriter bufWriter = null;
try {
bufWriter = new BufferedWriter(new FileWriter(LMAP_SWITCH_PATH));
if (switchOn) {
bufWriter.write("2"); //ON
} else {
bufWriter.write("1"); //OFF
}
bufWriter.close();
} catch (IOException e) {
e.printStackTrace();
Slog.e(TAG,"can't write the " + LMAP_SWITCH_PATH);
}
}
}
7、向SystemServer注册开机启动服务:
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index b5274586d3b..640c141eac1 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -120,6 +120,7 @@ import com.android.server.usage.UsageStatsService;
import com.android.server.vr.VrManagerService;
import com.android.server.webkit.WebViewUpdateService;
import com.android.server.wm.WindowManagerService;
+import com.android.server.GeninLampManagerService;
import com.mediatek.server.MtkSystemServer;
@@ -1261,6 +1262,15 @@ public final class SystemServer {
}
traceEnd();
+ traceBeginAndSlog("StartGeninLampManagerService");
+ try {
+ Slog.i(TAG, "ClassMonitor Service is create");
+ ServiceManager.addService(Context.LAMP_MANAGER_SERVICE, new GeninLampManagerService(context));
+ } catch (Throwable e) {
+ reportWtf("starting ClassMonitorService", e);
+ }
+ traceEnd();
+
traceBeginAndSlog("StartNotificationManager");
mSystemServiceManager.startService(NotificationManagerService.class);
SystemNotificationChannels.createAll(context);
8、返回代码根目录,更新一下api,执行make update-api -j32命令,这个执行完毕,framework/base/api目录的current.txt会更新:
diff --git a/api/current.txt b/api/current.txt
index 65de90fdf8a..fc55efa1b56 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4926,6 +4926,28 @@ package android.app {
field public static final int TRANSIT_UNSET = -1; // 0xffffffff
}
+ public class GeninLampManager {
+ ctor public GeninLampManager(android.content.Context, android.app.IGeninLampManager);
+ method public java.lang.String getLampBrightness();
+ method public void setLampBrightness(int);
+ method public void setLampMode(int);
+ method public void setLampSwitch(boolean);
+ }
+
+ public abstract interface IGeninLampManager implements android.os.IInterface {
+ method public abstract java.lang.String getLampBrightness() throws android.os.RemoteException;
+ method public abstract void setLampBrightness(int) throws android.os.RemoteException;
+ method public abstract void setLampMode(int) throws android.os.RemoteException;
+ method public abstract void setLampSwitch(boolean) throws android.os.RemoteException;
+ }
+
+ public static abstract class IGeninLampManager.Stub extends android.os.Binder implements android.app.IGeninLampManager {
+ ctor public IGeninLampManager.Stub();
+ method public android.os.IBinder asBinder();
+ method public static android.app.IGeninLampManager asInterface(android.os.IBinder);
+ method public boolean onTransact(int, android.os.Parcel, android.os.Parcel, int) throws android.os.RemoteException;
+ }
+
public class Instrumentation {
ctor public Instrumentation();
method public android.os.TestLooperManager acquireLooperManager(android.os.Looper);
@@ -10460,6 +10482,7 @@ package android.content {
field public static final java.lang.String IPSEC_SERVICE = "ipsec";
field public static final java.lang.String JOB_SCHEDULER_SERVICE = "jobscheduler";
field public static final java.lang.String KEYGUARD_SERVICE = "keyguard";
+ field public static final java.lang.String LAMP_MANAGER_SERVICE = "lampmanager";
field public static final java.lang.String LAUNCHER_APPS_SERVICE = "launcherapps";
field public static final java.lang.String LAYOUT_INFLATER_SERVICE = "layout_inflater";
field public static final java.lang.String LOCATION_SERVICE = "location";
到这一步,服务添加流程基本完成;
9、如何使用该服务接口:
在app的类文件导入服务类包名,然后通过servicemanager拿到代理,进行方法调用:
mManager = (GeninLampManager) mContext.getSystemService(Context.LAMP_MANAGER_SERVICE);
mManager.setLampBrightness(bright);
10、这一步至关重要,添加系统服务需要修改selinux规则,否则会无法操作内核的设备节点:
修改device/mediatek/sepolicy/bsp目录对应文件
diff --git a/non_plat/system_server.te b/non_plat/system_server.te
index 6565630..d9f627b 100644
--- a/non_plat/system_server.te
+++ b/non_plat/system_server.te
@@ -136,6 +136,10 @@ hal_client_domain(system_server,hal_dfps)
allow system_server mute_key_file:dir { search read };
allow system_server mute_key_file:file { read open getattr };
+# For system service lamp_mcu permission
+allow system_server mcu_file:dir { search read };
+allow system_server mcu_file:file { read write open getattr };
+
#============= system_server ==============
allow system_server audioserver:file write;
diff --git a/plat_private/service.te b/plat_private/service.te
index d1dcaab..58571c2 100644
--- a/plat_private/service.te
+++ b/plat_private/service.te
@@ -5,3 +5,4 @@
# Other Services
type aal_service, service_manager_type;
type mtk_connmetrics_service, service_manager_type;
+type genin_lamp_service, app_api_service, system_server_service, service_manager_type;
diff --git a/plat_private/service_contexts b/plat_private/service_contexts
index b2b0002..af224f9 100644
--- a/plat_private/service_contexts
+++ b/plat_private/service_contexts
@@ -28,6 +28,7 @@ search_engine_service u:object_r:mtk_search_engine_service:s0
duraspeed u:object_r:mtk_duraspeed_service:s0
FullscreenSwitchService u:object_r:mtk_fullscreen_switch_service:s0
fm_radio_service u:object_r:mtk_fm_radio_service:s0
+lampmanager u:object_r:genin_lamp_service:s0
# Other Services
GoogleOtaBinder u:object_r:ota_agent_service:s0
至此,添加完成~~~欢迎老细和张老师多提宝贵意见!
感谢!