Android 安卓自定义系统服务
最近有个需求,要增加系统服务,生成第三方 jar 包提供给第三方应用调用,而且 jar 包必须用特定的包名 ,最后生成的 jar 包不能包含 frameworks 相关代码。
网上搜索了很多资料,搜索结果都没有自定义包名的案例,导出的 jar 也包含了 frameworks
相关代码。最终搜到这篇 博客 ,结合其他博客,最终完成功能
Android 10 自定义系统服务 安卓自定义系统服务 输出jar包
- 该案例基于 rockchip 芯片开发,在 PX30 Android10 上进行的测试,在其他设备上大同小异,请自行查找或替换为对应的路径。
- 实操过程中,可以在 AndroidStudio 中先编写好代码,检查代码中是否有语法错误,然后将代码拷贝到 frameworks 中,最后进行编译。
- 该示例包名为
com.test.customservice
1. 编写代码
1.1 编写 AIDL ITestService.aidl
文件
frameworks/base/test/java/com/test/customservice/ITestService.aidl
package com.test.customservice;
import android.os.Bundle;
interface ITestService {
void setValue(int value);
int getValue();
void setBundle( in Bundle bundle);
Bundle getBundle();
}
1.2 编写服务管理 TestServiceManager.java
文件
frameworks/base/test/java/com/test/customservice/TestServiceManager.java
package com.test.customservice;
import android.content.Context;
import android.os.Bundle;
import android.os.RemoteException;
import android.util.Log;
import com.test.customservice.ITestService;
public class TestServiceManager {
private static final String TAG = "TestServiceManager";
private ITestService iTestService;
public TestServiceManager(Context context, ITestService iTestService) {
this.iTestService = iTestService;
}
public void setValue(int value) {
try {
iTestService.setValue(value);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
}
}
public int getValue() {
try {
return iTestService.getValue();
} catch (RemoteException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
}
return 0;
}
public void setBundle(Bundle bundle) {
try {
iTestService.setBundle(bundle);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
}
}
public Bundle getBundle() {
try {
return iTestService.getBundle();
} catch (RemoteException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
}
return null;
}
}
1.3 编写服务的实现 TestService.java
文件
frameworks/base/services/core/java/com/test/customservice/TestService.java
package com.test.customservice;
import android.os.Bundle;
import android.os.RemoteException;
import android.util.Log;
import android.content.Context;
import com.test.customservice.ITestService;
public class TestService extends ITestService.Stub {
public static final String TAG = "TestService";
private Context mContext;
public TestService(Context context){
this.mContext = context;
}
@Override
public void setValue(int value) throws RemoteException {
Log.i(TAG, "set value is " + value);
}
@Override
public int getValue() throws RemoteException {
Log.i(TAG, "get value is default value 0");
return 0;
}
@Override
public void setBundle(Bundle bundle) throws RemoteException {
Log.i(TAG, "set bundle is " + bundle.toString());
}
@Override
public Bundle getBundle() throws RemoteException {
Bundle bundle = new Bundle();
Log.i(TAG, "get bundle is " + bundle);
return bundle;
}
}
1.4 编写 Android.mk
文件
此文件用于将自定义的 service 生成jar包
frameworks/base/test/Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := test
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-java-files-under, java)
LOCAL_MODULE_CLASS := JAVA_LIBRARIES
include $(BUILD_JAVA_LIBRARY)
1.5 拷贝文件到 frameworks
指定目录
该步骤仅针对先在 AndroidStudio 中创建好 AIDL 和 java 文件的情况;如果你是直接在 frameworks 源码中创建的,请忽略本步骤。
- 拷贝
ITestService.aidl
和TestServiceManager.java
+ 在frameworks/base
目录下创建子目录test/java/com/test/customservice
,
+ 将ITestService.aidl
和TestServiceManager.java
拷贝到frameworks/base/test/java/com/test/customservice
路径下- 拷贝
Android.mk
+ 将Android.mk
拷贝到frameworks/base/test
路径下,用来生成 jar 包,供第三方应用使用- 拷贝
TestService.java
+ 在frameworks/base/services/core/java/
目录下创建子目录com/test/customservice
,
由于frameworks/base/services/core/java/com
目录已经创建,因此相当于在frameworks/base/core/java/com
创建test/customservice
目录即可。
+ 将TestService.java
拷贝到frameworks/base/core/java/com/test/customservice
路径下
2. 配置
2.1 frameworks 引入创建的 AIDL 和 java 代码
编辑 frameworks/base/Android.bp
或者 frameworks/base/Android.mk
文件,配置自定义的 aidl 和 java 文件
java_library {
name: "framework",
srcs: [
"packages/services/PacProcessor/com/android/net/IProxyService.aidl",
"packages/services/Proxy/com/android/net/IProxyCallback.aidl",
"packages/services/Proxy/com/android/net/IProxyPortListener.aidl",
"core/java/android/service/quicksettings/IQSService.aidl",
"core/java/android/service/quicksettings/IQSTileService.aidl",
+ "test/java/**/*.java",
+ "test/java/com/test/customservice/ITestService.aidl",
],
aidl: {
export_include_dirs: [
// From build/make/core/pathmap.mk FRAMEWORK_BASE_SUBDIRS
"core/java",
"graphics/java",
"location/java",
"lowpan/java",
"media/java",
"media/mca/effect/java",
"media/mca/filterfw/java",
"media/mca/filterpacks/java",
"drm/java",
"opengl/java",
"sax/java",
"telecomm/java",
"telephony/java",
"wifi/java",
"keystore/java",
"rs/java",
+ "test/java",
],
}
2.2 编辑 device.mk
将 test 模块编译进 system 中
编辑 device/rockchip/rk3326/PX30_indpx30a/device-common.mk
,增加以下内容
# add test service
PRODUCT_PACKAGES += \
test
# add test service
2.3 将 test 模块加入到 framework
编辑 build/core/pathmap.mk
在 FRAMEWORKS_BASE_SUBDIRS
中增加 test \
FRAMEWORKS_BASE_SUBDIRS := \
$(addsuffix /java, \
core \
graphics \
location \
media \
media/mca/effect \
media/mca/filterfw \
media/mca/filterpacks \
drm \
opengl \
sax \
telecomm \
telephony \
wifi \
lowpan \
keystore \
rs \
+ test \
)
2.4 编辑 Context.java
修改 frameworks/base/core/java/android/content/Context.java
增加 TEST_SERVICE
常量
/**
* Use with {@link #getSystemService(String)} to retrieve a {@link com.test.customservice.TestServiceManager} for test by the system.
*
* @see #getSystemService(String)
* @see com.test.customservice.TestServiceManager
*/
public static final String TEST_SERVICE = "test";
2.5 编辑 SystemServer.java
在 frameworks/base/services/java/com/android/server/SystemServer.java
的 startOtherServices()
方法中中增加服务,注意别漏掉 import 语句
import com.test.customservice.TestService;
***
private void startOtherServices() {
***
traceBeginAndSlog("Start Test Service");
try {
ServiceManager.addService(Context.TEST_SERVICE, new TestService(context));
} catch (Throwable e) {
reportWtf("starting TestService", e);
}
traceEnd();
***
}
2.6 编辑 SystemServiceRegistry.java
注册服务
在 frameworks/base/core/java/android/app/SystemServiceRegistry.java
中注册服务,注意别漏掉 import 语句
import com.test.customservice.ITestService;
import com.test.customservice.TestServiceManager;
***
static {
***
registerService(Context.TEST_SERVICE, TestServiceManager.class,
new CachedServiceFetcher<TestServiceManager>() {
@Override
public TestServiceManager createService(ContextImpl ctx)
throws ServiceNotFoundException {
IBinder b = ServiceManager.getService(Context.TEST_SERVICE);
return new TestServiceManager(ctx,
ITestService.Stub.asInterface(b));
}});
***
}
2.7 编辑 package_whitelist.txt
添加白名单
在 build/make/core/tasks/check_boot_jars/package_whitelist.txt
中最后一行增加
com\.test\.customservice\..*
2.8 编辑 hiddenapi-greylist-packages.txt
添加白名单
在 frameworks/base/config/hiddenapi-greylist-packages.txt
中最后一行增加
***
org.apache.xpath
org.apache.xpath.axes
org.apache.xpath.compiler
org.apache.xpath.domapi
org.apache.xpath.functions
org.apache.xpath.jaxp
org.apache.xpath.objects
org.apache.xpath.operations
org.apache.xpath.patterns
org.apache.xpath.res
org.ccil.cowan.tagsoup
org.ccil.cowan.tagsoup.jaxp
+ com.test.customservice
2.9 配置SELinux
- 在
device/rockchip/common/sepolicy/private/service_contexts
中加一行,其中 test 为frameworks/base/core/java/android/content/Context.java
中增加的TEST_SERVICE
的值
test u:object_r:test_service:s0
- 在
device/rockchip/common/sepolicy/vendor/service.te
中加一行
type test_service, app_api_service, ephemeral_app_api_service, system_server_service, service_manager_type;
3. 编译验证
先执行 make update-api
,然后编译新固件,刷机后开机验证 ,
windows : adb shell service list | findstr "test"
linux : adb shell service list | grep test
如果显示有 test: [com.test.customservice.ITestService]
证明 service 启动成功
4. 集成到应用并调用
自定义服务生成的 jar 包路径为 out/target/common/obj/JAVA_LIBRARIES/test_intermediates/classes.jar
,将其拷贝到 AndroidStudio 工程的 libs
目录,然后右击Add As Library
集成到工程中。
调用示例如下
package com.test.tempserviceclient;
import android.annotation.SuppressLint;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import com.test.customservice.TestServiceManager;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
@SuppressLint("WrongConstant") TestServiceManager testServiceManager = (TestServiceManager) getSystemService("test");
int value = testServiceManager.getValue();
System.out.println(value);
}
}