简介
今天来谈谈Android系统service,大家都知道android系统是基于Linux的。只不过是对Linux做了些修改和再封装。在我们android开发当中,各项system service的使用可谓是占了相当大的比例,较为经典的有为4大组件服务的ams、pms、zygote等。了解binder通信以及各种service的功能,对于我们理解android framework有很大帮助。关于binder通信相关的资料,网上可谓是汗牛充栋,大家最好了解下c++,嵌入式编程、linux编程,了解完这个。再去学习会事半功倍,推荐大家看一下韦东山老师的关于Binder通信的视频,讲解的比较详细(非拖)
我们可以在手机shell中,用ps命令查看下运行进程[图片上传中...(image-33c17f-1523686626159-0)]
我这用的是华为荣耀3的机器,看的出来里面的进程比较多,不清楚他们在做系统裁剪的时候做了什么。
在这里我们可以看到zygote进程,这个进程是用来创建android应用进程的,每当我们启动activity和service或者其他组件的时候,一般都会检查这个组件。关于zygote的详细内容可以参考这篇文章以及AMS文章,内容较长但绝对干货。比我写的有价值多了。
我们用命令ps之后,并没有发现与ams、pms的相关进程,这是因为这些服务都是一个叫system_server的进程拉起来的。和它隶属于同一个进程,在我们通过conext.getSystemService()方法拿到这些service的代理类,然后通过Binder与其进行通信。
下面我们说说将服务做成SYSTEM SERVICE的一些好处:
1.因为system_server进程会专门被监控,挂掉的时候会导致zygote自杀,然后系统重启。只要自己添加的service是稳定的,那么这个进程就会一直存在,我们就不用担心服务被干掉之类的。
2.system_server属于system用户,权限略小于root,大于普通用户。这样我们自添加的service拥有较大的权限做一些特殊的事情。
3.android framework启动过程中,service的启动是相当耗时的,因为有扫描应用程序的过程。而有些东西,我们需要在系统启动的时候做,例如启动的时候闪灯。这时候,我们就需要把一些操作放到Linux内核启动的过程中或者android环境启动过程中。Linux内核启动相对较快,综合考虑的话,还是放到android环境启动过程中较好。
坏处就是system service编写和使用都比较麻烦,好在系统为我们提供了利用aidl添加service。下面我们来看看怎么添加service。
一、编写IHelloWorld.aidl,并放到源码frameworks/base/core/java/android/os/ 下面(如果是在ide中写这些代码,注意写完之后编译下项目,否则无法生成相关的stub)
// IHelloWorld.aidl.aidl
package android.os;
// Declare any non-default types here with import statements
interface IHelloWorld {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void printSth(String content);
String getHelloWorld();
}
二、创建Service文件(java),放到源码 frameworks/base/services/core/java/com/android/server/下面
package com.android.server;
import android.os.IHelloWorld;
import android.os.RemoteException;
import android.util.Log;
/**
* Created by 41264 on 07/10/17.
*/
public class HelloWorldService extends IHelloWorld.Stub {
private static final String TAG = HelloWorldService.class.getSimpleName();
@Override
public void printSth(String content) throws RemoteException {
Log.i(TAG, content);
}
@Override
public String getHelloWorld() throws RemoteException {
return "hello world";
}
}
三、将自定义Service加入到SystemServer启动进程,先在 frameworks/base/core/java/android/content/Context.java 中添加一行
public static final String HELLOWORLD_SERVICE="helloworld ";
修改 frameworks/base/services/java/com/android/server/SystemServer.java
在 startOtherServices() 函数 的try模块中增加以下代码
try {
Slog.i(TAG, "helloworld Service");
ServiceManager.addService(Context. HELLOWORLD_SERVICE, new HelloWorldService());
} catch (Throwable e) {
Slog.e(TAG, "Failure starting helloworld Service ", e);
}
四、创建Manager,即HelloWorldManager,并放到frameworks/base/core/java/android/app/ 下
package android.app;
import android.content.Context;
import android.os.IHelloWorld;
import android.os.RemoteException;
/**
* Created by 41264 on 07/10/17.
*/
public class HelloWorldManager {
IHelloWorld mService;
public HelloWorldManager(Context ctx,IHelloWorld service){
mService = service;
}
public void printSth(String content){
try {
mService.printSth(content);
} catch (RemoteException e) {
e.printStackTrace();
}
}
public String getHelloWorld(){
try {
mService.getHelloWorld();
} catch (RemoteException e) {
e.printStackTrace();
}
return null;
}
}
五、注册到SystemService,修改frameworks/base/core/java/android/app/SystemServiceRegistry.java,在静态代码块中增加如下代码
registerService(Context. HELLOWORLD_SERVICE, HelloWorldManager.class,
new CachedServiceFetcher() {
@Override
public HelloWorldManager createService(ContextImpl ctx) {
IBinder b = ServiceManager.getService(Context. HELLOWORLD_SERVICE);
IHelloWorld service = IHelloWorld.Stub.asInterface(b);
return new HelloWorldManager (ctx, service);
}});
六、编译
make update-api 后再重新编译烧录系统(也可编译相应模块Push到系统中去)。
七、测试
有两种方式,一种是将编出来的jar包通过lib方式导入工程。jar包位置:out\target\common\obj\JAVA_LIBRARIES\framework_intermediates\classes.jar。另一种是在自建的app包下创建 HelloWorldManager类,导出Jar包供我们项目依赖。这样开发过程中就不会报错