AIDL(Android Interface Definition Language),Android 接口定义语言。Android 中的 IPC 方式之一。前面说过的 IPC 方式有 Bundle、文件共享、Messenger,它们都有各自的局限性,比如 Messenger 因为处理消息是一个一个的处理,如果有大量的并发请求,使用它就不合适了。同时,Messenger 的作用主要就是传递消息,通过 Message 为载体,可以携带 Bundle 类型的数据进行传输,如果客户端想通过 Messenger 这种方式调用服务端的方法时,就无法实现这个功能。所以这个时候我们就可以使用 AIDL 这种方式,它可以实现跨进程的方法调用。虽然 Messenger 的底层实现也是 AIDL,但是系统对它进行了封装,使它只可以简单的完成特定的任务,方便我们使用。
下面我们详细看一下 AIDL 的使用。
AIDL 文件所支持的数据类型:
1. 基本数据类型(byte、int、short、long、char、boolean、float、double等)。
2. String 和 CharSequence(char 值的一个可读序列)。
3. List:只支持 ArrayList,里面每个元素都必须能够被 AIDL 支持。
4. Map:只支持 HashMap,里面的每个元素都必须能够被 AIDL 支持,包括 key 和 value。
5. Parcelable:所有实现了 Parcelable 接口的对象。
6. AIDL:所有的 AIDL 接口本身也可以在 AIDL 文件中使用。
这里我们需要注意:
① 如果 AIDL 文件中用到了我们自定义的实现了 Parcelable 接口的对象,必须新建一个和该对象同名的 AIDL 文件,并在其中声明它为 Parcelable 类型。
② 如果 AIDL 文件中要使用我们自定义的实现了 Parcelable 接口的对象,不管它们是否和当前的 AIDL 文件位于同一个包内,必须要将该对象显式的 import 进来。
③ AIDL 中除了基本数据类型,其它类型的参数必须标上参数:in、out、inout。其中 in 表示输入型参数,out 表示输出型参数,inout 表示输入输出型参数。
④ AIDL 接口中只支持方法,不支持声明静态常量,这一点区别于传统的接口。
由于使用 AIDL 时,客户端和服务端中的 AIDL 文件必须完全一致,包括包名。所以为了方便 AIDL 开发,建议把所有和 AIDL 相关的类和文件全部放入同一个包中,这样,当客户端是另外一个应用时,就可以直接把整个包复制到客户端工程即可和服务端中 AIDL 接口保持完全一致。
使用 AIDL:
eg1:
AIDL 相关文件(在 aidl 目录下):
Book.aidl:
package com.cfm.aidltest; parcelable Book; // 因为 Book 类是我们自定义的实现了 Parcelable 接口的类,而且在 AIDL 文件中使用到了,所以在这里要进行声明。IBookManager.aidl:(AIDL 类型接口)
// IBookManager.aidl package com.cfm.aidltest; import com.cfm.aidltest.Book; // 注意这里要显式 import 进来 Book 类。 interface IBookManager { List<Book> getBookList(); void addBook(in Book book); }Book.java: (实现了 Parcelable 接口的 Book 类)
package com.cfm.aidltest; public class Book implements Parcelable { public int bookId; public String bookName; public Book(){ } public Book(int bookId, String bookName) { this.bookId = bookId; this.bookName = bookName; } protected Book(Parcel in) { bookId = in.readInt(); bookName = in.readString(); } public static final Creator<Book> CREATOR = new Creator<Book>() { @Override public Book createFromParcel(Parcel in) { return new Book(in); } @Override public Book[] newArray(int size) { return new Book[size]; } }; @Override public String toString() { return String.format("[bookId:%s, bookName:%s]", bookId, bookName); } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(bookId); dest.writeString(bookName); } }BookManagerService.java:(服务端实现代码)
package com.cfm.aidltest; public class BookManagerService extends Service { private static final String TAG = "cfmtest"; /** * 我们这里使用的是 CopyOnWriteArrayList 类,它实现了 Serializable 接口,所以能够跨进程传输,同时它也实现了 List 接口, * 所以它也属于 List 类型。而 AIDL 中支持 List 接口类型数据,所以我们可以使用 CopyOnWriteArrayList 类,只是虽然服务端返回 * 的是 CopyOnWriteArrayList,但是在 Binder 底层会按照 List 的规范去访问数据并最终形成一个新的 ArrayList 传递给客户端。 * (这也是为什么前面说 AIDL 中支持的 List 只能是 ArrayList,因为 Binder 经过底层转换之后返回给客户端的就是 ArrayList 对象) * * 为什么使用这个类?由于 AIDL 方法是在服务端的 Binder 线程池中执行的,因此当多个客户端同时连接的时候,会存在多个线程 * 同时访问的情形,所以我们要在 AIDL 方法中处理线程同步。而 CopyOnWriteArrayList 支持并发读/写,它的底层已经实现了线程 * 同步。与此类似的还有 ConcurrentHashMap。 */ private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<>(); // 当客户端请求服务端时,服务端完成的具体任务 private IBinder mBinder = new IBookManager.Stub() { @Override public List<Book> getBookList() throws RemoteException { return mBookList; } @Override public void addBook(Book book) throws RemoteException { mBookList.add(book); } }; @Override public void onCreate() { super.onCreate(); Log.d(TAG, "服务端的 service 创建成功!"); mBookList.add(new Book(1, "Android")); mBookList.add(new Book(2, "ios")); } @Override public IBinder onBind(Intent intent) { return mBinder; } }ClientActivity.java:(客户端实现代码)
package com.cfm.aidltest; public class ClientActivity extends AppCompatActivity{ private static final String TAG = "cfmtest"; // 绑定服务端服务 private ServiceConnection conn = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { // 将服务端传过来的的 IBinder 类型参数转换成客户端 AIDL 接口类型以方便调用 AIDL 中的实现方法 IBookManager clientManager = IBookManager.Stub.asInterface(service); try{ // 在客户端中为 服务端添加一本书 clientManager.addBook(new Book(3, "World Peace!")); List<Book> list = clientManager.getBookList(); Log.d(TAG, "服务端返回给客户端的 List 类型: " + list.getClass().getCanonicalName()); Log.d(TAG, "客户端取到的 List 内容: " + list.toString()); }catch (RemoteException e){ e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_client); // 绑定服务端服务 Intent intent = new Intent(this, BookManagerService.class); bindService(intent, conn, Context.BIND_AUTO_CREATE); } @Override protected void onDestroy() { super.onDestroy(); // 解绑服务 unbindService(conn); } }AndroidManifest.xml:
... <service android:name=".BookManagerService" android:enabled="true" android:exported="true" android:process=":remote"> </service> ... // 服务端与客户端不在一个进程中Log 打印信息:
// 服务端
com.cfm.aidltest:remote/cfmtest: 服务端的 service 创建成功!// 客户端
com.cfm.aidltest/cfmtest: 服务端返回给客户端的 List 类型: java.util.ArrayList com.cfm.aidltest/cfmtest: 客户端取到的 List 内容: [[bookId:1, bookName:Android], [bookId:2, bookName:ios], [bookId:3, bookName:World Peace!]]可以看到,虽然服务端使用的 List 类型为 CopyOnWriteArrayList 类,但是最后返回给客户端的是 ArrayList。还有,我们在客户端调用 addBook 方法为服务端的书单增加了一本书,可以看到也成功从服务端获取到了刚刚添加的这本书的信息。
下面引入一个 Java 中的设计模式,然后通过这个设计模式,再丰富一下上面的 Demo。
java 设计模式之观察者模式:
什么是观察者模式?
定义对象间的一种一对多的依赖关系。当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
观察者模式结构图:
根据上面的结构图,我们可以知道观察者模式中有如下角色:
Subject: 抽象主题(抽象被观察者),抽象主题角色把所有观察者对象保存在一个容器里,每个抽象主题都可以有任意数量的观察者,抽象主题还提供增加和删除观察者对象的接口(attach() 和 detach() 方法)。
ConcreteSubject: 具体主题(具体被观察者),该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知。
Observer: 抽象观察者,是观察者的抽象类,它定义了一个更新接口,使得在得到主题状态改变通知时更新自己。
ConcreteObserver: 具体观察者,实现抽象观察者定义的更新接口,当具体主题状态改变通知时,执行自己准备更新的内容。
下面举个简单的例子,妈妈是具体的被观察者,儿子和女儿是具体的观察者,妈妈把饭做好了之后,通知女儿和儿子吃饭:
Subject(抽象被观察者):
package com.cfm.observerpattern; /** * 抽象被观察者(Subject) */ public interface Subject { // 增加一个吃饭的人 void attach(Observer observer); // 减少一个吃饭的人 void detach(Observer observer); // 通知所有人吃饭 void notifyEat(); }ConcreteSubject(具体被观察者):
package com.cfm.observerpattern; public class Mother implements Subject{ // 管理要通知吃饭的人的容器 private List<Observer> users = new ArrayList<>(); @Override public void attach(Observer observer) { users.add(observer); } @Override public void detach(Observer observer) { users.remove(observer); } @Override public void notifyEat() { System.out.println("妈妈饭做好了,在通知孩子们准备吃饭了!"); for(Observer observer : users){ observer.eat(); } } }Observer(抽象观察者):
package com.cfm.observerpattern; /** * 抽象观察者 Observer */ public interface Observer { void eat(); }ConcreteObserver(具体观察者):
package com.cfm.observerpattern; /** * 具体观察者(ConcreteObserver) */ public class Son implements Observer { private String name; Son(String name){ this.name = name; } @Override public void eat() { System.out.println(this.name + " 收到了通知,准备开始吃饭!"); } } package com.cfm.observerpattern; /** * 具体观察者(ConcreteObserver) */ public class Daughter implements Observer { private String name; Daughter(String name){ this.name = name; } @Override public void eat() { System.out.println(this.name + " 收到了通知,准备开始吃饭了!"); } }测试代码:
package com.cfm.observerpattern; public class Test { public static void main(String[] args) { // 创建一个具体被观察者(也就是妈妈,当妈妈把饭做好了之后,就通知儿子和女儿吃饭) Mother mother = new Mother(); // 创建两个具体的观察者,并告诉妈妈,饭做好了要告诉我。 Son son = new Son("cfm"); Daughter daughter = new Daughter("ym"); mother.attach(son); mother.attach(daughter); // 饭做好了,妈妈通知孩子孩子们可以吃饭了 mother.notifyEat(); } }Log 信息:
妈妈饭做好了,在通知孩子们准备吃饭了! cfm 收到了通知,准备开始吃饭! ym 收到了通知,准备开始吃饭了!--------------------------------------分割线--------------------------------------
现在我们开始丰富第一个 aidl 的 demo,需求: 当服务端有新书到来时,就会通知每一个申请了提醒功能的客户端。(这会用到上面说的观察者模式。)
1. 新建一个 IOnNewBookArrivedListener.aidl 文件,然后添加一个接口方法: onNewBookArrived()。这个就相当于上面的抽象观察者 Observer.java 以及里面的 update() 方法。为什么使用 AIDL 接口而不是普通接口呢?这是因为在 AIDL 中无法使用普通接口。注意,这个是客户端要具体实现的接口,所以它的方法运行在客户端的 Binder 线程池中。
IOnNewBookArrivedListener.aidl:
package com.cfm.aidltest; import com.cfm.aidltest.Book; interface IOnNewBookArrivedListener { void onNewBookArrived(in Book book); }2.
IBookManager.aidl:(这个是抽象被观察者)
package com.cfm.aidltest; import com.cfm.aidltest.Book; import com.cfm.aidltest.IOnNewBookArrivedListener; interface IBookManager { List<Book> getBookList(); void addBook(in Book book); void registerListener(IOnNewBookArrivedListener listener); // 注册观察者 void unregisterListener(IOnNewBookArrivedListener listener); // 注销观察者 }3.
Book.aidl:
package com.cfm.aidltest; parcelable Book;Book.java:
package com.cfm.aidltest; public class Book implements Parcelable { public int bookId; public String bookName; public Book(){ } public Book(int bookId, String bookName) { this.bookId = bookId; this.bookName = bookName; } protected Book(Parcel in) { bookId = in.readInt(); bookName = in.readString(); } public static final Creator<Book> CREATOR = new Creator<Book>() { @Override public Book createFromParcel(Parcel in) { return new Book(in); } @Override public Book[] newArray(int size) { return new Book[size]; } }; @Override public String toString() { return String.format("[bookId:%s, bookName:%s]", bookId, bookName); } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(bookId); dest.writeString(bookName); } }4. 在服务单开启一个线程,每隔 5s 就向书单中添加一本新书并通知注册了提醒功能的客户端。
BookManagerService.java:
package com.cfm.aidltest; public class BookManagerService extends Service { private static final String TAG = "cfmtest"; // 如果服务端服务被销毁,就停止往书单中加书的线程。 private AtomicBoolean mIsServiceDestoryed = new AtomicBoolean(false); // 书单 private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<>(); // 存储具体观察者的容器,为什么使用 RemoteCallbackList,而不是普通的 List? 下面会具体分析。 private RemoteCallbackList<IOnNewBookArrivedListener> mListenerList = new RemoteCallbackList<>(); // 具体的被观察者(ConcreteSubject),里面的方法运行在服务端的 Binder 线程池中。 private Binder mBinderWithConcreteSubject = new IBookManager.Stub() { @Override public List<Book> getBookList() throws RemoteException { // 返回书单 return mBookList; } @Override public void addBook(Book book) throws RemoteException { // 向书单中添加新书 mBookList.add(book); } @Override public void registerListener(IOnNewBookArrivedListener listener) throws RemoteException { // 客户端(具体观察者)向服务端(具体被观察者)注册新书到来时的提醒通知,以当服务端有新书到来时通知给客户端。 mListenerList.register(listener); } @Override public void unregisterListener(IOnNewBookArrivedListener listener) throws RemoteException { // 客户端(具体观察者)向服务端(具体被观察者)注销新书到来时的提醒通知 mListenerList.unregister(listener); } }; @Override public void onCreate() { super.onCreate(); Log.d(TAG, "服务端的 service 创建成功!"); mBookList.add(new Book(1, "Android")); mBookList.add(new Book(2, "ios")); // 开始一个每隔 5s 添加一本新书到书单的线程 new Thread(new addNewBookRunnable()).start(); } @Override public IBinder onBind(Intent intent) { return mBinderWithConcreteSubject; } private void addNewBookAndNotifyClient(Book book) throws RemoteException { // 通知所有注册了提醒通知的客户端,有新书到了。 mBookList.add(book); // 先添加一本新书,然后通知客户端有新书到了 Log.d(TAG, "服务端添加了一本新书: " + book.toString()); final int N = mListenerList.beginBroadcast(); // 返回服务端中注册的客户端数量 for (int i = 0; i < N; i++) { IOnNewBookArrivedListener mClient = mListenerList.getBroadcastItem(i); if (mClient != null) { mClient.onNewBookArrived(book); } } mListenerList.finishBroadcast(); } private class addNewBookRunnable implements Runnable { @Override public void run() { while (!mIsServiceDestoryed.get()) { try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } int bookId = mBookList.size() + 1; Book newBook = new Book(bookId, "new book#" + bookId); try { addNewBookAndNotifyClient(newBook); } catch (RemoteException e) { e.printStackTrace(); } } } } }5. 客户端要实现抽象观察者接口(IOnNewBookArrivedListener)并向服务端注册提醒功能通知,在退出的时候再注销。由于 IOnNewBookArrivedListener 接口中的方法运行在客户端的 Binder 线程池中,所以为了方便进行 UI 操作,我们创建了一个 Handler 来将其切换到客户端的主线程中执行。
ClientActivity.java:
package com.cfm.aidltest; public class ClientActivity extends AppCompatActivity{ private static final String TAG = "cfmtest"; private static final int MESSAGE_NEW_BOOK_ARRIVED = 1; private IBookManager mRemoteServerBookManager; private Handler mHandler = new Handler(){ @Override public void handleMessage(Message msg) { switch (msg.what){ case MESSAGE_NEW_BOOK_ARRIVED: Book newBook = (Book) msg.obj; Log.d(TAG, "客户端收到服务端的新书提醒,提醒的新书为: " + newBook.toString()); } super.handleMessage(msg); } }; private ServiceConnection conn = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { IBookManager bookManager = IBookManager.Stub.asInterface(service); try{ mRemoteServerBookManager = bookManager; // 待会注销具体观察者时要用到 List<Book> list = bookManager.getBookList(); Log.d(TAG, "query book list: " + list.toString()); mRemoteServerBookManager.registerListener(mConcreteObsever); }catch (RemoteException e){ e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { } }; // 具体的被观察者 private IOnNewBookArrivedListener mConcreteObsever = new IOnNewBookArrivedListener.Stub() { @Override public void onNewBookArrived(Book book) throws RemoteException { // 由于这个方法运行在客户端的 Binder 线程池中,为了方便操作 UI。所以使用 Handler 切换到 // 客户端的主线程中执行。 mHandler.obtainMessage(MESSAGE_NEW_BOOK_ARRIVED, book).sendToTarget(); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_client); // 绑定远程服务 Intent intent = new Intent(this, BookManagerService.class); bindService(intent, conn, Context.BIND_AUTO_CREATE); } @Override protected void onDestroy() { super.onDestroy(); // 注销提醒 if(mRemoteServerBookManager != null && mRemoteServerBookManager.asBinder().isBinderAlive()){ try { Log.d(TAG, "客户端注销提醒成功!"); mRemoteServerBookManager.unregisterListener(mConcreteObsever); } catch (RemoteException e) { e.printStackTrace(); } } unbindService(conn); super.onDestroy(); } }AndroidManifest.xml:
... <service android:name=".BookManagerService" android:enabled="true" android:exported="true" android:process=":remote"> </service> ...Log 打印信息:
服务端:
2019-05-22 21:16:47.308 21611-21611/com.cfm.aidltest:remote D/cfmtest: 服务端的 service 创建成功! 2019-05-22 21:16:52.325 21611-21635/com.cfm.aidltest:remote D/cfmtest: 服务端添加了一本新书: [bookId:3, bookName:new book#3] 2019-05-22 21:16:57.337 21611-21635/com.cfm.aidltest:remote D/cfmtest: 服务端添加了一本新书: [bookId:4, bookName:new book#4] 2019-05-22 21:17:02.346 21611-21635/com.cfm.aidltest:remote D/cfmtest: 服务端添加了一本新书: [bookId:5, bookName:new book#5] 2019-05-22 21:17:07.356 21611-21635/com.cfm.aidltest:remote D/cfmtest: 服务端添加了一本新书: [bookId:6, bookName:new book#6]客户端:
2019-05-22 21:16:47.388 21591-21591/com.cfm.aidltest D/cfmtest: query book list: [[bookId:1, bookName:Android], [bookId:2, bookName:ios]] 2019-05-22 21:16:52.335 21591-21591/com.cfm.aidltest D/cfmtest: 客户端收到服务端的新书提醒,提醒的新书为: [bookId:3, bookName:new book#3] 2019-05-22 21:16:57.345 21591-21591/com.cfm.aidltest D/cfmtest: 客户端收到服务端的新书提醒,提醒的新书为: [bookId:4, bookName:new book#4] 2019-05-22 21:17:02.354 21591-21591/com.cfm.aidltest D/cfmtest: 客户端收到服务端的新书提醒,提醒的新书为: [bookId:5, bookName:new book#5] 2019-05-22 21:17:07.363 21591-21591/com.cfm.aidltest D/cfmtest: 客户端收到服务端的新书提醒,提醒的新书为: [bookId:6, bookName:new book#6] 2019-05-22 21:17:09.490 21591-21591/com.cfm.aidltest D/cfmtest: 客户端注销提醒成功!可以看到这里当客户端退出时,向服务端注销提醒功能成功,而这一切得益于 RemoteCallbackList 类。为什么要使用它呢?因为 Binder 会把客户端传递到服务端的 mConcreteObsever 转换成一个全新的对象,如果直接注销,会导致服务端找不到这个 mConcreteObsever 对象而失败。下面来看为什么使用 RemoteCallbackList 可以。
RemoteCallbackList 是 Android System 专门提供的用于删除跨进程 Listener 的接口。先看一下它的源码:
public class RemoteCallbackList<E extends IInterface>{ ... }可以看到 RemoteCallbackList 是一个泛型,支持管理任意的 AIDL 接口( 也就是实现或者继承了 IInterface 接口的类 )。
ArrayMap<IBinder, Callback> mCallbacks = new ArrayMap<IBinder, Callback>(); IBinder key = listener.asBinder(); Callback value = new Callback(listener, cookie);上面这个就是它的工作原理,在它的内部有一个 Map 结构专门用来保存所有的 AIDL 回调,这个 Map 的 key 是 IBinder 类型,value 是 Callback 类型。其中 Callback 中封装了真正的远程 listener。当客户端注册 listener 的时候,它会把这个 listener 的信息存入 mCallbacks。虽然跨进程传输客户端的同一个对象会在服务端生成不同的对象,但是它们底层的 Binder 对象都是同一个。
RemoteCallback 的主要作用:
1. 当客户端解注册的时候,我们只要遍历服务端所有的 listener,找出那个和解注册 listener 具有相同 Binder 对象的服务端 listener 并把它删掉即可。
2. 当客户端进程终止后,它能够自动移除客户端所注册的 listener。
3. RemoteCallback 内部自动实现了线程同步的功能,所以我们使用它来注册和解注册时,不需要做额外的线程同步工作。
下面说一下需要注意的几点:
1. 使用 RemoteCallback 时,我们无法像操作 List 一样去操作它,从源码可以看到,它压根就不是一个 List 类型接口。遍历 RemoteCallback,必须按照下面的方式进行,其中 beginBroadcast 和 finishBroadcast 必须要配对使用,即使我们只是想获取 RemoteCallback 中的元素个数也要如此:
RemoteCallback mListenerList; final int N = mListenerList.beginBroadcast(); for (int i = 0; i < N; i++) { ... } mListenerList.finishBroadcast();2. 使用 AIDL 进行跨进程通信时,注意我们在客户端调用服务端中的方法时,由于是在 UI 线程中,并且当前线程会挂起直到等待服务端方法执行完毕后唤醒它,所以为了避免 ANR,一般都会在调用服务端方法时开一个子线程。
当服务端进程意外停止导致 Binder 死亡时,我们在客户端重新连接服务的两种方法:
1. 通过 linkToDeath() 和 unlinkToDeath() 方法,当服务端 Binder 死亡时,客户端会回调 DeathRecipient 接口中的 binderDied 方法,然后我们可以在这个方法中重新连接远程服务。
2. 在客户端的 onServiceDisconnected() 方法中重新连接远程服务。
这两个方法的区别是,onServiceDisconnected 运行在客户端的 UI 线程中,而 binderDied 运行在客户端的 Binder 线程池中。所以在 binderDied 方法中我们不能访问 UI。其它效果都是一样的。
最后,我们看一下关于权限验证功能,之前我们在分析 Binder 底层时说过除了传输性能高效还有一个特点就是安全性更高。我们可以在服务端实现 AIDL 接口时重写 onTransact() 方法,并通过 permission 和 UID/PID 来验证。
在 AndroidManifest.xml 中我们可以自定义权限,eg:
<permission android:name="com.cfm.aidltest.ACCESS_BOOK_SERVICE" android:protectionLevel="normal"/>下面我们看一下具体的应用:
@Override public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { // 第一道: 通过 permission 验证 int check = checkCallingOrSelfPermission("com.cfm.aidltest.ACCESS_BOOK_SERVICE"); if( check == PackageManager.PERMISSION_DENIED){ return false; // 权限验证失败 } // 第二道: 通过 packageName 验证 String packageName = null; // 通过 getCallingUid 和 getCallingPid 可以得到客户端的 Uid 和 Pid String[] packages = getPackageManager().getPackagesForUid(getCallingUid()); if(packages != null && packages.length > 0){ packageName = packages[0]; } if (packageName != null && !packageName.startsWith("com.cfm")) { return false; } return super.onTransact(code, data, reply, flags); }