【Android】在framework中使用AIDL_android aidl 接口引用


90 import android.media.IAudioService;
187 /**
197 * @hide
198 */
199 public class AudioService extends IAudioService.Stub
200 implements AccessibilityManager.TouchExplorationStateChangeListener,
201 AccessibilityManager.AccessibilityServicesStateChangeListener {

4025 public boolean isMasterMute() {
4026 return AudioSystem.getMasterMute();
4027 }

10525 }


服务实现好后,必须要告诉系统,系统才知道有这么一个服务。所以通过 `publishBinderService(Context.AUDIO_SERVICE, mService)` 将该服务发布出去,第一个参数是我们给该服务起的名字,第二个参数是实现该服务的类实例,也就是 AudioService 对象。


这个 AudioService 是把服务的注册放在了内部类 Lifecycle 中,而 Lifecycle 继承了 **SystemService**,因为我们要实现的是一个系统服务,**必须要继承它**才行。


为了不影响阅读的连贯性,此处我们先知道它能注册一个 binder 服务就行了。



785 public static final class Lifecycle extends SystemService {
786 private AudioService mService;
787
788 public Lifecycle(Context context) {
789 super(context);
790 mService = new AudioService(context);
791 }
792
793 @Override
794 public void onStart() {
795 publishBinderService(Context.AUDIO_SERVICE, mService);
796 }
797
798 @Override
799 public void onBootPhase(int phase) {
800 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
801 mService.systemReady();
802 }
803 }
804 }


### 2.2 写法二:直接继承 SystemService,内部匿名类创建 IBinder 对象


接着,我们看一下 NotificationManagerService 的写法。  
 ![](https://img-blog.csdnimg.cn/f7fe6a0c5b23466d8d0489f444c665a5.png#pic_center)  
 (1)NotificationManagerService 是直接继承自 SystemServer;  
 (2)通过匿名类的方式创建 IBinder 对象,具体实现接口中定义的方法。



334 /** {@hide} /
335 public class NotificationManagerService extends SystemService {

2437 public void onStart() {

2483 publishBinderService(Context.NOTIFICATION_SERVICE, mService, /
allowIsolated= */ false,
2484 DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL);
2485 publishLocalService(NotificationManagerInternal.class, mInternalService);
2486 }
2487

@VisibleForTesting
3176 final IBinder mService = new INotificationManager.Stub() {

3180 @Override
3181 public void enqueueTextToast(String pkg, IBinder token, CharSequence text, int duration,
3182 int displayId, @Nullable ITransientNotificationCallback callback) {
3183 enqueueToast(pkg, token, text, null, duration, displayId, callback);
3184 }

11101 }
11102 }


### 2.3 写法三:直接继承 .stub,然后用另一个继承自 SystemServer 的类将其发布


