IPC、Window小结

1、IPC机制

1、Android IPC简介

  • IPC:含义为进程间通信或者跨进程通信。

2、Android中的多进程模式

  • Android中开启多进程方法,就是给四大组件在AndroidMenifest指定android:process属性,还有一种非常规的,就是通过JNI在native层去fork一个新的进程。
  • process指定进程命名:以":"开头的进程属于当前应用的私有进程,其他应用的组件不可以和它跑在同一个进程中,而进程名不以":"开头的进程属于全局进程,其他应用通过ShareUID方式可以和它跑在同一个进程中。
  • Android系统会为每个应用分配一个唯一的UID,具体相同UID的应该才能共享数据。两个应用通过ShareUID跑在同一个进程中是有要求的,需要这个两个应用的有相同的ShareUID并且签名相同才行。
  • 多进程会造成:
    静态成员和单例模式完全失效。
    线程同步机制完全失效。
    SharedPreferences的可靠性下降。
    Application会多次创建。
  • SharedPreferences不支持两个进程同时去执行写操作,否则会导致一定几率的数据丢失,这是因为SharedPreferences底层是通过读写XML文件来实现的,并发写显然3是可能出现问题的,甚至并发读都有可能出现问题。

3、IPC基础

  • Serializable
    serialVersionUID是用来辅助序列化与反序列化的,比如删除某个成员变量或增加新的成员变量,如果不指定serialVersionUID那么程序会挂掉,但是如果类发生了非常规性改变,如修改类名,修改成员变量的类型,尽管指定serialVersionUID,反序列化还是失败。
    静态成员变量属于类不属于对象,所以不会参与序列化过程,其次用transient关键字标记的成员变量不参与序列化过程。

  • Parcelable
    Parcelable是Android中的序列化方式,效率很高,主要用在内存序列化,而Serializable的Java的序列化接口,虽然简单但开销大,需要大量I/O操作,主要是在文件序列化。

  • Binder
    从IPC角度来说,Binder是Android中的一种跨进程通信方式;从Android Framework角度来说,Binder是ServiceManager连接各种Manager(ActivityManager、WindowManager等)和相应ManagerService的桥梁;从Android应用层来说,Binder是客户端和服务端进行通信的媒介,当bindservice的时候,服务端会返回一个包含服务端业务调用的Binder对象,通过这个Binder对象,客户端就可以获取服务端提供的服务或者数据,这里的服务包括普通服务和基于AIDL的服务。
    以AIDL来分析Binder机制:
    AIDL:

    public interface IBookManager extends android.os.IInterface {
          /**
           * Binder类
           */
          public static abstract class Stub extends android.os.Binder implements com.myapplication.IBookManager {
      
              //Binder的唯一标识
              private static final java.lang.String DESCRIPTOR = "com.myapplication.aidl.IBookManager";
      
              /**
               * Construct the stub at attach it to the interface.
               */
              public Stub() {
                  this.attachInterface(this, DESCRIPTOR);
              }
      
              /**
               * 用于将服务端的Binder对象转换成客户端所需要的AIDL接口类型的对象
               * 在同一进程,返回服务端Stub对象本身,不在同一进程返回系统封装后的Stub.proxy对象
               */
              public static com.myapplication.IBookManager asInterface(android.os.IBinder obj) {
                  if ((obj == null)) {
                      return null;
                  }
                  //如果不是同一个进程,其实是Binder的内部类BinderProxy,它的queryLocalInterface返回null
                  android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
                  if (((iin != null) && (iin instanceof com.myapplication.IBookManager))) {
                      return ((com.myapplication.IBookManager) iin);
                  }
                  return new com.myapplication.IBookManager.Stub.Proxy(obj);
              }
      
              @Override
              public android.os.IBinder asBinder() {
                  return this;
              }
      
              /**
               * 运行在服务端的Binder线程池中,返回false,则客户端请求失败
               */
              @Override
              public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
                  switch (code) {
                      case INTERFACE_TRANSACTION: {
                          reply.writeString(DESCRIPTOR);
                          return true;
                      }
                      case TRANSACTION_getBookList: {
                          data.enforceInterface(DESCRIPTOR);
                          java.util.List _result = this.getBookList();
                          reply.writeNoException();
                          reply.writeTypedList(_result);
                          return true;
                      }
                      case TRANSACTION_addBook: {
                          data.enforceInterface(DESCRIPTOR);
                          com.myapplication.aidl.Book _arg0;
                          if ((0 != data.readInt())) {
                              _arg0 = com.myapplication.aidl.Book.CREATOR.createFromParcel(data);
                          } else {
                              _arg0 = null;
                          }
                          this.addBook(_arg0);
                          reply.writeNoException();
                          return true;
                      }
                  }
                  return super.onTransact(code, data, reply, flags);
              }
      
              private static class Proxy implements com.myapplication.IBookManager {
                  private android.os.IBinder mRemote;
      
                  Proxy(android.os.IBinder remote) {
                      mRemote = remote;
                  }
      
                  @Override
                  public android.os.IBinder asBinder() {
                      return mRemote;
                  }
      
                  public java.lang.String getInterfaceDescriptor() {
                      return DESCRIPTOR;
                  }
      
                  /**
                   * Demonstrates some basic types that you can use as parameters
                   * and return values in AIDL.
                   */
                  @Override
                  public java.util.List getBookList() throws android.os.RemoteException {
                      android.os.Parcel _data = android.os.Parcel.obtain();  //输入型
                      android.os.Parcel _reply = android.os.Parcel.obtain();  //输出型
                      java.util.List _result;   //声明返回对象
                      try {
                          _data.writeInterfaceToken(DESCRIPTOR);
                          mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);  //调用transact后会调用onTransact
                          _reply.readException();
                          _result = _reply.createTypedArrayList(com.myapplication.aidl.Book.CREATOR);
                      } finally {
                          _reply.recycle();
                          _data.recycle();
                      }
                      return _result;
                  }
      
                  @Override
                  public void addBook(com.myapplication.aidl.Book book) throws android.os.RemoteException {
                      android.os.Parcel _data = android.os.Parcel.obtain();
                      android.os.Parcel _reply = android.os.Parcel.obtain();
                      try {
                          _data.writeInterfaceToken(DESCRIPTOR);
                          if ((book != null)) {
                              _data.writeInt(1);
                              book.writeToParcel(_data, 0);
                          } else {
                              _data.writeInt(0);
                          }
                          mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
                          _reply.readException();
                      } finally {
                          _reply.recycle();
                          _data.recycle();
                      }
                  }
              }
      
              /**
               * 记录客户端请求那个方法
               */
              public static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
              public static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
          }
      
          /**
           * Demonstrates some basic types that you can use as parameters
           * and return values in AIDL.
           */
          public java.util.List getBookList() throws android.os.RemoteException;
      
          public void addBook(com.myapplication.aidl.Book book) throws android.os.RemoteException;
      }
    

    服务端:

    public class BookService extends Service {
      
          private CopyOnWriteArrayList mBooks = new CopyOnWriteArrayList<>();
      
          @Nullable
          @Override
          public IBinder onBind(Intent intent) {
              return mBinder;
          }
      
          @Override
          public void onCreate() {
              super.onCreate();
              mBooks.add(new Book(1,"Android"));
          }
      
          private Binder mBinder = new IBookManager.Stub(){
              @Override
              public List getBookList() throws RemoteException {
                  return mBooks;
              }
      
              @Override
              public void addBook(Book book) throws RemoteException {
                  mBooks.add(book);
              }
          };
      }
    

    客户端:

    public class BindActivity extends AppCompatActivity {
      
          @Override
          protected void onCreate(@Nullable Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);
              Intent intent = new Intent(this,BookService.class);
              bindService(intent,mConnection,BIND_AUTO_CREATE);
          }
      
          private ServiceConnection mConnection = new ServiceConnection() {
              @Override
              public void onServiceConnected(ComponentName name, IBinder service) {
      
                  IBookManager iBookManager = IBookManager.Stub.asInterface(service);
                  Log.d("----",iBookManager.toString());
                  try {
                      List bookList = iBookManager.getBookList();
                      Log.d("----",bookList.toString());
                      iBookManager.addBook(new Book(2,"ios"));
                      Log.d("----", iBookManager.getBookList().toString());
                  } catch (RemoteException e) {
                      e.printStackTrace();
                  }
              }
      
              @Override
              public void onServiceDisconnected(ComponentName name) {
      
              }
          };
      
          @Override
          protected void onDestroy() {
              super.onDestroy();
              unbindService(mConnection);
          }
      }
    

    给Binder设置死亡代理:

     mIBookManager = IBookManager.Stub.asInterface(service);
          try {
              service.linkToDeath(mDeathRecipient,0);
          } catch (RemoteException e) {
              e.printStackTrace();
          }
     private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
      @Override
      public void binderDied() {
          mIBookManager.asBinder().unlinkToDeath(mDeathRecipient,0);
          mIBookManager = null;
          //重新连接
      }
    };
    

