环境说明
- ubuntu16.04
- android4.1
- java version “1.6.0_45”
- GNU Make 3.81
- gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.12)
可能有人会问,现在都2024了怎么还在用android4版本,早都过时了。确实,现在最新的都是Android13、Android14了,不过我这里主要是用于demo的演示学习使用,只要整个的流程掌握了,哪个版本的流程都是大同小异;再一个就拿Android13来说,源码100G多非常庞大,代码clone、源码编译都是很慢的,而Android4.1源码才4G多,编译运行就快多了,省时省力。
编写AIDL文件
如果不了解aidl,建议先看看:android AIDL使用demo
仿照系统中现有服务的编写方式,新增服务需要编写aidl接口(也就是提供什么服务),在frameworks/base/core/java/android/helloservice/新建aidl文件,
ICallBack.aidl内容如下
package android.helloservice;
interface ICallBack {
void onReceive(String serverMsg);
}
IHelloService.aidl内容如下
package android.helloservice;
import android.helloservice.ICallBack;
interface IHelloService {
String getHello(String send);
void registerCallback(ICallBack callback);
void unRegisterCallback(ICallBack callback);
}
修改frameworks/base/Android.mk,在LOCAL_SRC_FILES变量中加入新增的aidl文件
## READ ME: ########################################################
##
## When updating this list of aidl files, consider if that aidl is
## part of the SDK API. If it is, also add it to the list below that
## is preprocessed and distributed with the SDK. This list should
## not contain any aidl files for parcelables, but the one below should
## if you intend for 3rd parties to be able to send those objects
## across process boundaries.
##
## READ ME: ########################################################
LOCAL_SRC_FILES += \
core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl \
core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl \
core/java/com/android/internal/widget/IRemoteViewsFactory.aidl \
core/java/com/android/internal/widget/IRemoteViewsAdapterConnection.aidl \
//省略部分
core/java/android/helloservice/ICallBack.aidl \
core/java/android/helloservice/IHelloService.aidl \
执行mmm frameworks/base
单编,编译成功之后会在out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/helloservice/生成如下文件
IHelloService.java内容(androidstudio生成,aosp生成的代码紧凑不方便阅读)
/*
* This file is auto-generated. DO NOT MODIFY.
*/
package android.helloservice;
public interface IHelloService extends android.os.IInterface
{
/** Default implementation for IHelloService. */
public static class Default implements android.helloservice.IHelloService
{
@Override public java.lang.String getHello(java.lang.String send) throws android.os.RemoteException
{
return null;
}
@Override public void registerCallback(android.helloservice.ICallBack callback) throws android.os.RemoteException
{
}
@Override public void unRegisterCallback(android.helloservice.ICallBack callback) throws android.os.RemoteException
{
}
@Override
public android.os.IBinder asBinder() {
return null;
}
}
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements android.helloservice.IHelloService
{
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an android.helloservice.IHelloService interface,
* generating a proxy if needed.
*/
public static android.helloservice.IHelloService asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof android.helloservice.IHelloService))) {
return ((android.helloservice.IHelloService)iin);
}
return new android.helloservice.IHelloService.Stub.Proxy(obj);
}
@Override public android.os.IBinder asBinder()
{
return this;
}
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
java.lang.String descriptor = DESCRIPTOR;
if (code >= android.os.IBinder.FIRST_CALL_TRANSACTION && code <= android.os.IBinder.LAST_CALL_TRANSACTION) {
data.enforceInterface(descriptor);
}
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(descriptor);
return true;
}
}
switch (code)
{
case TRANSACTION_getHello:
{
java.lang.String _arg0;
_arg0 = data.readString();
java.lang.String _result = this.getHello(_arg0);
reply.writeNoException();
reply.writeString(_result);
break;
}
case TRANSACTION_registerCallback:
{
android.helloservice.ICallBack _arg0;
_arg0 = android.helloservice.ICallBack.Stub.asInterface(data.readStrongBinder());
this.registerCallback(_arg0);
reply.writeNoException();
break;
}
case TRANSACTION_unRegisterCallback:
{
android.helloservice.ICallBack _arg0;
_arg0 = android.helloservice.ICallBack.Stub.asInterface(data.readStrongBinder());
this.unRegisterCallback(_arg0);
reply.writeNoException();
break;
}
default:
{
return super.onTransact(code, data, reply, flags);
}
}
return true;
}
private static class Proxy implements android.helloservice.IHelloService
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
@Override public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
@Override public java.lang.String getHello(java.lang.String send) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(send);
boolean _status = mRemote.transact(Stub.TRANSACTION_getHello, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override public void registerCallback(android.helloservice.ICallBack callback) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeStrongInterface(callback);
boolean _status = mRemote.transact(Stub.TRANSACTION_registerCallback, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
@Override public void unRegisterCallback(android.helloservice.ICallBack callback) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeStrongInterface(callback);
boolean _status = mRemote.transact(Stub.TRANSACTION_unRegisterCallback, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_getHello = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_registerCallback = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
static final int TRANSACTION_unRegisterCallback = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
}
public static final java.lang.String DESCRIPTOR = "android.helloservice.IHelloService";
public java.lang.String getHello(java.lang.String send) throws android.os.RemoteException;
public void registerCallback(android.helloservice.ICallBack callback) throws android.os.RemoteException;
public void unRegisterCallback(android.helloservice.ICallBack callback) throws android.os.RemoteException;
}
ICallBack.java内容(androidstudio生成)
/*
* This file is auto-generated. DO NOT MODIFY.
*/
package android.helloservice;
public interface ICallBack extends android.os.IInterface
{
/** Default implementation for ICallBack. */
public static class Default implements android.helloservice.ICallBack
{
@Override public void onReceive(java.lang.String serverMsg) throws android.os.RemoteException
{
}
@Override
public android.os.IBinder asBinder() {
return null;
}
}
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements android.helloservice.ICallBack
{
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an android.helloservice.ICallBack interface,
* generating a proxy if needed.
*/
public static android.helloservice.ICallBack asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof android.helloservice.ICallBack))) {
return ((android.helloservice.ICallBack)iin);
}
return new android.helloservice.ICallBack.Stub.Proxy(obj);
}
@Override public android.os.IBinder asBinder()
{
return this;
}
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
java.lang.String descriptor = DESCRIPTOR;
if (code >= android.os.IBinder.FIRST_CALL_TRANSACTION && code <= android.os.IBinder.LAST_CALL_TRANSACTION) {
data.enforceInterface(descriptor);
}
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(descriptor);
return true;
}
}
switch (code)
{
case TRANSACTION_onReceive:
{
java.lang.String _arg0;
_arg0 = data.readString();
this.onReceive(_arg0);
reply.writeNoException();
break;
}
default:
{
return super.onTransact(code, data, reply, flags);
}
}
return true;
}
private static class Proxy implements android.helloservice.ICallBack
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
@Override public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
@Override public void onReceive(java.lang.String serverMsg) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(serverMsg);
boolean _status = mRemote.transact(Stub.TRANSACTION_onReceive, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_onReceive = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public static final java.lang.String DESCRIPTOR = "android.helloservice.ICallBack";
public void onReceive(java.lang.String serverMsg) throws android.os.RemoteException;
}
编写系统服务
上面aidl是定义服务接口,下面开始编写一个系统服务来实现接口。参考系统服务MountService.java的路径编写frameworks/base/services/java/com/android/server/HelloService.java
package com.android.server;
import android.content.Context;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.util.Log;
import android.helloservice.ICallBack;
import android.helloservice.IHelloService;
public class HelloService extends IHelloService.Stub {
private static final String TAG = "HelloService";
private RemoteCallbackList<ICallBack> callbackList = new RemoteCallbackList();
private Context context;
public HelloService(Context context) {
this.context = context;
Log.d(TAG, "HelloService() init");
}
@Override
public String getHello(String send) throws RemoteException {
Log.d(TAG, "getHello() called with: send = [" + send + "]");
int num = callbackList.beginBroadcast();
for (int i = 0; i < num; i++) {
ICallBack callback = callbackList.getBroadcastItem(i);
if (callback != null) {
callback.onReceive("callback from HelloService with:" + send);
}
}
callbackList.finishBroadcast();
return send + ",server receive ok";
}
@Override
public void registerCallback(ICallBack callback) throws RemoteException {
callbackList.register(callback);
Log.d(TAG, "registerCallback() called with: callback = [" + callback + "]");
}
@Override
public void unRegisterCallback(ICallBack callback) throws RemoteException {
callbackList.unregister(callback);
Log.d(TAG, "unRegisterCallback() called with: callback = [" + callback + "]");
}
}
注册系统服务
所有系统服务都运行在名为 system_server 的进程中,我们也要把服务加入进去。系统中已有很多服务了,我们把它加入到最后,修改frameworks/base/services/java/com/android/server/SystemServer.java
@Override
public void run() {
...省略部分
try {
Slog.i(TAG, "Entropy Mixer");
ServiceManager.addService("entropy", new EntropyMixer());
//HelloService的name必须唯一
Slog.i(TAG, "HelloService");
ServiceManager.addService("HelloService", new HelloService(context));
}
}
执行mmm frameworks/base/services/java/
编译service模块
执行make snod
重新打包system.img
执行emulator
重启模拟器,发现一直停留在重启界面。
无奈,执行make -j30
(本机16核32线程)重编也报错,提示如下
PRODUCT_COPY_FILES device/generic/goldfish/data/etc/apns-conf.xml:system/etc/apns-conf.xml ignored.
Checking API: checkapi-current
target Java: services (out/target/common/obj/JAVA_LIBRARIES/services_intermediates/classes)
out/target/common/obj/PACKAGING/public_api.txt:10084: error 2: Added package android.helloservice
******************************
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.
******************************
根据错误提示执行下面命令
make update-api
make -j30
emulator
模拟器重启成功,且看到HelloService相关日志,说明HelloService服务添加成功。
I/InputManager( 147): Starting input manager
D/PermissionCache( 35): checking android.permission.ACCESS_SURFACE_FLINGER for uid=1000 => granted (1193 us)
I/WindowManager( 147): Enabled StrictMode logging for WMThread's Looper
I/SystemServer( 147): HelloService
D/HelloService( 147): HelloService() init
I/SystemServer( 147): No Bluetooh Service (emulator)
App调用服务
framework层添加服务成功后,app如何使用服务呢?有两种方式,下面一一讲解
方式1:拿到AIDL文件直接访问
为了方便开发,用androidstudio新建一个项目名字就叫Hello。把上面的两个aidl文件复制到项目,保持aidl的包名结构,
MainActivity内容如下,其中ServiceManager会报红不用管,因为等下我们要拷贝项目到aosp源码环境下编译,源码环境下可以正常编过。
package com.hai.hello;
import android.app.Activity;
import android.helloservice.ICallBack;
import android.helloservice.IHelloService;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
import android.view.View;
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
IHelloService mService;
ICallBack.Stub callback = new ICallBack.Stub() {
@Override
public void onReceive(String serverMsg) throws RemoteException {
Log.d(TAG, "onReceive() called with: serverMsg = [" + serverMsg + "]");
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mService = IHelloService.Stub.asInterface(ServiceManager.getService("HelloService"));
Log.d(TAG, "onCreate: " + mService);
try {
mService.registerCallback(callback);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
try {
mService.getHello("client say hello");
} catch (RemoteException e) {
throw new RuntimeException(e);
}
try {
mService.unRegisterCallback(callback);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
}
}
把项目拷贝到packages/experimental/目录下。参考此目录下的其他app的项目结构,移除不要的文件,最终Hello的目录结构如图
Android.mk内容如下
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
#LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_SRC_FILES += aidl/android/helloservice/IHelloService.aidl
LOCAL_SRC_FILES += aidl/android/helloservice/ICallBack.aidl
LOCAL_PACKAGE_NAME := Hello
LOCAL_CERTIFICATE := platform
include $(BUILD_PACKAGE)
执行以下命令单编Hello项目,重启模拟器,
mmm packages/experimental/Hello
make snod
emulator
点击启动app,从日志可以看到Hello app启动成功并和HelloService正确交互了。
方式2:通过getSystemService访问
为了方便开发者使用,我们也提供通用接口context.getSystemService()方式获取服务。仿照AccountManager我们也写一个类就叫HelloManager吧,
frameworks/base/core/java/android/helloservice/HelloManager.java内容如下
package android.helloservice;
import android.content.Context;
import android.helloservice.ICallBack;
import android.helloservice.IHelloService;
import android.os.RemoteException;
import android.util.Log;
public class HelloManager {
private static final String TAG = "HelloManager";
private Context context;
private IHelloService service;
public HelloManager(Context context, IHelloService service) {
this.context = context;
this.service = service;
Log.d(TAG, "HelloManager()");
}
public String getHello(String send) {
try {
return service.getHello(send);
} catch (RemoteException ex) {
throw new RuntimeException(ex);
}
}
public void registerCallback(ICallBack callback) {
try {
service.registerCallback(callback);
} catch (RemoteException ex) {
throw new RuntimeException(ex);
}
}
public void unRegisterCallback(ICallBack callback) {
try {
service.unRegisterCallback(callback);
} catch (RemoteException ex) {
throw new RuntimeException(ex);
}
}
}
HelloManager写好之后需要注册到context中,修改frameworks/base/core/java/android/app/ContextImpl.java如下:
import android.helloservice.IHelloService;
import android.helloservice.HelloManager;
static {
...省略部分
registerService(ACCESSIBILITY_SERVICE, new ServiceFetcher() {
public Object getService(ContextImpl ctx) {
return AccessibilityManager.getInstance(ctx);
}});
registerService("HelloService", new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
IBinder b = ServiceManager.getService("HelloService");
IHelloService service = IHelloService.Stub.asInterface(b);
return new HelloManager(ctx, service);
}});
registerService(ACTIVITY_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
return new ActivityManager(ctx.getOuterContext(), ctx.mMainThread.getHandler());
}});
然后是app使用,这里还是使用Hello项目,修改MainActivity内容如下
package com.hai.hello;
import android.app.Activity;
import android.helloservice.ICallBack;
import android.helloservice.IHelloService;
import android.helloservice.HelloManager;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
import android.view.View;
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
IHelloService mService;
ICallBack.Stub callback = new ICallBack.Stub() {
@Override
public void onReceive(String serverMsg) throws RemoteException {
Log.d(TAG, "onReceive() called with: serverMsg = [" + serverMsg + "]");
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
HelloManager helloManager=(HelloManager) getSystemService("HelloService");
Log.d(TAG, "HelloManager onCreate: " + mService);
helloManager.registerCallback(callback);
helloManager.getHello("client say hello");
helloManager.unRegisterCallback(callback);
}
}
执行下面命令
mmm packages/experimental/Hello/
make update-api
make -j30
emulator
模拟器重启后看到如下日志,说明getSystemService的方式也访问成功。
参考:
Android 添加系统服务的完整流程SystemService
为Android系统的Application Frameworks层增加硬件访问服务
为Android硬件抽象层(HAL)模块编写JNI方法提供Java访问硬件服务接口