目录

一、叙述

二、代码结构以及实现

预置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 也非常的方便调试。

但是做法可能比较复杂、麻烦。。。

二、代码结构以及实现

android 开机挂载到 data下 安卓10挂载system模块_xml

新建两个文件夹、分别是 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。 

android 开机挂载到 data下 安卓10挂载system模块_android 开机挂载到 data下_02


编译出来的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 };