Android IPC机制(二)

Android中的IPC方式

1.使用Bundle

我们知道,四大组件中 三大组件(activity,service,Receiver)都是支持在Intent中传递Bundle数据的,由于Bundle实现了Parcelable接口,所以它可以方便的在不同的进程间传输,基于这一点,当我们在一个进程中启动了另一个进程的Activity,asevice,receiver,我们可以用Bundle中附加我们需要传输给远程进程的信息并通过Intent发送出去。

2.使用文件共享

//在MainActivity中修改
private void persistToFile() {
        new Thread(new Runnable() {

            @Override
            public void run() {
                User user = new User(1, "hello world", false);
                File dir = new File(MyConstants.CHAPTER_2_PATH);
                if (!dir.exists()) {
                    dir.mkdirs();
                }
                File cachedFile = new File(MyConstants.CACHE_FILE_PATH);
                ObjectOutputStream objectOutputStream = null;
                try {
                    objectOutputStream = new ObjectOutputStream(
                            new FileOutputStream(cachedFile));
                    objectOutputStream.writeObject(user);
                    Log.d(TAG, "persist user:" + user);
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    MyUtils.close(objectOutputStream);
                }
            }
        }).start();
    }
//在SecondActivity中修改
private void recoverFromFile() {
        new Thread(new Runnable() {

            @Override
            public void run() {
                User user = null;
                File cachedFile = new File(MyConstants.CACHE_FILE_PATH);
                if (cachedFile.exists()) {
                    ObjectInputStream objectInputStream = null;
                    try {
                        objectInputStream = new ObjectInputStream(
                                new FileInputStream(cachedFile));
                        user = (User) objectInputStream.readObject();
                        Log.d(TAG, "recover user:" + user);
                    } catch (IOException e) {
                        e.printStackTrace();
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    } finally {
                        MyUtils.close(objectInputStream);
                    }
                }
            }
        }).start();
    }

3.使用Messenger

Messenger可以翻译为信使,顾名思义,通过它可以在不同进程传递Message对象,它是一种轻量级的IPC方案,底层是通过AIDL实现的
(以串行方式处理客户端发来的信息,不适合处理并发请求)
实现一个Messenger有如下几个步骤,分为服务端和客户端

1. 服务端进程
首先要创建一个service来处理客户端的连接请求,同时创建一个Handler并通过它来创建一个Messenger对象,然后在Service的onBind中返回这个Messenger对象底层的Binder即可
2.客户端进程
客户端进程中,首先要绑定服务端的Service,绑定成功后用服务端返回 的IBinder对象创建一个Messenger,通过这个Messenger就可以向服务器发送消息了,发送消息的对象为Message对象,如果需要服务端能够回应客户端,就和服务端一样,我们还需要创建一个Handler并创建一个新的Messager,并把这个Messenger对象通过message的replyTo参数传递给服务端,服务daunt通过这个replyTo参数就可以回应客户端了

首先看服务端代码:

public class MessagerService extends Service {
    private static final String TAG = MessagerService.class.getSimpleName();

    private static class MessageHandler extends Handler{
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){

            }
            super.handleMessage(msg);
        }
    }
    private final Messenger mMessenger = new Messenger(new MessageHandler());
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mMessenger.getBinder();
    }
}

然后在清单文件中注册:

<service
            android:name=".messenger.MessengerService"
            android:process=":remote" >
        </service>

客户端的代码,实现比较简单

public class MessengerActivity extends AppCompatActivity {
    private static final  String TAG = MessengerActivity.class.getSimpleName();
    private Messenger messenger;
    public static final int MSG_FROM_CLIENT = 0;
    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            messenger = new Messenger(service);
            Message message = Message.obtain(null,MSG_FROM_CLIENT);
            Bundle bundle = new Bundle();
            bundle.putString("msg","xxxx");
            message.setData(bundle);
            try {
                messenger.send(message);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_messenger);
        Intent intent = new Intent(this,MessagerService.class);
        bindService(intent,connection, Context.BIND_AUTO_CREATE);
    }
}

服务端回复客户端

public class MessagerService extends Service {
    private static final String TAG = MessagerService.class.getSimpleName();

