Android系统添加一个自己的service

前段时间找工作,被面试官问到这样一个问题,怎样在系统里面添加一个service。我只知道个大概,自己还没有去加过。这次有空,就试着自己添加,并记录下来。我是在android 7.0系统添加的,不同系统代码位置可能会有差异。
1.设计接口
在/frameworks/base目录下新建一个文件夹addservice, 在addservice目录下新建Android.mk和/java/android/mymodule/test, 可以根据自己的需要命名。
/frameworks/base/addservice/java/android/mymodule/test目录下存放封装接口的java文件和对应的aidl文件。
/frameworks/base/addservice/目录下的Android.mk如下:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-java-files-under, java)
LOCAL_MODULE_CLASS := JAVA_LIBRARIES
LOCAL_MODULE := mymodule
include $(BUILD_JAVA_LIBRARY)

下面就是写这个接口了
在/frameworks/base/addservice/java/android/mymodule/test下新建一个aidl文件,命名为ITestManager.aidl,我这里就写一个测试的方法,没什么实际意义,内容为:

package android.mymodule.test;

/**
 * {@hide}
 */

interface ITestManager {
    void testMethod();
}

对应的TestManager.java,TestManager只是一个操作类,真正的实现是在TestService.java:

package android.mymodule.test;
import android.util.Slog;
import android.os.RemoteException;

public class TestManager {

    private final ITestManager mService;

    public TestManager(ITestManager mService) {
        //这里把ITestManager传进来,可以看看系统其它service,都是这样写的
        this.mService = mService;
    }

    public void testMethod() {
        try {
            mService.testMethod();
            Slog.i("add_service_test", "TestManager testMethod");
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }        
    }
}

在frameworks/base/services/core/java/com/android/server/文件夹创建一个TestService.java,这个文件夹有很多的其它service,像BatteryService

package com.android.server;

import android.content.Context;
import android.util.Slog;
import android.mymodule.test.ITestManager;
//这里的ITestManager.Stub是固定写法
public class TestService extends ITestManager.Stub {
    private final Context mContext;

    public TestService(Context context) {
        super();
        mContext = context;
    }
    public void testMethod() {
        // 测试方法,为了测试执行情况,在这里加log
        Slog.i("add_service_test", "TestService testMethod");
    }
 }

由于我们在frameworks/base目录下增加了一个新的目录/addservice, 所以需要在/build/core/pathmap.mk中增加到FRAMEWORKS_BASE_SUBDIRS,注意最后一句,原先是没有的,需要我们自己加:

FRAMEWORKS_BASE_SUBDIRS := \
    $(addsuffix /java, \
        core \
        graphics \
        location \
        media \
        media/mca/effect \
        media/mca/filterfw \
        media/mca/filterpacks \
        drm \
        opengl \
        sax \
        telecomm \
        telephony \
        wifi \
        keystore \
        rs \
        addservice \
     )

/frameworks/base/Android.mk也要修改,
注意增加的这两句:
addservice/java/android/mymodule/test/ITestManager.aidl \
android/mymodule/test

LOCAL_SRC_FILES += \
        core/java/android/service/quicksettings/IQSTileService.aidl \
        telephony/java/com/mediatek/internal/telephony/ITelephonyEx.aidl \
                                                telephony/java/com/mediatek/internal/telephony/ISetDefaultSubResultCallback.aidl \
      addservice/java/android/mymodule/test/ITestManager.aidl \
packages_to_document := \
        android \
        javax/microedition/khronos \
        org/apache/http/conn \
        org/apache/http/params
        org/apache/http/params \
        android/mymodule/test

我加了这里后,编译是没有问题的,但是整体编译时却没有把jar包编出来。后来发现还需要修改alps/build/target/product/base.mk 和 alps/build/target/product/generic_no_telephony.mk,把要编译的模块名写进去,跟自己定义的Android.mk中保持一致

--- a/alps/build/target/product/generic_no_telephony.mk
+++ b/alps/build/target/product/generic_no_telephony.mk
@@ -28,7 +28,8 @@ PRODUCT_PACKAGES := \
     Provision \
     SystemUI \
     EasterEgg \
