- 服務端首先要創建一個 Service 用來監聽客戶端的請求
- 創建一個 AIDL 文件,將暴露給客戶端的接口在這個 AIDL 文件中聲明
- 最後在 Service 中實現這個 AIDL 接口
- 首先需要綁定服務端的 Service
- 綁定成功後,將服務端返回的 Binder 對象轉成 AIDL 接口所屬類型,接着就可以調用AIDL中的方法了
目錄結構
Book.class
public class Book implements Parcelable {
public int bookId;
public String bookName;
public Book(int bookId, String bookName) {
this.bookId = bookId;
this.bookName = bookName;
}
private 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 int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(bookId);
dest.writeString(bookName);
}
}
Book.aidl// Book.aidl
package com.example.yhadmin.aidldemo.bean;
// Declare any non-default types here with import statements
parcelable Book;//由於是自定義的Book 類型數據,需要聲明爲 parcelable 類型
IBookManager.aidl// IBookManager.aidl
package com.example.yhadmin.aidldemo;
// Declare any non-default types here with import statements
import com.example.yhadmin.aidldemo.bean.Book;
interface IBookManager {
//除了基本數據類型,其他類型的參數都需要標上方向類型:in(輸入), out(輸出), inout(輸入輸出)
List<Book> getBookList();
void addBook(in Book book);
}
- 基本數據類型(int、long、char、boolean、double 等)
- String 和 CharSequence
- List:只支持 ArrayList,且裏面每個元素都必須能夠被 AIDL 支持
- Map:只支持 HashMap,且裏面每個元素都必須能夠被 AIDL 支持,包括 key 和 value
- Parcelable:所有實現了 Parcelable 接口的對象
- AIDL:所有 AIDL 接口本身也可以在 AIDL 文件中使用
- AIDL 中每個實現了Parcelable 接口的類都需要按照上面那種方式去創建相應的 AIDL 文件並聲明那個類爲 Parcelable。
- AIDL 中除了基本數據類型,其他類型的參數必須標上方向:in、out或者inout, in 表示輸入型參數,out 表示輸出型參數,inout 表示輸入輸出型參數
- 根據實際需要指定參數類型,不能一概使用out 或者 inout ,因爲這在底層實現是有開銷的
- AIDL 接口中只支持方法,不支持聲明靜態常量
public class BookManagerService extends Service {
private static final String TAG = "BMS";
private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<Book>();
//創建Binder 對象,即實現IBookManager 接口
private Binder 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();
mBookList.add(new Book(1,"Android"));
mBookList.add(new Book(2,"Ios"));
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
public class ThirdActivity
extends AppCompatActivity
{
private static final String TAG = "BookManagerActivity";
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//將返回的 Binder 對象轉換爲 AIDL 接口
IBookManager bookManager = IBookManager.Stub.asInterface(service);
try {
//通過 AIDL 接口調用服務端的遠程方法
List<Book> bookList = bookManager.getBookList();
Log.i(TAG,"query book list, list type:"+ bookList.getClass().getCanonicalName());
Log.i(TAG,"query book list: "+ bookList.toString());
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
public static void acrtionStart(Context context){
context.startActivity(new Intent(context, ThirdActivity.class));
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_third);
Button btn = findViewById(R.id.button);
final Intent intent = new Intent(this, BookManagerService.class);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
bindService(intent,mConnection,Context.BIND_AUTO_CREATE);
}
});
}
@Override
protected void onDestroy() {
unbindService(mConnection);
super.onDestroy();
}
}
使用 addBook 方法
public class ThirdActivity
extends AppCompatActivity
{
private static final String TAG = "BookManagerActivity";
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
IBookManager bookManager = IBookManager.Stub.asInterface(service);
try {
List<Book> bookList = bookManager.getBookList();
// Log.i(TAG,"query book list, list type:"+ bookList.getClass().getCanonicalName());
Log.i(TAG,"query book list: "+ bookList.toString());
Book newBook = new Book(3, "Android 開發藝術探索");
bookManager.addBook(newBook);
Log.i(TAG,"add book: "+ newBook);
List<Book> newList = bookManager.getBookList();
Log.i(TAG,"query book list: "+ newList.toString());
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
public static void acrtionStart(Context context){
context.startActivity(new Intent(context, ThirdActivity.class));
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_third);
Button btn = findViewById(R.id.button);
final Intent intent = new Intent(this, BookManagerService.class);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
bindService(intent,mConnection,Context.BIND_AUTO_CREATE);
}
});
}
@Override
protected void onDestroy() {
unbindService(mConnection);
super.onDestroy();
}
}
Log日誌// IOnNewBookArrivedListener.aidl
package com.example.yhadmin.aidldemo;
// Declare any non-default types here with import statements
import com.example.yhadmin.aidldemo.bean.Book;
interface IOnNewBookArrivedListener {
void onNewBookArrived(in Book newBook);
}
修改 IBookManager 代碼,新增註冊與註銷監聽器代碼// IBookManager.aidl
package com.example.yhadmin.aidldemo;
// Declare any non-default types here with import statements
import com.example.yhadmin.aidldemo.bean.Book;
import com.example.yhadmin.aidldemo.IOnNewBookArrivedListener;
interface IBookManager {
//除了基本數據類型,其他類型的參數都需要標上方向類型:in(輸入), out(輸出), inout(輸入輸出)
List<Book> getBookList();
void addBook(in Book book);
void registerListener(IOnNewBookArrivedListener listener);
void unregisterListener(IOnNewBookArrivedListener listener);
}
BookManagerService 代碼public class BookManagerService
extends Service
{
private static final String TAG = "BMS";
private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<Book>();
private AtomicBoolean mIsServiceDestoryed = new AtomicBoolean(false);
//存儲註冊監聽的客戶端集合
private CopyOnWriteArrayList<IOnNewBookArrivedListener> mListenerLiCopyOnWriteArrayList<IOnNewBookArrivedListener>();
private Binder 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 registerListener(IOnNewBookArrivedListener listener)
throws RemoteException
{
if (!mListenerList.contains(listener)){
mListenerList.add(listener);//添加監聽
}else {
Log.d(TAG,"already exists.");
}
Log.d(TAG,"regeisterListener,size:"+mListenerList.size());
}
@Override
public void unregisterListener(IOnNewBookArrivedListener listener)
throws RemoteException
{
if (mListenerList.contains(listener)){
mListenerList.remove(listener);//移除監聽
Log.d(TAG,"unregister listener succeed.");
}else {
Log.d(TAG,"not found, can not unregister.");
}
Log.d(TAG,"unregeisterListener,size:"+mListenerList.size());
}
};
@Override
public void onCreate() {
super.onCreate();
mBookList.add(new Book(1, "Android"));
mBookList.add(new Book(2, "Ios"));
new Thread(new ServiceWorker()).start();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
//開啓線程,5S 創建一本新書
private class ServiceWorker 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 {
//通知註冊的客戶端,新書已到達
onNewBookArrived(newBook);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
}
private void onNewBookArrived(Book newBook)
throws RemoteException
{
mBookList.add(newBook);//將新書添加到存儲書本的集合中
Log.d(TAG,"onNewBookArrived, notify listeners:"+mListenerList.size());
for (int i = 0; i < mListenerList.size(); i++) {//便利存儲的客戶端監聽集合
IOnNewBookArrivedListener listener = mListenerList.get(i);
Log.d(TAG,"onNewBookArrived, notify listeners:"+listener);
listener.onNewBookArrived(newBook);//通過接口回調方式通知客戶端新書已到達
}
}
}
ThirdActivity 代碼public class ThirdActivity
extends AppCompatActivity
{
private static final String TAG = "BookManagerActivity";
private static final int MESSAGE_NEW_BOOK_ARRAIVED = 1;
private IBookManager mRemoteBookManager;
//構建監聽器 Binder 對象
/**
* 當客戶端發起遠程請求時,由於當前線程會被掛起直至服務端進程返回數據,所以如果一個遠程方法是很耗時的,
* 則不能在UI 線程中發起此遠程請求,爲了避免阻塞UI 線程出現ANR
* 由於服務端的Binder 方法運行在 Binder 的線程池中,所以 Binder 方法不管是否耗時都應該採用同步的方式去實現,因爲它已經運行在一個線程中了
*/
private IOnNewBookArrivedListener mOnNewBookArrivedListener = new IOnNewBookArrivedListener.Stub() {
@Override
public void onNewBookArrived(Book newBook)
throws RemoteException
{
mHandler.obtainMessage(MESSAGE_NEW_BOOK_ARRAIVED, newBook)
.sendToTarget();
}
};
//防止Handler 泄漏
private static class ClientHandler extends Handler{
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_NEW_BOOK_ARRAIVED:
Log.d(TAG, "receive new book :" + msg.obj);
break;
default:
super.handleMessage(msg);
break;
}
}
}
private ClientHandler mHandler = new ClientHandler();
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//將返回的 IBinder 對象轉成 AIDL 接口所屬類型
mRemoteBookManager = IBookManager.Stub.asInterface(service);
try {
List<Book> bookList = mRemoteBookManager.getBookList();
// Log.i(TAG,"query book list, list type:"+ bookList.getClass().getCanonicalName());
Log.d(TAG, "query book list: " + bookList.toString());
Book newBook = new Book(3, "Android 開發藝術探索");
mRemoteBookManager.addBook(newBook);
Log.d(TAG, "add book: " + newBook);
List<Book> newList = mRemoteBookManager.getBookList();
Log.d(TAG, "query book list: " + newList.toString());
//註冊監聽器
mRemoteBookManager.registerListener(mOnNewBookArrivedListener);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
//連接斷開,釋放AIDL Binder對象
mRemoteBookManager = null;
Log.e(TAG, "Binder died.");
}
};
public static void acrtionStart(Context context) {
context.startActivity(new Intent(context, ThirdActivity.class));
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_third);
Button btn = findViewById(R.id.button);
final Intent intent = new Intent(this, BookManagerService.class);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
});
}
@Override
protected void onDestroy() {
//如果連接持續,並且Binder未死亡
if (mRemoteBookManager!=null&&mRemoteBookManager.asBinder().isBinderAlive()){
try {
Log.d(TAG,"unregister listener:"+mOnNewBookArrivedListener);
//註銷監聽
mRemoteBookManager.unregisterListener(mOnNewBookArrivedListener);
} catch (RemoteException e) {
e.printStackTrace();
}
}
unbindService(mConnection);
super.onDestroy();
}
}
ThirdActivity
public class BookManagerService
extends Service
{
.....
//註冊
@Override
public void registerListener(IOnNewBookArrivedListener listener)
throws RemoteException
{
/* if (!mListenerList.contains(listener)){
mListenerList.add(listener);//添加監聽
}else {
Log.d(TAG,"already exists.");
}*/
mListenerList.register(listener);
Log.d(TAG,"regeisterListener,current size:"+mListenerList.getRegisteredCallbackCount());
}
//解註冊
@Override
public void unregisterListener(IOnNewBookArrivedListener listener)
throws RemoteException
{
/*if (mListenerList.contains(listener)){
mListenerList.remove(listener);//移除監聽
Log.d(TAG,"unregister listener succeed.");
}else {
Log.d(TAG,"not found, can not unregister.");
}
*/
mListenerList.unregister(listener);
Log.d(TAG, "unregeisterListener,current size:"+mListenerList.getRegisteredCallbackCount());
}
private void onNewBookArrived(Book newBook)
throws RemoteException
{
mBookList.add(newBook);//將新書添加到存儲書本的集合中
/* Log.d(TAG,"onNewBookArrived, notify listeners:"+mListenerList.size());
for (int i = 0; i < mListenerList.size(); i++) {//便利存儲的客戶端監聽集合
IOnNewBookArrivedListener listener = mListenerList.get(i);
Log.d(TAG,"onNewBookArrived, notify listeners:"+listener);
listener.onNewBookArrived(newBook);//通過接口回調方式通知客戶端新書已到達
}*/
final int N = mListenerList.beginBroadcast();
for (int i = 0; i < N; i++) {
IOnNewBookArrivedListener l = mListenerList.getBroadcastItem(i);
if (null!=l){
l.onNewBookArrived(newBook);
}
}
mListenerList.finishBroadcast();
}
....
}
注意: RemoteCallbackList 並不是一個List ,不能像 List 一樣去操作它,遍歷RemoteCallbackList 必須要以下面的方式進行,其中 beginBroadcast 和 finishBroadcast 必須配套使用,哪怕我們僅僅是想要獲取 RemoteCallbackList 中的元素個數final int N = mListenerList.beginBroadcast();
for (int i = 0; i < N; i++) {
IOnNewBookArrivedListener l = mListenerList.getBroadcastItem(i);
if (null!=l){
l.onNewBookArrived(newBook);
}
}
mListenerList.finishBroadcast();
@Override
public List<Book> getBookList()
throws RemoteException
{
SystemClock.sleep(5000);
return mBookList;
}
連續單機幾次,就出現了 ANR如要避免這種 ANR, 只需把調用放在非UI 線程即可
public void onButtonClick(View view) {
new Thread(new Runnable() {
@Override
public void run() {
if (mRemoteBookManager != null) {
try {
List<Book> newList = mRemoteBookManager.getBookList();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
}).start();
}
同理,當遠程服務端需要調用客戶端的 listener 中的方法時,被調用的方法運行在客戶端的 Binder 池中,故我們同樣不可以在服務端調用客戶端耗時方法,比如針對 BookManagerService 的 onNewBookArrived 方法,在它內部調用了客戶端的 IOnNewBookArrivedListener 中的 onNewBookArrived 方法,如果客戶端的這個 onNewBookArrived 方法比較耗時的話,確保 BookManagerService 的onNewBookArrived 運行在非 UI 線程中,否則將導致服務端無法響應
private void onNewBookArrived(Book newBook)
throws RemoteException
{
mBookList.add(newBook);//將新書添加到存儲書本的集合中
/* Log.d(TAG,"onNewBookArrived, notify listeners:"+mListenerList.size());
for (int i = 0; i < mListenerList.size(); i++) {//便利存儲的客戶端監聽集合
IOnNewBookArrivedListener listener = mListenerList.get(i);
Log.d(TAG,"onNewBookArrived, notify listeners:"+listener);
listener.onNewBookArrived(newBook);//通過接口回調方式通知客戶端新書已到達
}*/
final int N = mListenerList.beginBroadcast();
for (int i = 0; i < N; i++) {
IOnNewBookArrivedListener l = mListenerList.getBroadcastItem(i);
if (null!=l){
l.onNewBookArrived(newBook);
}
}
mListenerList.finishBroadcast();
}
- 給Binder 設置DeathRecipient 監聽,當Binder 死亡時,我們會收到 binderDied 方法的回調,在 binderDied 方法中我們可以重新綁定遠程服務
- 在onServiceDisconnected 中重連遠程服務
public class ThirdActivity
extends AppCompatActivity
{
private static final String TAG = "BookManagerActivity";
private static final int MESSAGE_NEW_BOOK_ARRAIVED = 1;
private IBookManager mRemoteBookManager;
//構建監聽器 Binder 對象
/**
* 當客戶端發起遠程請求時,由於當前線程會被掛起直至服務端進程返回數據,所以如果一個遠程方法是很耗時的,
* 則不能在UI 線程中發起此遠程請求,爲了避免阻塞UI 線程出現ANR
* 由於服務端的Binder 方法運行在 Binder 的線程池中,所以 Binder 方法不管是否耗時都應該採用同步的方式去實現,因爲它已經運行在一個線程中了
*/
private IOnNewBookArrivedListener mOnNewBookArrivedListener = new IOnNewBookArrivedListener.Stub() {
@Override
public void onNewBookArrived(Book newBook)
throws RemoteException
{
mHandler.obtainMessage(MESSAGE_NEW_BOOK_ARRAIVED, newBook)
.sendToTarget();
}
};
//防止Handler 泄漏
private static class ClientHandler
extends Handler
{
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_NEW_BOOK_ARRAIVED:
Log.d(TAG, "receive new book :" + msg.obj);
break;
default:
super.handleMessage(msg);
break;
}
}
}
private ClientHandler mHandler = new ClientHandler();
//DeathRecipient 方式
private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
if (mRemoteBookManager==null)
return;
mRemoteBookManager.asBinder().unlinkToDeath(mDeathRecipient,0);
mRemoteBookManager=null;
//重新綁定服務
Intent intent = new Intent(ThirdActivity.this, BookManagerService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
};
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//將返回的 IBinder 對象轉成 AIDL 接口所屬類型
mRemoteBookManager = IBookManager.Stub.asInterface(service);
//客戶端綁定遠程服務成功後,給binder 設置死亡代理
try {
mRemoteBookManager.asBinder().linkToDeath(mDeathRecipient,0);
} catch (RemoteException e) {
e.printStackTrace();
}
try {
List<Book> bookList = mRemoteBookManager.getBookList();
// Log.i(TAG,"query book list, list type:"+ bookList.getClass().getCanonicalName());
Log.d(TAG, "query book list: " + bookList.toString());
Book newBook = new Book(3, "Android 開發藝術探索");
mRemoteBookManager.addBook(newBook);
Log.d(TAG, "add book: " + newBook);
List<Book> newList = mRemoteBookManager.getBookList();
Log.d(TAG, "query book list: " + newList.toString());
//註冊監聽器
mRemoteBookManager.registerListener(mOnNewBookArrivedListener);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
//連接斷開,釋放AIDL Binder對象
mRemoteBookManager = null;
Log.e(TAG, "Binder died.");
}
};
public static void acrtionStart(Context context) {
context.startActivity(new Intent(context, ThirdActivity.class));
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_third);
Button btn = findViewById(R.id.button);
final Intent intent = new Intent(this, BookManagerService.class);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
});
}
@Override
protected void onDestroy() {
//如果連接持續,並且Binder未死亡
if (mRemoteBookManager != null && mRemoteBookManager.asBinder()
.isBinderAlive())
{
try {
Log.d(TAG, "unregister listener:" + mOnNewBookArrivedListener);
//註銷監聽
mRemoteBookManager.unregisterListener(mOnNewBookArrivedListener);
} catch (RemoteException e) {
e.printStackTrace();
}
}
unbindService(mConnection);
super.onDestroy();
}
}
- 在onBind 中進行驗證,驗證不通過直接返回null ,這樣驗證失敗的客戶端直接無法綁定服務,至於驗證方式有很多種,比如使用permission 驗證,使用這種驗證方式,我們需要先在 AndroidMenifest 中聲明所需的權限,比如:
<permission android:name="com.example.yhadmin.aidldemo.permission.ACCESS_BOOK_SERVICE"
android:protectionLevel="normal"/>
permission 驗證?定義權限後,就可在BookManagerService 的onBinder 中做權限驗證了,如下所示:
@Nullable
@Override
public IBinder onBind(Intent intent) {
int check = checkCallingOrSelfPermission("com.example.yhadmin.aidldemo.permission.ACCESS_BOOK_SERVICE");
if (check == PackageManager.PERMISSION_DENIED) {
return null;
}
return mBinder;
}
<uses-permission android:name="com.example.yhadmin.aidldemo.permission.ACCESS_BOOK_SERVICE"/>
<uses-permission android:name="com.example.yhadmin.aidldemo.permission.ACCESS_BOOK_SERVICE"/>
其次包名必須以 “com.example.yhadmin” 開始,否則調用服務端的方法會失敗
private Binder mBinder = new IBookManager.Stub() {
@Override
public List<Book> getBookList()
throws RemoteException
{
SystemClock.sleep(5000);
return mBookList;
}
@Override
public void addBook(Book book)
throws RemoteException
{
mBookList.add(book);
}
//註冊
@Override
public void registerListener(IOnNewBookArrivedListener listener)
throws RemoteException
{
/* if (!mListenerList.contains(listener)){
mListenerList.add(listener);//添加監聽
}else {
Log.d(TAG,"already exists.");
}*/
mListenerList.register(listener);
Log.d(TAG,
"regeisterListener,current size:" + mListenerList.getRegisteredCallbackCount());
}
//解註冊
@Override
public void unregisterListener(IOnNewBookArrivedListener listener)
throws RemoteException
{
/*if (mListenerList.contains(listener)){
mListenerList.remove(listener);//移除監聽
Log.d(TAG,"unregister listener succeed.");
}else {
Log.d(TAG,"not found, can not unregister.");
}
*/
mListenerList.unregister(listener);
Log.d(TAG,
"unregeisterListener,current size:" + mListenerList.getRegisteredCallbackCount());
}
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException
{
int check = checkCallingOrSelfPermission("com.example.yhadmin.aidldemo.permission.ACCESS_BOOK_SERVICE");
if (check == PackageManager.PERMISSION_DENIED) {
return false;
}
String packageName = null;
String[] packages = getPackageManager().getPackagesForUid(getCallingUid());
if (packages != null && packages.length > 0) {
packageName=packages[0];
}
if (!packageName.startsWith("com.example.yhadmin")){
return false;
}
return super.onTransact(code, data, reply, flags);
}
};
還可以爲Service 指定 android:permission屬性等進行權限驗證