    private static class MessageHandler extends Handler{
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case MSG_FROM_CLIENT:
                    Messenger client = msg.replyTo;
                    Message replyMessage = Message.obtain(null,MSG_FROM_CLIENT);
                    Bundle bundle = new Bundle();
                    bundle.putString("reply","666");
                    replyMessage.setData(bundle);
                    try {
                        client.send(replyMessage);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                    break;
            }
            super.handleMessage(msg);
        }
    }
    private final Messenger mMessenger = new Messenger(new MessageHandler());
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mMessenger.getBinder();
    }
}
public class MessengerActivity extends AppCompatActivity {
    private static final  String TAG = MessengerActivity.class.getSimpleName();
    private Messenger messenger;
    public static final int MSG_FROM_CLIENT = 0;
    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            messenger = new Messenger(service);
            Message message = Message.obtain(null,MSG_FROM_CLIENT);
            Bundle bundle = new Bundle();
            bundle.putString("msg","xxxx");
            message.setData(bundle);
            //注意这一句
            message.replyTo = REPLYmessenger;
            try {
                messenger.send(message);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_messenger);
        Intent intent = new Intent(this,MessagerService.class);
        bindService(intent,connection, Context.BIND_AUTO_CREATE);
    }
    //定义接受回传的地方
    private static Messenger REPLYmessenger = new Messenger(new MessageHandle());
    private static class  MessageHandle extends Handler{
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            //接受
        }
    }
}

4.使用AIDL

1.服务端
首先创建一个service用来监听客户端的连接请求,然后创建一个AIDL文件,将暴露给客户端的接口在这个AIDL文件中声明,最后在Service中实现这个AIDL接口即可。

2.客户端
首先绑定service,绑定成功后,将服务端返回的Binder对象转换成AIDL接口所属的类似,然后就可以调用AIDL中的方法了。

3.AIDL接口的创建
创建出现错误参考

http://www.mamicode.com/info-detail-1357976.html

在AIDL中,并不是所有数据类型都支持,支持的数据类型如下:

  • 基本数据类型(int ,long,char,boolean,double,float)
  • String 和CharSequence
  • List:只支持ArrayList,里面每个元素都必须都能够被支持
  • Map:只支持HashMap,里面每个元素都必须都能够被支持
  • Parcelable:所有实现了Parcelable 接口的对象(需要import进去)
  • AIDL:所有AIDL接口本身也可以在AIDL文件中使用(需要import进去)

**注意:**1.如果AIDL文件中用到一个自定义的Parcelable对象,那么必须创建一个和它同名的AIDL文件,并声明它为Parcelable类型,列如:
2.AIDL接口中只支持方法,不支持声明静态变量,这一点区别于传统的接口

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;
    }

    public int describeContents() {
        return 0;
    }

    public void writeToParcel(Parcel out, int flags) {
        out.writeInt(bookId);
        out.writeString(bookName);
    }

    public static final Parcelable.Creator<Book> CREATOR = new Parcelable.Creator<Book>() {
        public Book createFromParcel(Parcel in) {
            return new Book(in);
        }

        public Book[] newArray(int size) {
            return new Book[size];
        }
    };

    private Book(Parcel in) {
        bookId = in.readInt();
        bookName = in.readString();
    }

    @Override
    public String toString() {
        return String.format("[bookId:%s, bookName:%s]", bookId, bookName);
    }

}
package com.ryg.chapter_2.aidl;

parcelable Book;

4.远程服务端Service的实现

public class BookManagerService extends Service {

    private static final String TAG = BookManagerService.class.getSimpleName();

    private CopyOnWriteArrayList<Book> list = new CopyOnWriteArrayList<>();

    private Binder binder = new IBookManager.Stub(){

        @Override
        public List<Book> getBookList() throws RemoteException {
            return  list;
        }

        @Override
        public void addBook(Book book) throws RemoteException {
            list.add(book);
        }
    };

    @Override
    public void onCreate() {
        super.onCreate();
        list.add(new Book(1,"ANDROID"));
        list.add(new Book(2,"IOS"));
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }
}

这里使用CopyOnWriteArrayList,这个CopyOnWriteArrayList支持并发读/写,AIDL是在服务端的Binder线程池中执行的,因此当多个客户端进行连接的时候,会存在多个线程同时访问的情形,所以我们要在AIDL方法中处理线程同步,而我们在这里直接使用CopyOnWriteArrayList来实现自动的线程同步。

//清单文件中注册
<service android:name=".BookManagerService"
             android:process=":remote"/>

5.客户端的实现

public class BookManagerActivity extends AppCompatActivity {
    private static final String TAG = BookManagerActivity.class.getSimpleName();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_book_manager);
        Intent intent = new Intent(this,BookManagerService.class);
        bindService(intent,connection, Context.BIND_AUTO_CREATE);
    }
    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            IBookManager bookManager = IBookManager.Stub.asInterface(service);
            try {
                List<Book> bookList = bookManager.getBookList();
            } catch (RemoteException e) {
                e.printStackTrace();
            }

        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    @Override
    protected void onDestroy() {
        unbindService(connection);
        super.onDestroy();
    }
}

