1. 程式人生 > >IPC機制1

IPC機制1

ceo bst describe cat lan gin 成員變量 eply right

1、Android IPC簡介

  Inter-Process Communication的縮寫就是IPC,含義是進程間通信或是跨進程間通信,是指兩個進程進行交換數據的過程。

  • 進程是什麽?

  進程在pc上就是一個程序,在Android就是一個應用。線程表示的是cpu調度的最小單元,進程指一個執行單元。一個進程可包含多個線程,也可以只有一個線程。

  所以Android IPC就可以理解為不同應用間的通信,但一個應用也有多進程模式,所以IPC不僅是應用間的通信,不過這個沒必要糾結,反正就是跨進程間通信。

2、Android中的多進程模式

  • 開啟多線程模式

  我們可以在AndroidManifest中修改Activity的屬性,輕易的開啟多線程模式。

<activity
  android:name=".MainActivity">
  <intent-filter>
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.LAUNCHER" />
  </intent-filter>
</activity>
<activity
  android:name=".Main2Activity"
  android:process
="com.xw.test" /> <activity   android:name=".Main3Activity"   android:process=":test" />

  android:process指定這個屬性就可以開啟多進程模式,

  將三個Activity依次啟動,然後使用adb shell可以看到

  這是MainActivity運行在這個應用的默認進程中,進程名就是包名

技術分享圖片

  這是Main2Activity運行在com.xw.test中

技術分享圖片

  這是Main3Activity運行在com.example.administrator.test:test中

技術分享圖片

  Main3Activity使用的“:”的含義是指要在當前的進程名之前附加上當前的包名。以“:”開頭的進程屬於當前應用的私有進程,其他應用的組件不可以和它跑在同一進程中,而不以“:”開頭的進程屬於全局進程,其他應用通過ShareUID方式可以和它跑在同一進程中。

  Android系統會為每一個應用分配一個唯一的UID,具有相同UID的應用才能共享數據,兩個應用通過ShareUID方式可以跑在同一進程中還需要簽名相同,在這種情況下它們可以互相訪問對方的私有數據,比如data目錄、組件信息等。

  • 多線程運行機制

  如果新建一個類,這個類中有一個public的靜態成員變量,

public class Data {
    public static int Id = 1;
}

  然後我們在MainActivity的onCreate中將其賦值為2然後打印出來,然後我們再Main2Activity中直接打印出來。我們會發現原本應該是共享的靜態變量,MainActivity修改為2打印也是2,Main2Activity打印還是1.

  其實,android會為每一個應用(或者說線程)分配一個獨立的虛擬機,不同的虛擬機在內存分配上有不同的地址空間,也就是說其實MainActivity和Main2Activity訪問的但是兩個名字相同的變量而已

  一般來說,多進程會造成如下幾方面的問題:

  (1) 靜態成員和單例模式失效:就上面的這種情況

  (2) 線程同步機制完全失效:已經不是一塊內存了,所以無論是鎖對象還是鎖全局類都無法保證線程同步。

  (3)SharePreferences的可靠性下降:SharePreferences的底層是通過讀/寫XML文件出現的,並發寫顯然是會出問題的,甚至並發讀/寫都有可能出現問題。

  (4)Application會多次創建:當一個組件在跑一個新的進程的時候,分配獨立的虛擬機,其實就是啟動一個應用的過程,相當於系統把這個應用重啟了一遍,就創建了新的Application。

3、Binder

  Binder是Android中的一個類,它實現了IBinder接口,Binder是Android中的一種跨進程通信方式

  Binder是客戶端和服務端進行通信的媒介,當bindService的時候,服務端會返回一個包含服務端業務調用的Binder對象,通過這個Binder對象,客戶端就可以獲取服務端提供的服務和數據。

  這裏使用AIDL來分析Binder的工作機制,

  先新建一個包並定義一個Book類,並實現Parcelable接口

技術分享圖片
public class Book implements Parcelable {

    public int bookId;
    public String bookName;

    public Book(int bookId, String bokName){
        this.bookId = bookId;
        this.bookName = bookName;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel parcel, int i) {
        parcel.writeInt(bookId);
        parcel.writeString(bookName);
    }

    public static final Parcelable.Creator<Book> CREATOR = new Parcelable.Creator<Book>(){

        @Override
        public Book createFromParcel(Parcel parcel) {
            return new Book(parcel);
        }

        @Override
        public Book[] newArray(int i) {
            return new Book[i];
        }
    };