-    WallpaperCropper
+    WallpaperCropper \
+       mymodule
--- a/alps/build/target/product/generic_no_telephony.mk
+++ b/alps/build/target/product/generic_no_telephony.mk
@@ -28,7 +28,8 @@ PRODUCT_PACKAGES := \
     Provision \
     SystemUI \
     EasterEgg \
-    WallpaperCropper
+    WallpaperCropper \
+       mymodule

把这里加进去,整体编译就没问题了。
4.将新增的service添加到system server.
在/framework/base/services/java/com/android/server/SystemServer.java,addService,像这样:

--- a/alps/frameworks/base/services/java/com/android/server/SystemServer.java
+++ b/alps/frameworks/base/services/java/com/android/server/SystemServer.java
@@ -683,6 +683,12 @@ public final class SystemServer {
             Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);

             mSystemServiceManager.startService(TelecomLoaderService.class);
+             TestService test = new TestService(context);      
+             ServiceManager.addService(Context.TEST_SERVICE, test); 
+             Slog.i("add_service_test", "SystemServer add service");

             traceBeginAndSlog("StartTelephonyRegistry");

这里的Context.TEST_SERVICE ,当然要自己在Context中添加。

 public static final String TEST_SERVICE= "test";

另外,还要在SystemServiceRegistry中注册这一service,注意7.0的代码是这个类,7.0以下的代码可能是ContextImpl这个类:

--- a/alps/frameworks/base/core/java/android/app/SystemServiceRegistry.java
+++ b/alps/frameworks/base/core/java/android/app/SystemServiceRegistry.java
@@ -158,6 +158,11 @@ import com.mediatek.usp.UspManager;

 /**
  * Manages all of the system services that can be returned by {@link Context#getSystemService}.
  * Used by {@link ContextImpl}.
@@ -177,6 +182,17 @@ final class SystemServiceRegistry {
     private SystemServiceRegistry() { }

     static {
+                registerService(Context.TEST_SERVICE,TestManager.class,  
+                new CachedServiceFetcher(){  
+            @Override   
+            public TestManager createService(ContextImpl ctx)  
+            {  
+                IBinder b = ServiceManager.getService(Context.TEST_SERVICE);  
+                Log.i("add_service_test","SystemServiceRegistry registerService method");  
+                return new TestManager(ITestManager.Stub.asInterface(b));  
+            }});  

5.特别注意,如果没有下面这两个修改,编译完了之后,不能正常开机,从log中看到是什么安全问题。
这里的命名跟Context中自己添加的保持一致,把大写改成小写。这个文件在不同的代码中位置可能不一样,有些在device目录下。
将服务加入到源码中,编译备份/alps/system/sepolicy/service.te

--- a/alps/system/sepolicy/service.te
+++ b/alps/system/sepolicy/service.te
@@ -119,3 +119,4 @@ type wifip2p_service, app_api_service, system_server_service, service_manager_ty
 type wifiscanner_service, system_api_service, system_server_service, service_manager_type;
 type wifi_service, app_api_service, system_server_service, service_manager_type;
 type window_service, system_api_service, system_server_service, service_manager_type;
+type test_service, system_api_service, system_server_service, service_manager_type;  

给服务权限
/external/sepolicy/service_contexts

--- a/alps/system/sepolicy/service_contexts
+++ b/alps/system/sepolicy/service_contexts
@@ -144,4 +144,5 @@ wifip2p                                   u:object_r:wifip2p_service:s0
 wifiscanner                               u:object_r:wifiscanner_service:s0
 wifi                                      u:object_r:wifi_service:s0
 window                                    u:object_r:window_service:s0
+test                                      u:object_r:test_service:s0 

至此,添加系统service的代码就写完了,剩下的就是编译了。
6.编译
回到根目录下执行make update-api,否则编译不能通过。先编译framework.jar,然后编译service.jar,最后编译自己加mymodule。可以用mm命令编译,没问题后再整编。因为编译出来的out目录有boot.art和boot.oat,framework.jar和service.jar不能push调试,所以只能刷整包验证。

你可能感兴趣的:(Android系统添加一个自己的service)