概述
AIDL是android接口定义语言,可以利用它定义客户端与服务端进行进程间通信 (IPC) 时都认可的编程接口。跨进程通信,不同的进程,运行在不同的VM虚拟机上,每个进程都有独立的内存空间,管理各自的数据,就像“我住长江头,君住长江尾。日日思君不见君,共饮长江水”。AIDL就是“我”与“君”沟通的桥梁。
关键词
Binder
AIDL:
序列化
Stub类: 字面上的翻译是存根的意思.
Proxy类:字面上的翻译是代理的意思.Stub的内部代理类Proxy。
Transaction:字面上的翻译是交易合同合约的意思.
AIDL机制的核心是对aidl文件进行编译后的编译中间件java文件,上述原理图中都是在该java文件中实现,因此分析AIDL机制的重点放在对此文件的分析中.
AIDL通讯为双工,双向通讯,但还是要分为服务端和客户端两个方面:
服务端的工作:
a) 创建一个Service用来监听客户端的连接请求
b) 创建一个AIDL文件,将暴露给客户端的接口在这个AIDL文件中声明
c) 在Service中实现AIDL中定义的接口
客户端工作:
a)绑定服务端
b) 绑定成功后,将服务端返回的Binder对象转成AIDL接口所属类型
c) 调用服务端接口
使用AIDL时需要注意以下几点: 参考
1、当非跨进程时(在Manifest没有指定process属性),当客户端调用AIDL方法时,客户端在UI线程,那么被调用的服务端的方法也在UI线程。反之。如果。客户端调用AIDL方法时,客户端在非UI线程,那么被调用的服务端方法也在非UI线程。
2、当跨进程时(在Manifest指定process属性),服务端的方法运行在Binder的线程池中,所以Binder方法不管是否耗时都应该采用同步的方式去实现。
3、当客户端发起远程请求时,由于当前线程会被挂起直至服务端进程返回数据,所以如果一个远程方法是很耗时的,那么不能再UI线程中发起此远程请求。
4、如果一个远程方法是耗时的,在客户端调用时会被挂起(上面说的第3点)。但是如果远程方法返回void,也就是远程方法在怎么耗时,客户端也不需要你返回数据,那么可以在AIDL方法中增加oneway关键字。
oneway void addBook(in Book book) 这样客户端就不会被挂起了。
5、在跨进程中,客户端传递的对象是经过序列化的,在服务端接收的对象,是经过反序列化的。服务端接收的对象只是里面的东西一样,但是根本不是同一个对象,这点要注意。
6、所有非原语(原语含义看下面)参数都需要指示数据走向的方向标记。可以是 in、out 或 inout。
原语默认为 in,不能是其他方向。
7、AIDL接口中只支持方法,不支持声明静态常量。
使用
拿IKeyguardService.aidl来举例
使用AIDL完成通讯需要经过如下几个步骤:
1) 创建 aidl 接口文件
2) 创建一个远程 Service
3) 客户端链接Binder
下面文字参考
创建 aidl 接口文件
支持的参数类型
- 八种基本数据类型;
- String、CharSequence;
- List、Map,它们中的数据类型也应该是AIDL支持的;
- 实现Parcelabel的引用类型。
自定义引用类型使用
如果要使用自定义的数据类型,需要先为它也生成一个aidl文件,里面内容只需两行:1
2AIDL的包名;
parcelable 类名;
例如:1
2package com.coorchice.coorchicelibone;
parcelable Role;
接着就可以创建对应的java数据类了,然后实现Parcelable接口,注意包名需要和aidl一模一样!如果你对自定义类型使用了in或者inout标识符的话,你必须再给自定义类实现readFromParcel()方法。比如:1
2
3
4public void readFromParcel(Parcel in) {
name = in.readString();
skill = in.readString();
}
然后在定义aidl接口时,一定要记得手动写一下自定义引用类的import!
参数修饰符
•in: 表示参数数据只能由客户端传递到服务端,基本类型就默认只支持in修饰符。
•out:表示参数数据只能由服务端传递到客户端。即服务端如果修改了参数对象的值,那么客户端的值也会变化,但是服务端无法读取到客户端对象的值。
•inout:表示参数数据能够双向传递。
定义服务接口
现在,我们可以开始定义服务接口了!这里定义的服务接口就是后面我们需要在客户端调用的。我们以SystemUI模块中的IRecentsSystemUserCallbacks.aidl为例来讲解
frameworks/base/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19package com.android.systemui.recents;
import android.graphics.Rect;
/**
* Due to the fact that RecentsActivity is per-user, we need to establish an
* interface (this) for the non-system user to register itself for callbacks and to
* callback to the system user to update internal state.
*/
oneway interface IRecentsSystemUserCallbacks {
void registerNonSystemUserCallbacks(IBinder nonSystemUserCallbacks, int userId);
void updateRecentsVisibility(boolean visible);
void startScreenPinning(int taskId);
void sendRecentsDrawnEvent();
void sendDockingTopTaskEvent(int dragMode, in Rect initialRect);
void sendLaunchRecentsEvent();
void setWaitingForTransitionStartEvent(boolean waitingForTransitionStart);
}
注意:自定义的类必须加in、out、inout等标识符,否则会报错!
实例
frameworks/base/core/java/android/bluetooth/le/PeriodicAdvertisingReport.java
frameworks/base/core/java/android/bluetooth/le/IPeriodicAdvertisingCallback.aidl
编译后生成的类解析
编译之后编译器自动帮我们生成了一个服务接口类名.Stub的抽象类,它继承自Binder,然后实现了我们定义的服务接口(注意我们的服务接口实现了IInterface接口)。嗯,重点是它是一个Binder!它就是我们用来进行Binder通讯的!
*.aidl文件如何被编译器编译后生成*.java文件的,请参考
其实,Android的AIDL就是让编译器帮助我们生成一个实现了我们接口的Binder,以帮助我们简化开发。当然,如果你了解原理的话,也可以自己写。
下面我们一步一步来看看这编译器生成的类都有些什么?
out/target/common/obj/APPS/SystemUI_intermediates/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.java
1 | /* |
服务接口实现IInterface
1 | public interface IRecentsSystemUserCallbacks extends android.os.IInterface |
编译器根据我们写的服务接口,重新生成了一个接口,唯一的区别就是新的接口继承了IInterface接口。这个接口是干什么的呢?
我们来看frameworks/base/core/java/android/os/IInterface.java的实现.1
2
3
4
5
6
7
8
9
10
11
12
13
14package android.os;
/**
* Base class for Binder interfaces. When defining a new interface,
* you must derive it from IInterface.
*/
public interface IInterface
{
/**
* Retrieve the Binder object associated with this interface.
* You must use this instead of a plain cast, so that proxy objects
* can return the correct result.
*/
public IBinder asBinder();
}
可以看到,它只有一个接口方法。这个方法用来定义将实现接口的类应该具备返回一个与之相关联的Binder的功能,以提供通讯能力。一般实现这个方法的类自己本身就会去继承Binder。
这样的设计使得Binder机制不用关心具体的接口是什么,只要是IInterface就行。事实上相当于是我们在IInterface接口的基础上扩展了接口功能,本质上还是一个IInterface,所以Binder能够认出它。
继承Binder,实现服务接口
要进行Binder通讯,我们自然需要一个Binder;要实现我们定义的服务接口功能,自然就需要实现服务接口。那么需要满足这两个条件怎么办?很简单,继承Binder,然后实现服务接口就行。
编译器为我们生成的类中有一个内部类Stub就是这么干的。1
2
3public static abstract class Stub extends android.os.Binder implements com.android.systemui.recents.IRecentsSystemUserCallbacks{
...
}
DESCRIPTOR
Binder需要绑定服务接口,定义DESCRIPTOR描述
为了一个Binder和一个特定服务接口绑定,以对外提供功能,需要给Binder定义一个DESCRIPTOR描述,表示我这个Binder是提供特定功能链接的,不是随便可以用的。
通常,DESCRIPTOR描述会直接使用包名 + 服务接口。1
private static final java.lang.String DESCRIPTOR = "com.android.systemui.recents.IRecentsSystemUserCallbacks";
实现asInterface()供客户端调用
1 | /** |
作为一个服务提供者,为了能够给调用者提供远程功能,自然需要能够提供和远程服务关联的Binder来通讯,请求服务。获取Binder的接口就是IInterface中定义的。
先查询一下获取到的和远程Service通讯的Binde中是否已经添加了功能接口的实现,如果没有则创建代理,通过代理间接的操作Binder和远程Service通讯,实现功能。
思考:既然我们已经获取到了能够直接和远程Service通讯的Binder,为什么不直接操作它去向远程Service请求服务呢?
确实,我们可以直接操作Binder向远程Service请求服务,但这过程中有很多繁琐的操作,还有一些code码的区别,如果不封装隔离的话,随着功能的扩展,我们将很难再去维护这段通讯逻辑。还有就是通过这种方式统一的管理通讯逻辑使得它可以随处使用,而不用没一个要用的地方都去写一遍。
既然是要代理和远程服务通讯,而且通讯的目的是为了请求服务接口定义的功能,那么很自然就能想到去实现服务接口,然后再对应的接口方法中实现逻辑即可。这样就可以分开来维护客户端和服务端的对应的每个功能了。
所以,我们的代理也需要实现服务接口,然后在代理中操作远程通讯的Binder进行通讯。
重写onTransact()
原理
先用上图整体描述这个AIDL从客户端(Client)发起请求至服务端(Server)相应的工作流程,我们可以看出整体的核心就是 Binder.如下:
在SystemUI的Recent模块中,每个用户都拥有一个Recent模块的SystemUI进程.这里的每个用户分两种,一种是System用户,一种是访客模式的用户.
android自从把最近任务改为一个activity后,最近任务的内部逻辑的复杂程度就在不停地快速增长着。android是支持多用户的,最近任务在每个用户空间都有一个单独运行的进程。而只有主用户空间的SystemUI进程通过AIDL才能收到PhoneWindowManager发过来的事件,比如showRecents,hideRecents等,所以副用户空间的systemui进程就需要主用户空间的systemui来通知副用户的systemui来做显示最近任务和隐藏最近任务等操作。所以会在SystemUI里面看到有两次的AIDL操作.
对于SystemUser,在Recent.java中收到来自PhoneWindwoManager的showRecentApps(),hideRecentApps()等操作时,会调用RecentImpl.java来处理.
在Recent.java的onStart函数中,对于SystemUser和SecondaryUser处理如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public void start() {
...
// Due to the fact that RecentsActivity is per-user, we need to establish and interface for
// the system user's Recents component to pass events (like show/hide/toggleRecents) to the
// secondary user, and vice versa (like visibility change, screen pinning).
final int processUser = sSystemServicesProxy.getProcessUser();
if (sSystemServicesProxy.isSystemUser(processUser)) {
// For the system user, initialize an instance of the interface that we can pass to the
// secondary user
getComponent(CommandQueue.class).addCallbacks(this);
mSystemToUserCallbacks = new RecentsSystemUser(mContext, mImpl);
} else {
// For the secondary user, bind to the primary user's service to get a persistent
// interface to register its implementation and to later update its state
registerWithSystemUser();
}
putComponent(Recents.class, this);
}
如果是SystemUser的话,会准备好SecondaryUser需要用到的回调mSystemToUserCallbacks,我们看RecentsSystemUser知道是一个AIDL来实现.此时通过mSystemToUserCallbacks
建立了SystemUser与SecondaryUser之间调用关系的服务端,等待客户端的调用.
如果是SecondaryUser的话,执行registerWithSystemUser函数,通过mSystemToUserCallbacks来注册RecentsImplProxy,RecentsImplProxy也是一个AIDL.
第一次:SystemUI进程与主用户的SystemUI进程之间的通信.
在IRecentsSystemUserCallbacks.aidl中
Server端:RecentsSystemUser.java
Client端:Recents.java
此次AIDL涉及到的文件有如下:
1) AIDL接口定义: frameworks/base/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl
2) 编译的中间件:
out/target/common/obj/APPS/SystemUI_intermediates/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.java
3) 接口的实现: frameworks/base/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
4) 接口的使用:frameworks/base/packages/SystemUI/src/com/android/systemui/recents/Recents.java
第二次:访客SystemUI进程与主用户SystemUI进程之间的通信.
Q:为何访客SystemUI进程不能直接与SystemUI进程通信????
1) 接口定义: frameworks/base/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl
2)编译中间件:
out/target/common/obj/APPS/SystemUI_intermediates/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.java
3)接口实现:frameworks/base/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java
4)接口使用:frameworks/base/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
IRecentsNonSystemUserCallbacks.aidl中
Server端:RecentsImplProxy.java
Client端:RecentsSystemUser.java
根据原理图,我们将按照一次Client的一次远程请求的流程开始分析.
客户端接口的使用
客户端 Recent.java开始调用
frameworks/base/packages/SystemUI/src/com/android/systemui/recents/Recents.java
IRecentsSystemUserCallbacks的声明
1
2
3
4
5
6
7
8
9
10
11
12/**
* An implementation of the SystemUI recents component, which supports both system and secondary
* users.
*/
public class Recents extends SystemUI
implements RecentsComponent, CommandQueue.Callbacks {
private final static String TAG = "Recents";
...
// Only for secondary users, this is the callbacks instance provided by the system user to make
// calls back
private IRecentsSystemUserCallbacks mUserToSystemCallbacks;Client发起请求,以Recent其中的一个onBusEvent为例来分析.可以看到对于非主用户,会新起一个线程.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29/**
* Handle Recents activity visibility changed.
*/
public final void onBusEvent(final RecentsVisibilityChangedEvent event) {
SystemServicesProxy ssp = Recents.getSystemServices();
int processUser = ssp.getProcessUser();//获取进程的User ID
if (ssp.isSystemUser(processUser)) {//如果是主用户进程,直接调用RecentImpl.java里面onVisibilityChanged函数处理
mImpl.onVisibilityChanged(event.applicationContext, event.visible);
} else {//如果是非主用户进程,则需要新起线程处理
postToSystemUser(new Runnable() {
public void run() {
try {
mUserToSystemCallbacks.updateRecentsVisibility(event.visible);//private IRecentsSystemUserCallbacks mUserToSystemCallbacks;
} catch (RemoteException e) {
Log.e(TAG, "Callback failed", e);
}
}
});
}
// This will catch the cases when a user launches from recents to another app
// (and vice versa) that is not in the recents stack (such as home or bugreport) and it
// would not reset the wait for transition flag. This will catch it and make sure that the
// flag is reset.
if (!event.visible) {
mImpl.setWaitingForTransitionStart(false);
}
}再看看postToSystemUser函数的实现.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27/**
* Runs the runnable in the system user's Recents context, connecting to the service if
* necessary.
*/
private void postToSystemUser(final Runnable onConnectRunnable) {
mOnConnectRunnables.add(onConnectRunnable);
if (mUserToSystemCallbacks == null) {
Intent systemUserServiceIntent = new Intent();
systemUserServiceIntent.setClass(mContext, RecentsSystemUserService.class);
boolean bound = mContext.bindServiceAsUser(systemUserServiceIntent,
mUserToSystemServiceConnection, Context.BIND_AUTO_CREATE, UserHandle.SYSTEM);
EventLog.writeEvent(EventLogTags.SYSUI_RECENTS_CONNECTION,
EventLogConstants.SYSUI_RECENTS_CONNECTION_USER_BIND_SERVICE,
sSystemServicesProxy.getProcessUser());
if (!bound) {
// Retry after a fixed duration
mHandler.postDelayed(new Runnable() {
public void run() {
registerWithSystemUser();
}
}, BIND_TO_SYSTEM_USER_RETRY_DELAY);
}
} else {
runAndFlushOnConnectRunnables();
}
}从上面两块代码可以看到postToSystemUser函数做了两件事件:
a)当mUserToSystemCallbacks即IRecentsSystemUserCallbacks的对象为空时,通过bindService函数,绑定RecentsSystemUserService这个服务,我们可以从 RecentsSystemUserService的onBind函数看到,此服务调用的是Recent.java
在bindService绑定时, 会调用主线程中的registerWithSystemUser函数,
b)如果mUserToSystemCallbacks不为空,即对主用户进程的回调存在,则执行mUserToSystemCallbacks.updateRecentsVisibility(event.visible);调用过程下面等会儿继续讲.
1 | //RecentsSystemUserService.java |
再来看看registerWithSystemUser函数1
2
连接服务,并绑定服务端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36// Only for secondary users, this is the service connection we use to connect to the system user
private final ServiceConnection mUserToSystemServiceConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName name, IBinder service) {
if (service != null) {
//第一步:获取IUserToSystemCallbacks对象
mUserToSystemCallbacks = IRecentsSystemUserCallbacks.Stub.asInterface(
service);
//第二步:写入SYSUI_RECENTS_CONNECTION事件,此处与AIDL无关,仅写入事件
EventLog.writeEvent(EventLogTags.SYSUI_RECENTS_CONNECTION,
EventLogConstants.SYSUI_RECENTS_CONNECTION_USER_SYSTEM_BOUND,
sSystemServicesProxy.getProcessUser());
//第三步:设置主用户Binder对象代理,监听主用户的IBinder,如果死亡,则说明开始启动访客模式
// Listen for system user's death, so that we can reconnect later
try {
service.linkToDeath(mUserToSystemCallbacksDeathRcpt, 0);
} catch (RemoteException e) {
Log.e(TAG, "Lost connection to (System) SystemUI", e);
}
//第四步:刷新进程中的线程
// Run each of the queued runnables
runAndFlushOnConnectRunnables();
}
// Unbind ourselves now that we've registered our callbacks. The
// binder to the system user are still valid at this point.
mContext.unbindService(this);
}
public void onServiceDisconnected(ComponentName name) {
// Do nothing
}
};从上述代码来看,连接服务做了四件事情,其中的重点是第二步,mUserToSystemCallbacks = IRecentsSystemUserCallbacks.Stub.asInterface(service);这句代码中我们重点关注asInterface,从后面的代码,我们可以看到我们可以IRecentsSystemUserCallbacks.Stub是IRecentsSystemUserCallbacks接口的内部抽象类.
asInterface用于将服务端的Binder对象转换成客户端所需的AIDL接口类型的对象,这种转换过程是区分进程的【如果客户端和服务端位于同一进程,那么此方法返回的就是服务端的Stub对象本身,否则返回的是系统封装后的Stub.proxy对象】
在 ServiceConnection 绑定服务的方法里,我们通过IRecentsSystemUserCallbacks.Stub.asInterface(service)方法 获得 IRecentsSystemUserCallbacks对象,我们跟着 asInterface 步伐看看里面有什么名堂。
我们到编译中间件IRecentsSystemUserCallbacks.java中看下asInterface函数的实现:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15/**
* Cast an IBinder object into an com.android.systemui.recents.IRecentsSystemUserCallbacks interface,
* generating a proxy if needed.
*/
public static com.android.systemui.recents.IRecentsSystemUserCallbacks asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.android.systemui.recents.IRecentsSystemUserCallbacks))) {
return ((com.android.systemui.recents.IRecentsSystemUserCallbacks)iin);
}
return new com.android.systemui.recents.IRecentsSystemUserCallbacks.Stub.Proxy(obj);
}我们看看DESCRIPTOR的定义:
1
private static final java.lang.String DESCRIPTOR = "com.android.systemui.recents.IRecentsSystemUserCallbacks";
因此,可以看出如果是同一进程,那么就返回Stub对象本身(obj.queryLocalInterface(DESCRIPTOR)),否则如果是跨进程则返回Stub的代理内部类Proxy。
也就是说这个 asInterface 方法返回的是一个远程接口具备的能力(有什么方法可以调用),在我们项目里,asInterface 的能力就是 get/setDemand 和 注册/解绑监听接口。
主用户IBinder死亡,开始启动访客模式SystemUI.这里就是开启了另外一个AIDL,等会儿讲.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18// Only for secondary users, this is the death handler for the binder from the system user
private final IBinder.DeathRecipient mUserToSystemCallbacksDeathRcpt = new IBinder.DeathRecipient() {
public void binderDied() {
mUserToSystemCallbacks = null;
EventLog.writeEvent(EventLogTags.SYSUI_RECENTS_CONNECTION,
EventLogConstants.SYSUI_RECENTS_CONNECTION_USER_SYSTEM_UNBOUND,
sSystemServicesProxy.getProcessUser());
// Retry after a fixed duration
mHandler.postDelayed(new Runnable() {
public void run() {
registerWithSystemUser();
}
}, BIND_TO_SYSTEM_USER_RETRY_DELAY);
}
};
接口定义:
frameworks/base/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl
1 | package com.android.systemui.recents; |
接口中间件
out/target/common/obj/APPS/SystemUI_intermediates/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.java
1 | /* |
接口的实现
frameworks/base/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99package com.android.systemui.recents;
import android.content.Context;
import android.graphics.Rect;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.EventLog;
import android.util.Log;
import android.util.SparseArray;
import com.android.systemui.EventLogConstants;
import com.android.systemui.EventLogTags;
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.DockedTopTaskEvent;
import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
import com.android.systemui.recents.events.component.SetWaitingForTransitionStartEvent;
import com.android.systemui.recents.events.ui.RecentsDrawnEvent;
import com.android.systemui.recents.misc.ForegroundThread;
/**
* An implementation of the system user's Recents interface to be called remotely by secondary
* users.
*/
public class RecentsSystemUser extends IRecentsSystemUserCallbacks.Stub {
private static final String TAG = "RecentsSystemUser";
private Context mContext;
private RecentsImpl mImpl;
private final SparseArray<IRecentsNonSystemUserCallbacks> mNonSystemUserRecents =
new SparseArray<>();
public RecentsSystemUser(Context context, RecentsImpl impl) {
mContext = context;
mImpl = impl;
}
public void registerNonSystemUserCallbacks(final IBinder nonSystemUserCallbacks,
final int userId) {
try {
final IRecentsNonSystemUserCallbacks callback =
IRecentsNonSystemUserCallbacks.Stub.asInterface(nonSystemUserCallbacks);
nonSystemUserCallbacks.linkToDeath(new IBinder.DeathRecipient() {
public void binderDied() {
mNonSystemUserRecents.removeAt(mNonSystemUserRecents.indexOfValue(callback));
EventLog.writeEvent(EventLogTags.SYSUI_RECENTS_CONNECTION,
EventLogConstants.SYSUI_RECENTS_CONNECTION_SYSTEM_UNREGISTER_USER,
userId);
}
}, 0);
mNonSystemUserRecents.put(userId, callback);
EventLog.writeEvent(EventLogTags.SYSUI_RECENTS_CONNECTION,
EventLogConstants.SYSUI_RECENTS_CONNECTION_SYSTEM_REGISTER_USER, userId);
} catch (RemoteException e) {
Log.e(TAG, "Failed to register NonSystemUserCallbacks", e);
}
}
public IRecentsNonSystemUserCallbacks getNonSystemUserRecentsForUser(int userId) {
return mNonSystemUserRecents.get(userId);
}
public void updateRecentsVisibility(boolean visible) {
ForegroundThread.getHandler().post(() -> {
mImpl.onVisibilityChanged(mContext, visible);
});
}
public void startScreenPinning(int taskId) {
ForegroundThread.getHandler().post(() -> {
mImpl.onStartScreenPinning(mContext, taskId);
});
}
public void sendRecentsDrawnEvent() {
EventBus.getDefault().post(new RecentsDrawnEvent());
}
public void sendDockingTopTaskEvent(int dragMode, Rect initialRect) throws RemoteException {
EventBus.getDefault().post(new DockedTopTaskEvent(dragMode, initialRect));
}
public void sendLaunchRecentsEvent() throws RemoteException {
EventBus.getDefault().post(new RecentsActivityStartingEvent());
}
public void setWaitingForTransitionStartEvent(boolean waitingForTransitionStart) {
EventBus.getDefault().post(new SetWaitingForTransitionStartEvent(
waitingForTransitionStart));
}
}
1) 接口定义: frameworks/base/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl
2)编译中间件:
3)接口实现:frameworks/base/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java
4)接口使用:
Q:很好奇AIDL文件写好后是如何编译成java文件的?
待后续继续研究.
参考资料
Android 深入浅出AIDL(一)
Android 深入浅出AIDL(二)
Android:学习AIDL,这一篇文章就够了(上)
Android:学习AIDL,这一篇文章就够了(下)