android service
android系统服务
android自定义服务添加
安卓系统服务添加、
自己的服务进程添加
这时间的工作,涉及到androd framework层的问题,客户总是有各种奇葩问题已经各自服务要求。
虽然在系统启动最初此,init.rc的时候,我们加入我们自己的config程序(一个c写层可执行程序,跟着系统一起编译到系统中),可以做一些c语言的配置或者做成服务后台一直运行。
但是,毕竟只是一个可执行程序,而且是c写的,即便做成服务,和java framework层通信也诸多不便。
于是我想直接在android做一个service。刚刚好这两天有点时间,赶紧做起来。
我的平台和环境是:
rk3399,
android 7.1
ubuntu 14.04 deskop
先在网上搜索一下相关资料:
https://blog.csdn.net/qq_32072451/article/details/78140251
这个仁兄写的就非常明晰,而且做过androi,刚刚接触framework的一看就基本了解。下面开始参考他的做法做一遍。
在/frameworks/base目录下新建一个文件夹wqservice,在wqservice目录下新建Android.mk和/java/android/wqmodule/test,可以根据自己的需要命名。
在/frameworks/base/wqservice/java/android/wqmodule/test目录下存放封装接口的java文件和对应的aidl文件。也就是java文件和aidl文件都丢那里就可以了。
先在/frameworks/base/wqservice/目录下的新建一个makefile文件: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 := wqmodule
include $(BUILD_JAVA_LIBRARY)
下面就是写这个接口,android的接口描述是aidl文件:
关于aidl文件,如不了解,请参考:
https://www.jianshu.com/p/d1fac6ccee98
在/frameworks/base/wqservice/java/android/wqmodule/test下新建一个aidl文件,命名为ITestManager.aidl,我这里就写一个测试的方法,没什么实际意义,内容为:
package android.wqmodule.test;
/**
* {@hide}
*/
interface ITestManager {
void testMethod();
}
对应的TestManager.java,TestManager只是一个操作类,真正的实现是在TestService.java, 所以在同样的文件夹下面,新建一个TestService.java,内容如下:
package android.wqmodule.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.wqmodule.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目录下增加了一个新的目录/wqservice, 所以需要在/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 \
wqservice \
)
/frameworks/base/Android.mk也要修改, 注意增加的这两句(红色字体):
wqservice/java/android/wqmodule/test/ITestManager.aidl \
android/wqmodule/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
wqservice/java/android/wqmodule/test/ITestManager.aidl
…
…
…
packages_to_document :=
android
javax/microedition/khronos
org/apache/http/conn
org/apache/http/params
org/apache/http/params
android/wqmodule/test
我加了这里后,编译是没有问题的,但是整体编译时却没有把jar包编出来。
还需要修改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 \
PRODUCT_PACKAGES +=
20-dns.conf
95-configured
…
…
wm
+ wqmodule
把这里加进去,整体编译就没问题了。
在/framework/base/services/java/com/android/server/SystemServer.java,wqService,像这样:
--- 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中添加。
gedit ./system/sepolicy/service_contexts
添加如下定义,决定系统中看到的服务名称:
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
//注意,在要引入头类和包,路径名称如下:
+ import android.wqmodule.test.TestManager;
+ import android.wqmodule.test.ITestManager;
...
...
...
@@ -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));
+ }});
特别注意,如果没有下面这两个修改,编译完了之后,不能正常开机,从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;
给服务权限:
gedit /external/sepolicy/service_contexts
或者:
gedit ./system/sepolicy/service_contexts
上面的文件路径可能二选一,因为有些版本的android系统,不是相同路径,我的android 7.1路径是system/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
在文件最底下,加入下面的test服务,这个test后面可以在adb shell中看到,名字就是test。
至此,添加系统service的代码就写完了,剩下的就是编译了。
回到anndroid源码根目录下,先执行make update-api,不能直接make,否则编译不能通过。
重新编译一席android的时间很长,可以。先编译framework.jar,然后编译service.jar,最后编译自己加wqmodule。可以用mm/mmm命令编译,没问题后再整编,由于是不是库也不是可执行文件,不能adb push去更新文件验证,每次都只能刷整包验证。
查看logcat,是否运行:
logcat|grep "add_service_test"
用service list命令查看:
service list|grep wq[ 1949.320288]
test: [android.wqmodule.test.ITestManager]
从上面的信息可以知道,我们已经成功的在android系统中写入字节的服务程序,名字为test,service已经在后台运行,我们可以愉快的进行服务操作或者对各种客户需求进行定制修改了。