目录
一、叙述
二、代码结构以及实现
预置MyAutoSdk和MyAutoService
1、MyAutoSdk
1.1 Android.mk
1.2 IMyAutoService.aidl
1.3 MyAutoManager.java
2 、MyAutoService以及SystemServer拉起服务
2.1 Android.mk
2.2 AndroidManifest.xml
2.3 MyAutoServiceImp.java
2.4 MyAutoService.java
2.5 strings.xml
2.6 SystemServer拉起服务
3、 总结(注意事项)
3.1 服务端的拉起
3.2 服务端的AIDL文件
3.3 ServiceManager.addService的注意
3.4 ServiceManager的addService和getService要一致
3.5 客户端的编译静态库
三、修改Selinux 权限
一、叙述
之所以增加一个系统服务,是因为做安卓定制系统,难免要跟APP的工程师对接接口,所以我们的思路是将APP需要到的接口功能的实现,放在我们创建的服务里边,然后再把这些接口封装在一个管理类可以让APP调用到。
其实系统服务主要是放在 framework /base/service(以及core)下面是比较标准和规范的,但是本人觉得这样子每次给客户更新接口时候都要
make update-api
比较麻烦,所以选择放在 package/app 下面,然后单编就可以了,原理跟在 framework 添加一个服务是完全一样的,只是位置不同而已,放在 package/app 也非常的方便调试。
但是做法可能比较复杂、麻烦。。。
二、代码结构以及实现
新建两个文件夹、分别是 MyAutoSdk、MyAutoService,分别说明以下他们的作用。
MyAutoSdk -------------------里边就是存放 aidl 接口文件和 一个管理类。aidl 里边有实现功能的api,而管理类就是将这些api封装出去给APP调用,跟 WifiManager、AudioManager...都是一样的道理。
我们需将MyAutoSdk编译成一个jar包丢给APP端、APP就可以使用了通过管理类的方法从而调用到api了。
MyAutoService -----------------则是服务端。
如果学习过 AIDL 的基本使用应该都能很好明白上边两个文件夹调用实现的一个过程。
将它们预置进系统是必不可少的。
预置MyAutoSdk和MyAutoService
device/mediatek/mt6765/device.mk
--- a/device/mediatek/mt6765/device.mk
+++ b/device/mediatek/mt6765/device.mk
@@ -322,6 +322,8 @@ PRODUCT_PACKAGES += ipod
PRODUCT_PACKAGES += libipod
PRODUCT_PACKAGES += fuelgauged
PRODUCT_PACKAGES += fuelgauged_nvram
+PRODUCT_PACKAGES += MyAutoSDK
+PRODUCT_PACKAGES += MyAutoService
ifeq ($(MTK_GAUGE_VERSION), 30)
PRODUCT_PACKAGES += libfgauge_gm30
else
1、MyAutoSdk
MyAutoSdk 共有三个文件,如下:
packages/apps/MyAutoSdk/src/main/java/com/example/myautosdk/MyAutoManager.java
packages/apps/MyAutoSdk/src/main/java/com/example/myautosdk/IMyAutoService.aidl
packages/apps/MyAutoSdk/Android.mk
1.1 Android.mk
如果不熟悉mk文件的编写规则、就直接照抄,不要漏任何一项。
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-java-files-under,src/main/java)
LOCAL_SRC_FILES += $(call all-Iaidl-files-under,src/main/java)
LOCAL_MODULE := MyAutoSdk
LOCAL_CERTIFICATE := platform
LOCAL_DX_FLAGS := --core-library
# LOCAL_SDK_VERSION := current
include $(BUILD_STATIC_JAVA_LIBRARY)
1.2 IMyAutoService.aidl
aidl 里边增加了两个api
// IMyAutoService.aidl
package com.example.myautosdk;
// Declare any non-default types here with import statements
interface IMyAutoService {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void setValue( String value );
String getValue();
}
1.3 MyAutoManager.java
管理类。封装 AIDL 里边的api,APP可以通过 管理类里边的方法 从而调用aidl里边的api。
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.example.myautosdk;
import android.content.Context;
import android.os.ServiceManager;
import android.util.Log;
import android.os.RemoteException;
import com.example.myautosdk.IMyAutoService;
public class MyAutoManager {
public static final String TAG = "MyAutoManager";
private static final String SERVER = "com.example.myautoservice.IMyAutoService";
private static MyAutoManager mInstance;
private IMyAutoService mIMyAutoService = IMyAutoService.Stub.asInterface(ServiceManager.getService(SERVER));
public static MyAutoManager getInstance() {
if (mInstance == null) {
mInstance = new MyAutoManager();
}
return mInstance;
}
private IMyAutoService getStub() {
if (null == this.mIMyAutoService) {
this.getNewStub();
}
if (null == this.mIMyAutoService) {
throw new IllegalArgumentException("MyAutoService service doesn't start");
} else if (this.mIMyAutoService.asBinder().isBinderAlive() && this.mIMyAutoService.asBinder().pingBinder()) {
Log.d("MyAutoManager", "MyAutoService.asBinder().isBinderAlive() true");
return this.mIMyAutoService;
} else {
Log.d("MyAutoManager", "MyAutoService.asBinder().isBinderAlive() false");
return this.getNewStub();
}
}
private IMyAutoService getNewStub() {
Log.i("MyAutoManager", "getNewStub() invoked");
this.mIMyAutoService = IMyAutoService.Stub.asInterface(ServiceManager.getService(SERVER));
return this.mIMyAutoService;
}
public void setValue(String value){
try {
getStub().setValue(value);
} catch (RemoteException e) {
e.printStackTrace();
}
}
public String getValue(){
String str = "";
try {
str = getStub().getValue();
} catch (RemoteException e) {
e.printStackTrace();
}
return str;
}
}
2 、MyAutoService以及SystemServer拉起服务
MyAutoService 共有5 个文件,如下:
packages/apps/MyAutoService/src/main/res/values/strings.xml
packages/apps/MyAutoService/src/main/AndroidManifest.xml
packages/apps/MyAutoService/src/main/java/com/example/myautoservice/MyAutoService.java
packages/apps/MyAutoService/src/main/java/com/example/myautosdk/MyAutoServiceImp.java
packages/apps/MyAutoService/Android.mk
2.1 Android.mk
编译成一个apk,不懂 mk 编写规则的直接照抄
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-java-files-under,src/main/java)
LOCAL_MANIFEST_FILE := src/main/AndroidManifest.xml
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/src/main/res
LOCAL_PACKAGE_NAME := MyAutoService
LOCAL_CERTIFICATE := platform
LOCAL_PRIVATE_PLATFORM_APIS = true
# LOCAL_SDK_VERSION := current
LOCAL_PRIVILEGED_MODULE := false
LOCAL_STATIC_JAVA_LIBRARIES += MyAutoSdk
LOCAL_RESOURCE_DIR += prebuilts/sdk/current/support/v7/appcompat/res
LOCAL_RESOURCE_DIR += prebuilts/sdk/current/support/v7/gridlayout/res
LOCAL_AAPT_FLAGS := --auto-add-overlay
LOCAL_AAPT_FLAGS += --extra-packages android.support.v7.appcompat:android.support.v7.gridlayout
include $(BUILD_PACKAGE)
2.2 AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.myautoservice"
coreApp="true"
android:sharedUserId="android.uid.system"
>
<application
android:allowBackup="true"
android:label="@string/app_name"
android:supportsRtl="true"
android:persistent="true"
android:hardwareAccelerated="true"
android:defaultToDeviceProtectedStorage="true"
android:directBootAware="true"
>
<!--receiver
android:name=".MyReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver-->
<service
android:name=".MyAutoService"
android:enabled="true"
android:exported="true" />
</application>
</manifest>
2.3 MyAutoServiceImp.java
实现 aidl 里边的 api 功能
package com.example.myautosdk;
import android.os.RemoteException;
import android.provider.Settings;
import android.content.Context;
import com.example.myautosdk.IMyAutoService;
public class MyAutoServiceImp extends IMyAutoService.Stub {
private Context mContext;
public MyAutoServiceImp(Context context){
mContext = context;
}
@Override
public void setValue(String value) throws RemoteException {
Settings.System.putString( mContext.getContentResolver(), "test" , value );
}
@Override
public String getValue() throws RemoteException {
return Settings.System.getString( mContext.getContentResolver(), "test" );
}
}
2.4 MyAutoService.java
package com.example.myautoservice;
import android.os.ServiceManager;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.content.Context;
import android.os.RemoteException;
import android.util.Log;
import android.provider.Settings;
import java.io.IOException;
import com.example.myautosdk.MyAutoServiceImp;
public class MyAutoService extends Service {
MyAutoServiceImp mMyAutoServiceImp = null;
@Override
public void onCreate() {
super.onCreate();
mMyAutoServiceImp = new MyAutoServiceImp(this);
ServiceManager.addService( "com.example.myautoservice.IMyAutoService",mMyAutoServiceImp);
Log.e("ldq","服务开始");
}
@Override
public IBinder onBind(Intent intent) {
return mMyAutoServiceImp;
}
}
2.5 strings.xml
<resources>
<string name="app_name">MyAutoService</string>
</resources>
2.6 SystemServer拉起服务
frameworks/base/services/java/com/android/server/SystemServer.java
添加两处地方:
... ...
private static void startSystemUi(Context context, WindowManagerService windowManager) {
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.android.systemui",
"com.android.systemui.SystemUIService"));
intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
//Slog.d(TAG, "Starting service: " + intent);
context.startServiceAsUser(intent, UserHandle.SYSTEM);
windowManager.onSystemUiStarted();
}
//add by ldq
private static void startMyAutoService(Context context) {
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.example.myautoservice",
"com.example.myautoservice.MyAutoService"));
Slog.d(TAG, "Starting service: " + intent);
context.startServiceAsUser(intent, UserHandle.SYSTEM);
}
//add by ldq
/// M: NetworkDataController start
private final void startNetworkDataControllerService(Context context) {
if ((SystemProperties.getInt("persist.vendor.sys.disable.moms", 0) != 1) &&
(SystemProperties.getInt("ro.vendor.mtk_mobile_management", 0) == 1)) {
Intent serviceIntent = new Intent("com.mediatek.security.START_SERVICE");
serviceIntent.setClassName("com.mediatek.security.service",
"com.mediatek.security.service.NetworkDataControllerService");
context.startServiceAsUser(serviceIntent, UserHandle.SYSTEM);
}
}
... ...
... ...
traceBeginAndSlog("StartSystemUI");
try {
startSystemUi(context, windowManagerF);
} catch (Throwable e) {
reportWtf("starting System UI", e);
}
traceEnd();
//add by ldq
traceBeginAndSlog("startMyAutoService");
try {
startMyAutoService(context);
} catch (Throwable e) {
reportWtf("starting MyAutoService", e);
}
traceEnd();
//add by ldq
// Enable airplane mode in safe mode. setAirplaneMode() cannot be called
// earlier as it sends broadcasts to other services.
// TODO: This may actually be too late if radio firmware already started leaking
// RF before the respective services start. However, fixing this requires changes
// to radio firmware and interfaces.
if (safeMode) {
traceBeginAndSlog("EnableAirplaneModeInSafeMode");
try {
connectivityF.setAirplaneMode(true);
} catch (Throwable e) {
reportWtf("enabling Airplane Mode during Safe Mode bootup", e);
}
traceEnd();
}
... ...
3、 总结(注意事项)
其实这本质就是一个使用 AIDL 进行跨进程通信的例子,但需要注意以下几点。
3.1 服务端的拉起
刚开始我是使用开机广播、收到开机广播后、在 MyAutoService 服务的 onCreate 里边通过 ServiceManager.addService 把 binder 加入到系统服务中、但是因为开机广播太慢了,有时候安卓系统一开机就要调用到 binder,开机广播根本来不及反应。
所以可以看到我在 AndroidManifest.xml 把开机广播注释掉了,改成了在SystemServer 中拉起该服务。
如果想要在SystemServer中拉起,得在 AndroidManifest.xml 添加以下属性。
coreApp="true"
android:sharedUserId="android.uid.system"
android:persistent="true"
android:hardwareAccelerated="true"
android:defaultToDeviceProtectedStorage="true"
android:directBootAware="true"
3.2 服务端的AIDL文件
写过 AIDL Demo 的都知道服务端和客户端都是需要有 aidl 文件,并且里边的接口要一致。但是我觉得太麻烦(有时候客户要求定制新的接口,在客户端的 aidl 文件里增加了,又得去服务端的 aidl 文件增加进行同步),于是在构建 MyAutoService 的Android.mk文件中,我添加了客户端的依赖。
这样子编译的时候就能实现一个aidl文件两边共用(服务端直接调客户端的 aidl 就好了,无需再创新的aidl)。
LOCAL_STATIC_JAVA_LIBRARIES += MyAutoSdk
3.3 ServiceManager.addService的注意
mk文件中不要使用:
LOCAL_SDK_VERSION := current
否则编译到 ServiceManager.addService 的时候会出错,而应该使用:
LOCAL_PRIVILEGED_MODULE := false
3.4 ServiceManager的addService和getService要一致
这两个方法的参数必须要一致:
ServiceManager.addService的第一个参数是服务的名字,随便起,但getService要和addService保持一致。
比如你填的是 test
ServiceManager.addService("test",xxx)
那么另一边就是
ServiceManager.getService("test")
3.5 客户端的编译静态库
mk文件使用 以下语句编译成静态库:
include $(BUILD_STATIC_JAVA_LIBRARY)
这样子编译出来的 jar 可以被Android Studio解析出类文件来(如下图),使用其他语句编译出来可能是个壳文件,这样子不方便 Android Studio开发APP。
编译出来的jar实在obj下面,可以通过linux命令:
find out/target/product/p22_366_fhd_5m/obj/ -name MyAutoSdk*
结果为:
out/target/product/p22_366_fhd_5m/obj/JAVA_LIBRARIES/MyAutoSdk_intermediates
那么jar包就是在里边了。mv出来
mv out/target/product/p22_366_fhd_5m/obj/JAVA_LIBRARIES/MyAutoSdk_intermediates/javalib.jar .
Android10的好像统一命名为 javalib.jar,其他版本可能不同,反正你去这个文件夹里搜出来 jar 就行了。
三、修改Selinux 权限
当你以为完事的时候、还有Selinux权限是最后一道关卡。
ServiceManager.getService和ServiceManager.addService 这两个引起的avc权限问题:add 和 find的权限(Log找不到了)。
本人加的比较粗糙:
device/mediatek/sepolicy/bsp/plat_private/system_app.te
device/mediatek/sepolicy/bsp/plat_private/untrusted_app.te
system/sepolicy/prebuilts/api/29.0/public/domain.te
system/sepolicy/public/domain.te
diff --git a/device/mediatek/sepolicy/bsp/plat_private/system_app.te b/device/mediatek/sepolicy/bsp/plat_private/system_app.te
index d5dc5aa0a2..1ff6553603 100755
--- a/device/mediatek/sepolicy/bsp/plat_private/system_app.te
+++ b/device/mediatek/sepolicy/bsp/plat_private/system_app.te
@@ -51,3 +51,4 @@ get_prop(system_app, mtk_rsc_sys_prop);
# Purpose: allow to read init.svc.md_monitor property for calling SystemService.waitForState()
# Package Name: com.mediatek.mdmconfig
get_prop(system_app, init_svc_md_monitor_prop)
+allow system_app default_android_service:service_manager add;
\ No newline at end of file
diff --git a/device/mediatek/sepolicy/bsp/plat_private/untrusted_app.te b/device/mediatek/sepolicy/bsp/plat_private/untrusted_app.te
index 0d4d9fd283..ec75b24e60 100755
--- a/device/mediatek/sepolicy/bsp/plat_private/untrusted_app.te
+++ b/device/mediatek/sepolicy/bsp/plat_private/untrusted_app.te
@@ -3,3 +3,4 @@
# Purpose : For hongbao optimization
allow untrusted_app mtk_connmetrics_service:service_manager find;
allow untrusted_app_25 mtk_connmetrics_service:service_manager find;
+allow untrusted_app default_android_service:service_manager find;
diff --git a/system/sepolicy/prebuilts/api/29.0/public/domain.te b/system/sepolicy/prebuilts/api/29.0/public/domain.te
index f348701819..de63ce3a36 100755
--- a/system/sepolicy/prebuilts/api/29.0/public/domain.te
+++ b/system/sepolicy/prebuilts/api/29.0/public/domain.te
@@ -506,7 +506,7 @@ neverallow { domain recovery_only(`userdebug_or_eng(`-fastbootd')') } contextmou
# system_app_service rather than the generic type.
# New service_types are defined in {,hw,vnd}service.te and new mappings
# from service name to service_type are defined in {,hw,vnd}service_contexts.
-neverallow * default_android_service:service_manager add;
+# neverallow * default_android_service:service_manager add;
neverallow * default_android_vndservice:service_manager { add find };
neverallow * default_android_hwservice:hwservice_manager { add find };
diff --git a/system/sepolicy/public/domain.te b/system/sepolicy/public/domain.te
index f348701819..de63ce3a36 100755
--- a/system/sepolicy/public/domain.te
+++ b/system/sepolicy/public/domain.te
@@ -506,7 +506,7 @@ neverallow { domain recovery_only(`userdebug_or_eng(`-fastbootd')') } contextmou
# system_app_service rather than the generic type.
# New service_types are defined in {,hw,vnd}service.te and new mappings
# from service name to service_type are defined in {,hw,vnd}service_contexts.
-neverallow * default_android_service:service_manager add;
+# neverallow * default_android_service:service_manager add;
neverallow * default_android_vndservice:service_manager { add find };
neverallow * default_android_hwservice:hwservice_manager { add find };