    private Book(Parcel parcel){
        bookId = parcel.readInt();
        bookName = parcel.readString();
    }
}
View Code

  然後再創建Book.aidl和IBookManager.aidl

//Book.aidl
package com.xw.book.aidl;

parcelable Book;

//IBookManager.aidl
package com.xw.book.aidl;

import com.xw.book.aidl.Book;

interface IBookManager{
    List<Book> getBookList();
    void addBook(in Book book);
}

  Book.aidl是Book在AIDL中的聲明,IBookManager.aidl是定義的一個接口。

  再點擊安裝到手機之後,在gen目錄下的com.xw.book.aidl包中有一個IBookManager.java的類,這個是系統自動生成的

技術分享圖片
/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: C:\\Users\\Administrator\\Desktop\\test\\app\\src\\main\\aidl\\com\\xw\\book\\aidl\\IBookManager.aidl
 */
package com.xw.book.aidl;
public interface IBookManager extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.xw.book.aidl.IBookManager
{
private static final java.lang.String DESCRIPTOR = "com.xw.book.aidl.IBookManager";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
 * Cast an IBinder object into an com.xw.book.aidl.IBookManager interface,
 * generating a proxy if needed.
 * 
 */
public static com.xw.book.aidl.IBookManager asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.xw.book.aidl.IBookManager))) {
return ((com.xw.book.aidl.IBookManager)iin);
}
return new com.xw.book.aidl.IBookManager.Stub.Proxy(obj);
}
@Override public android.os.IBinder asBinder()
{
return this;
}

@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<com.xw.book.aidl.Book> _result = this.getBookList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addBook:
{
data.enforceInterface(DESCRIPTOR);
com.xw.book.aidl.Book _arg0;
if ((0!=data.readInt())) {
_arg0 = com.xw.book.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.xw.book.aidl.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;
}
@Override public java.util.List<com.xw.book.aidl.Book> getBookList() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.xw.book.aidl.Book> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.xw.book.aidl.Book.CREATOR);
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override public void addBook(com.xw.book.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();
}
}
}
static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
public java.util.List<com.xw.book.aidl.Book> getBookList() throws android.os.RemoteException;
public void addBook(com.xw.book.aidl.Book book) throws android.os.RemoteException;
}
View Code
  • DESCRIPTOR

    Binder的唯一標識,一般使用當前Binderd的類名表示。

  • asInterface(android.os.IBinder obj)

    用於將服務端的Binder對象轉換成客戶端需要的AIDL接口類型的對象,這種轉換是區分進程的,如果服務端和客戶端位於同一進程,那麽該方法會返回服務端的Stub對象本身,否則返回的是系統封裝後的Stub.proxy對象。

  • onTransact

    這個方法運行在服務端的Binder線程池中,當客戶端發起跨進程請求時,遠程請求會通過系統底層封裝後交由此方法來處理, 服務端通過code可以確定客戶端請求的目標方法是什麽,從data中取出目標方法所需要的參數,然後執行目標方法沒目標方法執行完後,就向reply中寫入結果如果此方法返回false,那麽客戶端的請求就會失敗

  • Proxy

    這個類中有兩個方法分別是getBookList和addBook,兩個方法的執行過程是一樣的,說一個就行,方法將運行在客戶端,先創建該方法所需要的輸入型Parcel對象_data、輸出型Parcel對象_reply,和返回值對象,然後把該方法的參數信息寫入_data,然後調用transact方法來發起RPC(遠程過程調用)請求;然後服務端的onTransact方法會被調用,知道RPC過程返回後,當前線程繼續執行,並從_reply中取出RPC過程的返回結果,最後返回_reply中的結果

  以上就是Binder的工作機制,然後還有兩點需要註意:當客戶端發出請求的時候,由於當前線程會被掛起直至服務端進程返回數據,所以如果一個遠程方法是很耗時的,那麽不能在UI線程中發起此遠程請求,其次,由於服務端的Binder方式運行在Binder的線程池中,所以Binder方法不管是否耗時都應該采用同步的方法去實現,因為它已經運行在一個線程中了。

  技術分享圖片

Binder的工作機制

  圖片來源:http://blog.csdn.net/u012827296/article/details/51259006

IPC機制1