这次看一下 AppWidget 相关的 AIDL 服务。  
 ![](https://img-blog.csdnimg.cn/7b4f10887df14c64ab3ff0b23d65244f.png#pic_center)


服务的实现类是 AppWidgetServiceImpl.java



17 package com.android.server.appwidget;

146 class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBackupProvider,
147 OnCrossProfileWidgetProvidersChangeListener {

4940 }


我们发现这个类直接继承了 IAppWidgetService.Stub,实现了一些具体方法。但然后呢?我们发现,它并没有 IBinder 类型的对象,没有继承 SystemServer,也没有发布 binder 服务。


这是怎么一回事,不慌,我们接着看看和它同包下的 AppWidgetService.java 这个类。  
 ![](https://img-blog.csdnimg.cn/4d39d3749b134b96bb81dc16d008b683.png#pic_center)


注释就首先吸引了我的目光,“SystemService that publishes an IAppWidgetService”。这个继承自 SystemService,组合了一个 AppWidgetServiceImpl 类型的对象,然后将其发布出去。



27 /**
28 * SystemService that publishes an IAppWidgetService.
29 */
30 public class AppWidgetService extends SystemService {
31 private final AppWidgetServiceImpl mImpl;
32
33 public AppWidgetService(Context context) {
34 super(context);
35 mImpl = new AppWidgetServiceImpl(context);
36 }
37
38 @Override
39 public void onStart() {
40 mImpl.onStart();
41 publishBinderService(Context.APPWIDGET_SERVICE, mImpl);
42 AppWidgetBackupBridge.register(mImpl);
43 }

62 }


### 2.4 服务实现和发布小结


方法的实现一定是在继承了 .Stub 的类中,方法的发布一定是在继承了 SystemServer 的类中,。总共有三种情形:


* 首先是在同一个 Java 类中的情况
	1. 外部类继承 .Stub,内部类继承 SystemServer,此时 IBinder 对象是外部内的实例。方法的实现在外部类中,发布则在内部类中。这种方法写的比较死,适合整个服务就只实现一个 AIDL 服务的情形。
	2. 外部类继承 SystemServer,内部类继承 .Stub,此时 IBinder 对象就是内部内的实例。方法实现在内部内中,发布在外部内中。这种写法具有可拓展性,因为可以有多个内部类,所以可以同时发布多个 AIDL 服务。
* 然后是写在两个 Java 类中的情况 此时一个 java 类继承自 SystemServer,它的内部必须要维和一个继承了 .Stub 的类对象(也就是 IBinder 对象),这样才能发布相应服务。另一个 java 类继承 .Stub,只用来实现具体方法。同方法 2 一样,这种方法也具有较高的灵活性,当维护多个 IBinder对象时,也就能发布多个 AIDL 服务。


## 3 将服务封装到 AudioManager


这一层封装是为了方便客户端调用,客户端调用 AudioManager.java 中的方法就跟调用普通类中的方法没什么两样,因为系统已经做好了封装。这步不是必须的,调用 binder 服务的客户端自己也可以做。


看一下,isMasterMute() 这个方法,其实就是直接**调用 AIDL 文件中定义的方法**,细心的同学可能已经发现 manager 文件是与 .aidl 文件共包的。



/frameworks/base/media/java/android/media/AudioManager.java



17 package android.media;

90 /**
91 * AudioManager provides access to volume and ringer mode control.
92 */
93 @SystemService(Context.AUDIO_SERVICE)
94 public class AudioManager {

1460 public boolean isMasterMute() {
1461 final IAudioService service = getService();
1462 try {
1463 return service.isMasterMute(); //直接调用 AIDL 中的方法
1464 } catch (RemoteException e) {
1465 throw e.rethrowFromSystemServer();
1466 }
1467 }

7837 }


有必要关注一下上面代码里的 `service` 的获取,所以看一下 `getService()` 方法。



808 private static IAudioService getService()
809 {
810 if (sService != null) {
811 return sService;
812 }
813 IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
814 sService = IAudioService.Stub.asInterface(b);
815 return sService;
816 }


`ServiceManager.getService(Context.AUDIO_SERVICE)`:当我们前面通过 publish 方法将服务发布出去后,就可以通过服务名获取该 binder 服务了,返回的是一个 IBinder 对象。


`IAudioService.Stub.asInterface(b)`:同上一条语句一样,这也是一个固定写法。通过它,我们就能将 IBinder 转化成对应服务的对象了。


## 4 总结


最后再概括一下, Frameworks 中实现 AIDL 系统服务的步骤:


1. 在 IAudioService.aidl 中定义相关方法;
2. 在 AudioService.java 中实现具体方法,该类或者其内部类必须要继承 IAudioService.stub,这样才能实例化一个 IBinder 对象;
3. 通过 publishBinderService() 将服务发布出去,向系统注册,该方法第二个参数是步骤二中的 IBinder 对象,调用该方法的类要继承了 SystemServer。方法实现和 AIDL 发布的总结见 2.4 节;
4. 最后在 AudioManager.java 类里封装好服务,方便客户端使用。这个封装也可以不做,让客户端调用的时候自己实现。


最后,如果大伙有什么好的学习方法或建议欢迎大家在评论中积极留言哈,希望大家能够共同学习、共同努力、共同进步。


**小编在这里祝小伙伴们在未来的日子里都可以 升职加薪,当上总经理,出任CEO,迎娶白富美,走上人生巅峰!!**



> 
> 不论遇到什么困难,都不应该成为我们放弃的理由!
> 
> 
> 


很多人在刚接触这个行业的时候或者是在遇到瓶颈期的时候,总会遇到一些问题,比如学了一段时间感觉没有方向感,不知道该从那里入手去学习,需要一份小编整理出来的学习资料的**关注我主页或者点击扫描下方二维码免费领取~**  
 ![](https://img-blog.csdnimg.cn/d645bdf2a4714084b298fca534035c57.png)  
 这里是关于**我自己的Android 学习,面试文档,视频收集大整理**,有兴趣的伙伴们可以看看~


如果你看到了这里,觉得文章写得不错就给个赞呗?如果你觉得那里值得改进的,请给我留言,一定会认真查询,修正不足,谢谢。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值