1 定义 AIDL 接口
定义后缀名为 aidl 的接口文件 IAudioService.aidl,然后定义需要的方法,这里就只关注 isMasterMute() 这一个方法。
/frameworks/base/media/java/android/media/IAudioService.aidl
package android.media;
...
/**
* {@hide}
*/
interface IAudioService {
...
boolean isMasterMute();//我们就只关注这一个方法
...
}
2 实现具体的服务并注册
想先看完 audio 服务实现流程的同学,看完 2.1 节就可以到第 3 章了,后面其他小节只是为了展示 binder 服务的不同写法。
2.1 写法一:直接继承 IAudioService.Stub,内部类继承 SystemServer
定义 AudioService.java 直接继承 IAudioService.Stub,然后在该类里实现章节 1 定义的方法。
package com.android.server.audio;
...
import android.media.IAudioService;
/**
* @hide
*/
public class AudioService extends IAudioService.Stub
implements AccessibilityManager.TouchExplorationStateChangeListener,
AccessibilityManager.AccessibilityServicesStateChangeListener {
...
public boolean isMasterMute() {
return AudioSystem.getMasterMute();
}
...
}
服务实现好后,必须要告诉系统,系统才知道有这么一个服务。所以通过 publishBinderService(Context.AUDIO_SERVICE, mService)
将该服务发布出去,第一个参数是我们给该服务起的名字,第二个参数是实现该服务的类实例,也就是 AudioService 对象。
这个 AudioService 是把服务的注册放在了内部类 Lifecycle 中,而 Lifecycle 继承了 SystemService,因为我们要实现的是一个系统服务,必须要继承它才行。
为了不影响阅读的连贯性,publishBinderService
具体实现请看这篇 AIDL 服务的发布 publishBinderService 和 获取 getService,此处我们先知道它能注册一个 binder 服务就行了。
public static final class Lifecycle extends SystemService {
private AudioService mService;
public Lifecycle(Context context) {
super(context);
mService = new AudioService(context);
}
@Override
public void onStart() {
publishBinderService(Context.AUDIO_SERVICE, mService);
}
@Override
public void onBootPhase(int phase) {
if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
mService.systemReady();
}
}
}
2.2 写法二:直接继承 SystemService,内部匿名类创建 IBinder 对象
接着,我们看一下 NotificationManagerService 的写法。
(1)NotificationManagerService 是直接继承自 SystemServer; (2)通过匿名类的方式创建 IBinder 对象,具体实现接口中定义的方法。
/** {@hide} */
public class NotificationManagerService extends SystemService {
...
public void onStart() {
...
publishBinderService(Context.NOTIFICATION_SERVICE, mService, /* allowIsolated= */ false,
DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL);
publishLocalService(NotificationManagerInternal.class, mInternalService);
}
...
@VisibleForTesting
final IBinder mService = new INotificationManager.Stub() {
...
@Override
public void enqueueTextToast(String pkg, IBinder token, CharSequence text, int duration,
int displayId, @Nullable ITransientNotificationCallback callback) {
enqueueToast(pkg, token, text, null, duration, displayId, callback);
}
...
}
}
2.3 写法三:直接继承 .stub,然后用另一个继承自 SystemServer 的类将其发布
这次看一下 AppWidget 相关的 AIDL 服务。
服务的实现类是 AppWidgetServiceImpl.java
package com.android.server.appwidget;
...
class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBackupProvider,
OnCrossProfileWidgetProvidersChangeListener {
...
}
我们发现这个类直接继承了 IAppWidgetService.Stub,实现了一些具体方法。但然后呢?我们发现,它并没有 IBinder 类型的对象,没有继承 SystemServer,也没有发布 binder 服务。
这是怎么一回事,不慌,我们接着看看和它同包下的 AppWidgetService.java 这个类。
[图片上传失败...(image-2e3045-1675841442990)]
注释就首先吸引了我的目光,“SystemService that publishes an IAppWidgetService”。这个继承自 SystemService,组合了一个 AppWidgetServiceImpl 类型的对象,然后将其发布出去。
/**
* SystemService that publishes an IAppWidgetService.
*/ public class AppWidgetService extends SystemService {
private final AppWidgetServiceImpl mImpl;
public AppWidgetService(Context context) {
super(context);
mImpl = new AppWidgetServiceImpl(context);
}
@Override
public void onStart() {
mImpl.onStart();
publishBinderService(Context.APPWIDGET_SERVICE, mImpl);
AppWidgetBackupBridge.register(mImpl);
}
...
}
2.4 服务实现和发布小结
方法的实现一定是在继承了 .Stub 的类中,方法的发布一定是在继承了 SystemServer 的类中,。总共有三种情形:
-
首先是在同一个 Java 类中的情况
-
外部类继承 .Stub,内部类继承 SystemServer,此时 IBinder 对象是外部内的实例。方法的实现在外部类中,发布则在内部类中。这种方法写的比较死,适合整个服务就只实现一个 AIDL 服务的情形。
-
外部类继承 SystemServer,内部类继承 .Stub,此时 IBinder 对象就是内部内的实例。方法实现在内部内中,发布在外部内中。这种写法具有可拓展性,因为可以有多个内部类,所以可以同时发布多个 AIDL 服务。
-
-
然后是写在两个 Java 类中的情况 此时一个 java 类继承自 SystemServer,它的内部必须要维和一个继承了 .Stub 的类对象(也就是 IBinder 对象),这样才能发布相应服务。另一个 java 类继承 .Stub,只用来实现具体方法。同方法 2 一样,这种方法也具有较高的灵活性,当维护多个 IBinder对象时,也就能发布多个 AIDL 服务。
3 将服务封装到 AudioManager
这一层封装是为了方便客户端调用,客户端调用 AudioManager.java 中的方法就跟调用普通类中的方法没什么两样,因为系统已经做好了封装。这步不是必须的,调用 binder 服务的客户端自己也可以做。
看一下,isMasterMute() 这个方法,其实就是直接调用 AIDL 文件中定义的方法,细心的同学可能已经发现 manager 文件是与 .aidl 文件共包的。
package android.media;
...
/**
* AudioManager provides access to volume and ringer mode control.
*/
@SystemService(Context.AUDIO_SERVICE)
public class AudioManager {
...
public boolean isMasterMute() {
final IAudioService service = getService();
try {
return service.isMasterMute(); //直接调用 AIDL 中的方法
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
...
}
有必要关注一下上面代码里的 service
的获取,所以看一下 getService()
方法。
private static IAudioService getService()
{
if (sService != null) {
return sService;
}
IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
sService = IAudioService.Stub.asInterface(b);
return sService;
}
ServiceManager.getService(Context.AUDIO_SERVICE)
:当我们前面通过 publish 方法将服务发布出去后,就可以通过服务名获取该 binder 服务了,返回的是一个 IBinder 对象,getService 的具体实现也请看这篇 AIDL 服务的发布 publishBinderService 和 获取 getService。
IAudioService.Stub.asInterface(b)
:同上一条语句一样,这也是一个固定写法。通过它,我们就能将 IBinder 转化成对应服务的对象了。
4 总结
最后再概括一下, Frameworks 中实现 AIDL 系统服务的步骤:
-
在 IAudioService.aidl 中定义相关方法;
-
在 AudioService.java 中实现具体方法,该类或者其内部类必须要继承 IAudioService.stub,这样才能实例化一个 IBinder 对象;
-
通过 publishBinderService() 将服务发布出去,向系统注册,该方法第二个参数是步骤二中的 IBinder 对象,调用该方法的类要继承了 SystemServer。方法实现和 AIDL 发布的总结见 2.4 节;
-
最后在 AudioManager.java 类里封装好服务,方便客户端使用。这个封装也可以不做,让客户端调用的时候自己实现。
网友评论