这里要实现一个新的功能就是有新书到的时候,会提醒对每一本新书感兴趣的用户,这是一种典型的观察者模式,在开发中经常用到,我们这里进行一个模拟。
首先,我们需要提供一个AIDL接口,每个用户都需要实现这个接口并且向图书馆申请新书的提醒功能,当然用户也可以取消这种提醒。之所以选择AIDL接口而不是普通的接口,是因为AIDL中无法使用普通接口,这里我们新创建一个IOnNewBookArrivedListener.aidl文件,我们期望的情况是:当服务器有新书到来的时候,我们会通知每一个已经申请提醒功能的用户。从程序上讲就是调用所有IOnNewBookArrivedListener对象中的onNewBookArrived方法,并把新书通过参数推荐个客户端。

package com.aspsine.mobi.chapter2;

// Declare any non-default types here with import statements
import com.aspsine.mobi.chapter2.Book;
interface IOnNewBookArrivedListener {
   void onNewBookArrived(in Book newBook);
}

除了要新加一个AIDL接口,还需要在原有的接口中添加两个方法,即订阅这个功能和取消订阅的监听事件

package com.aspsine.mobi.chapter2;

// Declare any non-default types here with import statements
import com.aspsine.mobi.chapter2.Book;
import com.aspisne.mobi.chapter2.IOnNewBookArrivedListener;
interface IBookManager {
   List<Book> getBookList();
   void addBook(in Book book);
   void registerListener(IOnNewBookArrivedListener listener);
   void unregisterListener(IOnNewBookArrivedListener listener);
}

接着,服务端中Service的实现也要稍微修改一下,主要是Service中IBookManager.Stub()的实现,因为我们在IBookManager中增加了两个方法,所以在IBookManager.Stub()中也要实现这两个方法。同时,在BookManagerService中还要开启一个线程,每个5秒向书库增加一本书然后提醒用户。

public class BookManagerService extends Service {

    private static final String TAG = BookManagerService.class.getSimpleName();

    private AtomicBoolean mIsServiceDestoryed = new AtomicBoolean();

    private CopyOnWriteArrayList<IOnNewBookArrivedListener> mListenerList = new
            CopyOnWriteArrayList<>();

    private CopyOnWriteArrayList<Book> list = new CopyOnWriteArrayList<>();
    //这里别调用的方法运行在Binder线程池中,如果是耗时的,则避免ui线程去访问这个方法
    private Binder binder = new IBookManager.Stub(){

        @Override
        public List<Book> getBookList() throws RemoteException {
            return  list;
        }

        @Override
        public void addBook(Book book) throws RemoteException {
            list.add(book);
        }

        @Override
        public void registerListener(IOnNewBookArrivedListener listener) throws RemoteException {
            if(!mListenerList.contains(listener)){
                mListenerList.add(listener);
            }else {
                Log.d(TAG,"listener exists");
            }
        }

        @Override
        public void unregisterListener(IOnNewBookArrivedListener listener) throws RemoteException {
             if(mListenerList.contains(listener)){
                 mListenerList.remove(listener);
             }else {
                 Log.d(TAG,"listener not register");
             }
        }
    };

    @Override
    public void onCreate() {
        super.onCreate();
        list.add(new Book(1,"ANDROID"));
        list.add(new Book(2,"IOS"));
        new Thread(new ServiceWorker()).start();
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }
    //模拟延迟操作
    private class ServiceWorker implements Runnable {

        @Override
        public void run() {
            while (!mIsServiceDestoryed.get()) {
                try {
                    Thread.sleep(5000);
                    int bookId = list.size() +1;
                    Book book = new Book(bookId,"new  book" +bookId);
                    onNewBookArrived(book);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    //给每个listener都执行onNewBookArrived方法
    private void  onNewBookArrived(Book book) throws RemoteException{
         list.add(book);
        for (int i = 0; i < mListenerList.size(); i++) {
             IOnNewBookArrivedListener listener = mListenerList.get(i);
             listener.onNewBookArrived(book);
        }
    }

    @Override
    public void onDestroy() {
        mIsServiceDestoryed.set(true);
        super.onDestroy();
    }
}

修改客户端

public class BookManagerActivity extends AppCompatActivity  {
    private static final String TAG = BookManagerActivity.class.getSimpleName();
    private static final int MESSAGE_NEW_BOOK_ARRIVED = 1;
    private IBookManager mRemoteBookManager;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_book_manager);
        Intent intent = new Intent(this,BookManagerService.class);
        bindService(intent,connection, Context.BIND_AUTO_CREATE);
    }
    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            IBookManager bookManager = IBookManager.Stub.asInterface(service);
            try {
                mRemoteBookManager = bookManager;
                List<Book> bookList = bookManager.getBookList();
                Book book = new Book(3,"ANDROID JINJIE");
                bookManager.addBook(book);
                //注册新书监听
                bookManager.registerListener(iOnNewBookArrivedListener);
            } catch (RemoteException e) {
                e.printStackTrace();
            }

        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
             mRemoteBookManager = null;
        }
    };

