一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第21天,点击查看活动详情。
1. 背景
在Robot OS架构设计中我们规划了语音、视觉、运动、指令处理四大核心服务,这些服务会放在framework层,开机后自动启动运行,我们提供SDK与这些服务交互,本文我们分析如何在framework层中增加开机自启动服务。
本文以Android 9.0系统为主。
2. 定义跨进程通信接口
进入到frameworks/base/core/java/android/o
s目录,新增IDemoService.aidl接口定义文件:
package android.os;
interface IDemoService {
void setValue(int val);
int getValue();
}
复制代码
AIDL只支持传输基本java类型数据, 要想传递自定义类, 类需要实现 Parcelable 接口, 如果传递基本类型数组, 需要指定 in out 关键字, 比如 void process(in byte[] input, out byte[] output)
, 用 in 还是 out, 只需要记住: 数组如果作为参数, 通过调用端传给被调端, 则使用 in, 如果数组只是用来接受数据, 实际数据是由被调用端来填充的, 则使用 out。
在frameworks/base
目录,打开Android.mk文件,修改LOCAL_SRC_FILES变量的值,增加IDemoService.aidl源文件:
core/java/android/os/IDemoService.aidl /
复制代码
执行mmm frameworks/base
编译aidl文件,这里在9.0版本会报错:
******************************
You have tried to change the API from what has been previously approved.
To make these errors go away, you have two choices:
1) You can add "@hide" javadoc comments to the methods, etc. listed in the
errors above.
2) You can update current.txt by executing the following command:
make update-api
To submit the revised current.txt to the main Android repository,
you will need approval.
...
复制代码
这里我们直接执行sudo make update-api
再重新编译既可,编译整个base还是有点耗时间。
执行完后会根据IDemoService.aidl生成IDemoService.Stub接口。
3. 实现DemoService
在frameworks/base/services/java/com/android/server
目录,新增DemoService.java文件:
package com.android.server;
import android.content.Context;
import android.os.IDemoService;
import android.util.Slog;
public class DemoService extends IDemoService.Stub {
private static final String TAG = "DemoService";
private int value;
DemoService() {
Log.i(TAG, "DemoSerice init")
}
public void setValueint val) {
this.value = val;
}
public int getValue() {
return value;
}
};
复制代码
DemoService什么也没干,只是维护了一个int型变量,可供APP侧获取或者赋值。
修改同目录的SystemServer.java文件,在ServerThread::run函数中增加加载DemoService的代码:
@Override
public void run() {undefined
......
try {undefined
Slog.i(TAG, "DiskStats Service");
ServiceManager.addService("diskstats", new DiskStatsService(context));
} catch (Throwable e) {undefined
Slog.e(TAG, "Failure starting DiskStats Service", e);
}
try {
Slog.i(TAG, "Demo Service");
ServiceManager.addService("hello", new DemoService());
} catch (Throwable e) {
Slog.e(TAG, "Failure starting Demo Service", e);
}
......
复制代码
调用我们的编译打包命令编译出镜像头,烧制到设备,开机后就可以看到我们的Demo Service
和DemoSerice init
的日志了。
4. 验证接口
我们自己创建一个Android工程,里面实现一个acitivity,通过导包:import android.os.IDemoService;
后,可以通过:
IDemoService demoService = IDemoService.Stub.asInterface(
ServiceManager.getService("demo"));
复制代码
来获取DemoService,然后通过IDemoService多态来调用get和set方法。
5. 其他实现方式
首先,我们可以不修改android.os包,而是把IDemoService.Stub的库封装到SDK供APP使用,或者通过修改Context,在Context中提供获取DemoService的接口。
其次,我们可以做成一个单独的APK,内置到系统,开机启动并提供服务。
6. 总结
本文提供了framework层添加系统服务的方式,主要是介绍修改代码的位置,后续我们基于这个思路实现我们架构设计中规划的四个核心服务,并提供SDK供APP层调用。