Adding a Custom Service in Android System
This document describes how to add a custom service to the Android system. This example was implemented on Android 7.0, so code locations may vary on different systems.
1. Design the Interface
Create a new folder named addservice
under the frameworks/base
directory. Inside addservice
, create the following structure:
Android.mk
java/android/mymodule/test
(This path can be customized)
The java/android/mymodule/test
directory will contain the Java interface files and corresponding AIDL files.
The Android.mk
file under frameworks/base/addservice/
should look like this:
1 2 3 4 5 6 7 |
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) |
2. Write the Interface
Create an AIDL file named ITestManager.aidl
under frameworks/base/addservice/java/android/mymodule/test
. This example includes a simple test method:
1 2 3 4 5 6 7 8 9 | package android.mymodule.test; /**
* {@hide}
*/ interface ITestManager { void testMethod(); } |
Create the corresponding TestManager.java
file. TestManager
is an operation class; the actual implementation is in TestService.java
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | package android.mymodule.test; import android.util.Slog; import android.os.RemoteException; public class TestManager { private final ITestManager mService; public TestManager(ITestManager mService) { // Here, ITestManager is passed in. Check other system services for similar implementations. this.mService = mService; } public void testMethod() { try { mService.testMethod(); Slog.i("add_service_test", "TestManager testMethod"); } catch (RemoteException ex) { ex.printStackTrace();
}
}
} |
Create TestService.java
in the frameworks/base/services/core/java/com/android/server/
directory. This directory contains other services like BatteryService
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | package com.android.server; import android.content.Context; import android.util.Slog; import android.mymodule.test.ITestManager; // ITestManager.Stub is a fixed pattern. public class TestService extends ITestManager.Stub { private final Context mContext; public TestService(Context context) { super(); mContext = context;
} public void testMethod() { // Test method. Add a log to check execution. Slog.i("add_service_test", "TestService testMethod"); }
} |
3. Modify Build Files
Since a new directory addservice
was added under frameworks/base
, update /build/core/pathmap.mk
by adding it to FRAMEWORKS_BASE_SUBDIRS
. Add the following line:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
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 \ |
Modify /frameworks/base/Android.mk
. Add these lines:
addservice/java/android/mymodule/test/ITestManager.aidl \
android/mymodule/test
1 2 3 4 5 |
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 \ |
1 2 3 4 5 6 7 |
packages_to_document := \
android \
javax/microedition/khronos \
org/apache/http/conn \
org/apache/http/params
org/apache/http/params \
android/mymodule/test |
Modify alps/build/target/product/base.mk
and alps/build/target/product/generic_no_telephony.mk
to include the module name defined in Android.mk
.
1 2 3 4 5 6 7 8 9 |
--- 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 |
1 2 3 4 5 6 7 8 9 |
--- 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. Add the Service to System Server
In framework/base/services/java/com/android/server/SystemServer.java
, add the service like this:
1 2 3 4 5 6 7 8 9 10 11 |
--- 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"); |
Add Context.TEST_SERVICE
in Context.java
:
1 | public static final String TEST_SERVICE= "test"; |
Register the service in SystemServiceRegistry.java
(or ContextImpl
in older versions):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
--- 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. Security Configuration
Without these modifications, the system may fail to boot due to security issues. The naming must match the Context
definition, converting uppercase to lowercase. The file location may vary.
Add the service to /alps/system/sepolicy/service.te
:
1 2 3 4 5 6 7 |
--- 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; |
Grant service permissions in /external/sepolicy/service_contexts
:
1 2 3 4 5 6 7 |
--- 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 |
With the code modifications complete, proceed to compilation.
6. Compilation
Run make update-api
in the root directory. Compile framework.jar
, then service.jar
, and finally mymodule
. Use mm
for individual module compilation, followed by a full build for verification. Due to the presence of boot.art
and boot.oat
in the out
directory, framework.jar
and service.jar
cannot be pushed for debugging, requiring a full system flash for validation.