4、Android中的IPC方式

  • 使用Messenger
    服务端:

    public class MessengerService extends Service {
      
          @Nullable
          @Override
          public IBinder onBind(Intent intent) {
              return mMessenger.getBinder();
          }
      
          private Messenger mMessenger = new Messenger(new MessengerHandler());
      
          private class MessengerHandler extends Handler{
              @Override
              public void handleMessage(Message msg) {
                  switch (msg.what){
                      case 1:
                          Log.d("------","收到了"+msg.getData().getString("msg"));
                          Messenger replyTo = msg.replyTo;
                          Message message = Message.obtain(null,1);
                          Bundle bundle = new Bundle();
                          bundle.putString("reply","收到了");
                          message.setData(bundle);
                          try {
                              replyTo.send(message);  //回复
                          } catch (RemoteException e) {
                              e.printStackTrace();
                          }
                          break;
                      default:
                          super.handleMessage(msg);
                  }
              }
          }
      }
    

    注册单独进程:

     
    

    客户端:

    public class MainActivity extends AppCompatActivity {
      
          private Messenger mMessenger;
      
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);
              Intent intent = new Intent(this,MessengerService.class);
              bindService(intent,mConnection,BIND_AUTO_CREATE);
          }
      
      
          private ServiceConnection mConnection = new ServiceConnection() {
              @Override
              public void onServiceConnected(ComponentName name, IBinder service) {
                  mMessenger = new Messenger(service);
              }
      
              @Override
              public void onServiceDisconnected(ComponentName name) {
      
              }
          };
      
          public void send(View view){
              Message message = Message.obtain(null, 1);
              Bundle bundle = new Bundle();
              bundle.putString("msg","我的客户端");
              message.setData(bundle);
              message.replyTo = mReplyMessenger;  //指定回应的Messenger
              try {
                  mMessenger.send(message);
              } catch (RemoteException e) {
                  e.printStackTrace();
              }
          }
      
          private Messenger mReplyMessenger = new Messenger(new MessengerHandle());
      
          private class MessengerHandle extends Handler{
              @Override
              public void handleMessage(Message msg) {
      
                  switch (msg.what){
                      case 1:
                          Log.d("------","回复了"+msg.getData().getString("reply"));
                          break;
                  }
              }
          }
      
          @Override
          protected void onDestroy() {
              super.onDestroy();
              unbindService(mConnection);
          }
      }  
    
  • AIDL
    支持的数据类型:
    基本数据类型(int、long、char、boolean、double等);
    String和CharSequence;
    List:只支持ArrayList,里面的每个元素都必须能够被AIDL支持;
    Map:只支持HashMap,里面的每个元素都必须被AIDL支持,包括key和value;
    Parcelable:所有实现了Parcelable;
    AIDL:所有的AIDL接口本身也可以在AIDL文件中使用。

    使用注意:
    Parcelable对象和AIDL对象必须要显示import进来;
    如果AIDL文件用到自定义的Parcelable对象,那么必须新建一个和它同名的AIDL文件,比如Book.aidl,然后添加内容:parcelable Book;
    AIDL除了基本数据类型,其他类型的参数必须标上方向:in、out、inout,表示输入型参数、输出型参数、输入输出型参数;
    AIDL只支持方法,不支持声明静态常量。

    CopyOnWriteArrayList:
    支持并发读写,AIDL方法在服务端的Binder线程池中执行,当多个客户端同时连接时的情况。

    RemoteCallbackList:
    RemoteCallbackList是系统专门提供用于删除跨进程listener的接口

    private RemoteCallbackList<对应的接口> mCallbackList = new RemoteCallbackList<>();
    mCallbackList.register(对应的接口);
    mCallbackList.unregister(对应的接口);
    int n = mCallbackList.beginBroadcast();
    for (int i = 0; i < n; i++) {
          mCallbackList.getBroadcastItem(i).xxxx;
    }
    mCallbackList.finishBroadcast();
    
  • Socket
    服务端:

    public class TCPServerService extends Service {
      
          private boolean mIsServiceDestroyed = false;
          private String[] mDefinedMessages = {"你好啊","你叫我?","1111111"};
      
          @Override
          public void onCreate() {
              super.onCreate();
              new Thread(new TcpServer()).start();
          }
      
          @Override
          public void onDestroy() {
              super.onDestroy();
              mIsServiceDestroyed = true;
          }
      
          @Nullable
          @Override
          public IBinder onBind(Intent intent) {
              return null;
          }
      
          private class TcpServer implements Runnable{
      
              @Override
              public void run() {
                  ServerSocket serverSocket = null;
                  try {
                      serverSocket = new ServerSocket(8688);
                  } catch (IOException e) {
                      e.printStackTrace();
                  }
      
                  while (!mIsServiceDestroyed){
                      try {
                          final Socket client = serverSocket.accept();
                          Log.d("----",client.toString());
                          new Thread(new Runnable() {
                              @Override
                              public void run() {
                                  try {
                                      respone(client);
                                  } catch (IOException e) {
                                      e.printStackTrace();
                                  }
                              }
                          }).start();
                      } catch (IOException e) {
                          e.printStackTrace();
                      }
                  }
              }
          }
      
          private void respone(Socket client) throws IOException {
              BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
              PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(client.getOutputStream())),true);
              out.println("欢迎来到聊天室");
              while (!mIsServiceDestroyed){
                  String str = in.readLine();
                  if (str == null){
                      break;
                  }
                  Log.d("-----",str);
                  int i = new Random().nextInt(mDefinedMessages.length);
                  String msg = mDefinedMessages[i];
                  out.println(msg);
              }
              in.close();
              out.close();
              client.close();
          }
      }
    

    客户端:

    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
      
          private TextView tvMessage;
          private EditText etInput;
      
          private Handler mHandler = new Handler() {
              @Override
              public void handleMessage(Message msg) {
                  switch (msg.what) {
                      case 1:
                          tvMessage.setText(tvMessage.getText()+(String)msg.obj);
                          break;
                      case 2:
                          btnSend.setEnabled(true);
                          break;
                  }
              }
          };
          private Button btnSend;
          private Socket mClientSocker;
          private PrintWriter mPrintWriter;
      
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);
              initView();
      
              Intent intent = new Intent(this,TCPServerService.class);
              startService(intent);
              new Thread(new Runnable() {
                  @Override
                  public void run() {
                      connectTCPServer();
                  }
              }).start();
          }
      
      
          private void initView() {
              tvMessage = (TextView) findViewById(R.id.tv_message);
              etInput = (EditText) findViewById(R.id.et_input);
              btnSend = (Button) findViewById(R.id.btn_send);
              btnSend.setOnClickListener(this);
          }
      
          @Override
          public void onClick(View v) {
              if (v == btnSend){
                  String msg = etInput.getText().toString();
                  if (!TextUtils.isEmpty(msg) && mPrintWriter != null){
                      mPrintWriter.println(msg);
                      etInput.setText("");
                      String time = formateDateTime(System.currentTimeMillis());
                      String show = "self "+time+":"+msg+"\n";
                      tvMessage.setText(tvMessage.getText()+show);
                  }
              }
          }
      
          private void connectTCPServer(){
              Socket socket = null;
              while (socket == null){
                  try {
                      socket = new Socket("localhost",8688);
                      mClientSocker = socket;
                      mPrintWriter
                              = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),true);
                      mHandler.sendEmptyMessage(2);
                  } catch (IOException e) {
                      e.printStackTrace();
                  }
              }
      
              try {
                  BufferedReader br
                          = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                  while (!MainActivity.this.isFinishing()){
                      String msg = br.readLine();
                      if (msg != null){
                          Log.d("----",msg);
                          String time = formateDateTime(System.currentTimeMillis());
                          String show = "server "+time+":"+msg+"\n";
                          mHandler.obtainMessage(1,show).sendToTarget();
                      }
                  }
                  mPrintWriter.close();
                  br.close();
              } catch (IOException e) {
                  e.printStackTrace();
              }
          }
      
          private String formateDateTime(long time){
              return new SimpleDateFormat("HH:mm:ss").format(new Date(time));
          }
      }
    
  • Binder连接池
    减少Service的数量。将所有AIDL放在同一个Service中去管理。
    工作机制:每个业务模块创建自己的AIDL接口并实现此接口,这个时候不同业务模块之间是不能有耦合的,所有实现细节我们需要单独开来,然后向服务端提供自己的唯一标识和其对应的Binder对象;对于服务端来说,只需要一个Service就可以了,服务端提供一个queryBinder接口,这个接口能给根据业务模块的特征来返回相应的Binder对象给它们,不同的业务模块拿到所需要的Binder对象后就可以进行远程方法调用了。
    BindPool:

    public class BinderPool {
          private static final String TAG = "BinderPool";
          public static final int BINDER_NONE = -1;
          public static final int BINDER_COMPUTE = 0;
          public static final int BINDER_SECURITY_CENTER = 1;
      
          private Context mContext;
          private IBinderPool mBinderPool;
          private static volatile BinderPool sInstance;
          private CountDownLatch mConnectBinderPoolCountDownLatch;
      
          private BinderPool(Context context) {
              mContext = context.getApplicationContext();
              connectBinderPoolService();
          }
      
          public static BinderPool getInsance(Context context) {
              if (sInstance == null) {
                  synchronized (BinderPool.class) {
                      if (sInstance == null) {
                          sInstance = new BinderPool(context);
                      }
                  }
              }
              return sInstance;
          }
      
          private synchronized void connectBinderPoolService() {
              mConnectBinderPoolCountDownLatch = new CountDownLatch(1);
              Intent service = new Intent(mContext, BinderPoolService.class);
              mContext.bindService(service, mBinderPoolConnection,
                      Context.BIND_AUTO_CREATE);
              try {
                  mConnectBinderPoolCountDownLatch.await();
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
          }
      
          /**
           * query binder by binderCode from binder pool
           * 
           * @param binderCode
           *            the unique token of binder
           * @return binder who's token is binderCode
    * return null when not found or BinderPoolService died. */ public IBinder queryBinder(int binderCode) { IBinder binder = null; try { if (mBinderPool != null) { binder = mBinderPool.queryBinder(binderCode); } } catch (RemoteException e) { e.printStackTrace(); } return binder; } private ServiceConnection mBinderPoolConnection = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { // ignored. } @Override public void onServiceConnected(ComponentName name, IBinder service) { mBinderPool = IBinderPool.Stub.asInterface(service); try { mBinderPool.asBinder().linkToDeath(mBinderPoolDeathRecipient, 0); } catch (RemoteException e) { e.printStackTrace(); } mConnectBinderPoolCountDownLatch.countDown(); } }; private IBinder.DeathRecipient mBinderPoolDeathRecipient = new IBinder.DeathRecipient() { @Override public void binderDied() { Log.w(TAG, "binder died."); mBinderPool.asBinder().unlinkToDeath(mBinderPoolDeathRecipient, 0); mBinderPool = null; connectBinderPoolService(); } }; public static class BinderPoolImpl extends IBinderPool.Stub { public BinderPoolImpl() { super(); } @Override public IBinder queryBinder(int binderCode) throws RemoteException { IBinder binder = null; switch (binderCode) { case BINDER_SECURITY_CENTER: { binder = new SecurityCenterImpl(); break; } case BINDER_COMPUTE: { binder = new ComputeImpl(); break; } default: break; } return binder; } } }

    服务端:

    public class BinderPoolService extends Service {
      
          private static final String TAG = "BinderPoolService";
      
          private Binder mBinderPool = new BinderPool.BinderPoolImpl();
      
          @Override
          public void onCreate() {
              super.onCreate();
          }
      
          @Override
          public IBinder onBind(Intent intent) {
              Log.d(TAG, "onBind");
              return mBinderPool;
          }
      
          @Override
          public void onDestroy() {
              super.onDestroy();
          }
      
      }
    

    客户端:

    public class BinderPoolActivity extends Activity {
          private static final String TAG = "BinderPoolActivity";
      
          private ISecurityCenter mSecurityCenter;
          private ICompute mCompute;
      
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);
              new Thread(new Runnable() {
      
                  @Override
                  public void run() {
                      doWork();
                  }
              }).start();
          }
      
          private void doWork() {
              BinderPool binderPool = BinderPool.getInsance(BinderPoolActivity.this);
              IBinder securityBinder = binderPool
                      .queryBinder(BinderPool.BINDER_SECURITY_CENTER);
              ;
              mSecurityCenter = (ISecurityCenter) SecurityCenterImpl
                      .asInterface(securityBinder);
              Log.d(TAG, "visit ISecurityCenter");
              String msg = "helloworld-安卓";
              System.out.println("content:" + msg);
              try {
                  String password = mSecurityCenter.encrypt(msg);
                  System.out.println("encrypt:" + password);
                  System.out.println("decrypt:" + mSecurityCenter.decrypt(password));
              } catch (RemoteException e) {
                  e.printStackTrace();
              }
      
              Log.d(TAG, "visit ICompute");
              IBinder computeBinder = binderPool
                      .queryBinder(BinderPool.BINDER_COMPUTE);
              ;
              mCompute = ComputeImpl.asInterface(computeBinder);
              try {
                  System.out.println("3+5=" + mCompute.add(3, 5));
              } catch (RemoteException e) {
                  e.printStackTrace();
              }
          }
      
      }
    

2、理解Windowh和WindowManager

1、Window和WondowManager

  • WondowManagers是外界访问Window的入口,Window的具体实现位于WindowManagerService中,WindowManager和WindowManagerService的交互是一个IPC过程。
  • FLAG
    FLAG_NOT_FOCUSABLE:
    表示Window不需要获取焦点,也不需要接收各种输入事件,这个标记会同时启用FLAG_NOT_TOUCH_MODAL,最终事件会直接传递给下层的具有焦点的Window。
    FLAG_NOT_TOUCH_MODAL:
    系统会将当期区域以外的单击事件传递给底层的Window,当前Window区域以内的单击事件则自己处理。一般要开启,否则其他Window将无法收到单击事件。
    FLAG_SHOW_WHEN_LOCKED:
    让Window显示在锁屏界面上。
  • Type参数表示Window类型,有三种,应用Window、子Window、系统Window;应用Window对应着一个Activity,层级是1-99,子Window不能单独存在,比如Dialog,层级是1000-1999,系统Window比如Toast,层级是2000-2999。

你可能感兴趣的:(IPC、Window小结)