    @Override
    protected void onDestroy() {
        //取消注册
        if(mRemoteBookManager != null && mRemoteBookManager.asBinder().isBinderAlive()){
            try {
                mRemoteBookManager.unregisterListener(iOnNewBookArrivedListener);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
        unbindService(connection);
        super.onDestroy();
    }
    //切换到主线程
    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
           switch (msg.what){
               case MESSAGE_NEW_BOOK_ARRIVED:
                   //更新ui
                   break;
           }
        }
    };
    private IOnNewBookArrivedListener iOnNewBookArrivedListener = new IOnNewBookArrivedListener.Stub(){

        @Override
        public void onNewBookArrived(Book newBook) throws RemoteException {
            mHandler.obtainMessage(MESSAGE_NEW_BOOK_ARRIVED,newBook).sendToTarget();
        }
    };
}

利用RemoteCallbackList 进行跨进程的注册和解注册(p85)
RemoteCallbackList 是系统专门提供的用于删除跨进程的listener的接口,RemoteCallbackList 是一个泛型,支持任意的AIDL接口,这点从它的声明可以看出来,因为所以的AIDL都是继承自IInterface

public class RemoteCallbackList < E extends IInterface>

它的工作原理很简单,在它的内部有一个Map结构专门用来保存所有的AIDL回调,这个Map的key是IBinder,value是Callback类型

ArrayMap<IBinder,Callback> mCallbacks = new ArrayList<IBinder,Callback>();

其中Callback中封装了真正的远程listener,当客户端注册listener时,它会把这个listener的信息存入mCallbacks,同时RemoteCallbackList还有一个很重要的功能,那就是在客户端进程终止后,能够自动移除客户端注册的listener,另外,RemoteCallbackList内部自动实现了线程同步的功能,所有用他进行注册和解注册,不需要做额外的线程同步工作。
这里使用RemoteCallbackList很简单,只要把CopyOnWriteArrayList替换成RemoteCallbackList就好了,然后修改registerListener,unregisterListener俩个接口

private RemoteCallbackList<IOnNewBookArrivedListener> mListenerList = new
            RemoteCallbackList<>();
 @Override
        public void registerListener(IOnNewBookArrivedListener listener) throws RemoteException {
            mListenerList.register(listener);
        }

        @Override
        public void unregisterListener(IOnNewBookArrivedListener listener) throws RemoteException {
            mListenerList.unregister(listener);
        }
//给每个listener都执行onNewBookArrived方法
    private void  onNewBookArrived(Book book) throws RemoteException{
         list.add(book);
         final  int N = mListenerList.beginBroadcast();
        for (int i = 0; i < N; i++) {
            IOnNewBookArrivedListener listenr = mListenerList.getBroadcastItem(i);
            if(listenr != null){
                listenr.onNewBookArrived(book);
            }
        }
        mListenerList.finishBroadcast();
    }

注意使用RemoteCallbackList时,我们无法向list那样操作他,因为它并不是一个list,遍历RemoteCallbackList需要按上面的方法去做,其中
beginBroadcast()和finishBroadcast()必须配对使用;

总结注意:
我们知道客户端调用远程服务的方法,被调用的方法运行在服务端的Binder线程池中同时客户端线程会被挂起,这个时候如果服务端方法执行比较耗时,就会导致客户端线程长时间阻塞在那里,如果这个客户端线程是UI线程的话,就会导致客户端ANR,因此,如果我们知道某个远程方法是耗时的,那么久避免在客户端UI线程中去访问远程方法。由于客户端的onServiceConnected,onServiceDisconnected方法都是运行在UI线程里面的,所以也不可以再它们里面直接调用服务器的耗时方法,。另外,由于服务端的方法本身就运行在服务端的Binder线程池中,所以服务daunt本身是可以执行耗时操作的,,这个时候千万不要在服务端去开启线程进行异步操作。
那么避免这个ANR很简单,我们把方法的调用放在非UI线程中就可以了。

public void onButton1Click(View view) {
        Toast.makeText(this, "click button1", Toast.LENGTH_SHORT).show();
        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 方法,如果这个方法在客户端中是比较耗时的,请保证BookManagerService的onNewBookArrived方法运行在非UI线程中,否则服务端无响应

    private void  onNewBookArrived(Book book) throws RemoteException{
         list.add(book);
         final  int N = mListenerList.beginBroadcast();
        for (int i = 0; i < N; i++) {
            IOnNewBookArrivedListener listenr = mListenerList.getBroadcastItem(i);
            if(listenr != null){
                listenr.onNewBookArrived(book);
            }
        }

另外,由于客户端的IOnNewBookArrivedListener的onNewBookArrived 方法运行在客户端的Binder线程池中,所有不能再它里面进行访问UI的相关操作,如果要访问,要切换到主线程,用handler来实现了。

同时为了程序的健壮性,Binder如果意外死亡,这是我们需要重新连接服务,这里与两个方法,一个是给Binder设置DeathRecipient监听,当Binder死亡时会在binderDied中回调,我们就可以在这个方法中重新连接服务。另一个方法就是在onServiceDisconnected中重新连接服务。两者的区别在于onServiceDisconnected是在客户端的UI线程中被回调,而
binderDied是在客户端的Binder线程池中被回调的。这就是说binderDied不能访问我们的ui.

 private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
        @Override
        public void binderDied() {
            Log.d(TAG, "binder died. tname:" + Thread.currentThread().getName());
            if (mRemoteBookManager == null)
                return;
            mRemoteBookManager.asBinder().unlinkToDeath(mDeathRecipient, 0);
            mRemoteBookManager = null;
            // TODO:这里重新绑定远程Service
            bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
        }
    };
 @Override
        public void onServiceDisconnected(ComponentName name) {
             mRemoteBookManager = null;
             //重启服务
             bindService(intent,connection, Context.BIND_AUTO_CREATE);
        }

最后在AIDL中如何使用权限验证功能。默认情况下,我们的远程服务任何人都可以进行连接,但这应该不是我们要看到的,所以必须给服务加入权限验证功能,权限验证失败则无法调用服务中的方法。常用又两种方法

第一种:我们可以在onBind中进行验证,验证不通过返回为null,这样验证失败 的客户端就无法绑定服务了。至于验证的方式有多种,比如首页permission验证。使用这种验证,我们首先要在清单文件中声明所需的权限

//关于permission 的定义方式再找
 <permission android:name="com.aspsine.mobi.chapter2.permission.ACCESS_BOOK_SERVICE"
        android:protectionLevel="normal"/>

然后在onBind中验证

@Nullable
    @Override
    public IBinder onBind(Intent intent) {
        int check = checkCallingOrSelfPermission("com.aspsine.mobi.chapter2.permission.ACCESS_BOOK_SERVICE");
        if(check == PackageManager.PERMISSION_DENIED){
            return  null;
        }
        return binder;
    }

如果我们内部的应用想绑定我们的服务只需定义如下就可以

<uses-permission android:name="com.aspsine.mobi.chapter2.permission.ACCESS_BOOK_SERVICE"/>

第二种方法:
我们可以在服务端的onTranact方法中进行权限认证,如果认证失败则直接返回false,这样服务端就不会终止执行AIDL中的方法,从而达到保护服务端的效果。至于验证方式有多中,可以使用第一种方法的验证方式,还可以通过Uid和Pid来验证,通过getCallingUid和getCallingPid可以拿到客户端所属应用的Uid和Pid,通过这两个参数我们可以进行一些验证工作,比如验证包名,下面方法即验证了permission有验证了Uid和Pid。

 @Override
        public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
            //验证permission
            int check = checkCallingOrSelfPermission("com.aspsine.mobi.chapter2.permission.ACCESS_BOOK_SERVICE");
            if(check == PackageManager.PERMISSION_DENIED){
                return false;
            }
            //验证包名是不是以com.aspsine开头
            String packageName = null;
            String[] packages = getPackageManager().getPackagesForUid(getCallingUid());
            if(packages != null && packages.length > 0){
                 packageName = packages[0];
            }
            if(!packageName.startsWith("com.aspsine")){
                return  false;
            }
            return super.onTransact(code,data,reply,flags);
        }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值