1. 程式人生 > >Android-Binder之一:簡單IPC

Android-Binder之一:簡單IPC

引文

Binder 是android中一個很基礎的概念,設計上很簡潔。因為是基礎 IPC 模組,所以基本上 Android 的核心內容都對它有依賴。所以掌握了 Binder ,算是掌握了 Android 系統的一把鑰匙。 網路上有不少文章對 Binder 做了剖析,假設你已經看完了所有資料,也過了一邊原始碼。

這個系列是使用 Binder 的筆記,包括 簡單IPC 、建立&使用系統級服務。這是第一篇 :)

簡單IPC

AndroidManifest

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

aidl

org.yeshen.ipc.ipctest.IRemoteService.aidl

package org.yeshen.ipc.ipctest;

import org.yeshen.ipc.ipctest.EchoData;

interface IRemoteService {
    EchoData echo(String msg);
}

org.yeshen.ipc.ipctest.EchoData.aidl

package org.yeshen.ipc.ipctest;

parcelable EchoData;

impl

org.yeshen.ipc.ipctest.MainActivity.java

package org.yeshen.ipc.ipctest;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.view.View; import android.widget.TextView; import android.widget.Toast; public class MainActivity extends AppCompatActivity { private IRemoteService mRemoteService; private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { mRemoteService = IRemoteService.Stub.asInterface(service); } @Override public void onServiceDisconnected(ComponentName name) { mRemoteService = null; } }; private TextView mPrintView; private boolean mIsBound = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mPrintView = findViewById(R.id.print_view); } public void performEcho(View v) { if (!mIsBound || mRemoteService == null) { Toast.makeText(this, "not bind yet", Toast.LENGTH_SHORT).show(); return; } try { String now = "utc[" + System.currentTimeMillis() + "]"; mPrintView.setText(mRemoteService.echo(now).toString()); } catch (RemoteException e) { e.printStackTrace(); } } public void performBind(View v) { Intent intent = new Intent(MainActivity.this, RemoteService.class); intent.setAction(IRemoteService.class.getName()); bindService(intent, mConnection, Context.BIND_AUTO_CREATE); mIsBound = true; } public void performUnBind(View v) { if (!mIsBound) return; unbindService(mConnection); mIsBound = false; } public void performKill(View v) { if (mRemoteService == null) return; try { android.os.Process.killProcess(mRemoteService.echo("").getPid()); mIsBound = false; } catch (RemoteException e) { e.printStackTrace(); } } }

org.yeshen.ipc.ipctest.RemoteService.java

package org.yeshen.ipc.ipctest;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;

public class RemoteService extends Service {

    EchoData mData;

    @Override
    public void onCreate() {
        super.onCreate();
        mData = new EchoData();
        mData.setPid(android.os.Process.myPid());
    }

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

    @Override
    public boolean onUnbind(Intent intent) {
        return super.onUnbind(intent);
    }

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

    private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {

        @Override
        public EchoData echo(String msg) throws RemoteException {
            mData.setMsg(msg);
            mData.increaseEcho();
            return mData;
        }

        @Override
        public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
            return super.onTransact(code, data, reply, flags);
        }
    };
}

org.yeshen.ipc.ipctest.EchoData.java

package org.yeshen.ipc.ipctest;

import android.os.Parcel;
import android.os.Parcelable;

public class EchoData implements Parcelable {
    public static final Creator<EchoData> CREATOR = new Creator<EchoData>() {
        @Override
        public EchoData createFromParcel(Parcel in) {
            return new EchoData(in);
        }

        @Override
        public EchoData[] newArray(int size) {
            return new EchoData[size];
        }
    };

    private String msg;
    private int pid;
    private int echo;

    public EchoData() {
    }

    protected EchoData(Parcel in) {
        readFromParcel(in);
    }

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

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(msg);
        dest.writeInt(pid);
        dest.writeInt(echo);
    }

    private void readFromParcel(Parcel in) {
        msg = in.readString();
        pid = in.readInt();
        echo = in.readInt();
    }

    public int getPid() {
        return pid;
    }

    public void setPid(int pid) {
        this.pid = pid;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public void increaseEcho() {
        this.echo++;
    }

    @Override
    public String toString() {
        return "msg = " + msg + ",\n pid=" + pid + ",\n times=" + this.echo;
    }
}

小結:

這樣就實現了一個最簡單的自定義資料讀寫和跨程序通訊。

建立&使用系統級服務

做一個系統級別的服務。考慮在Android系統中寫一個 EchoServer 服務,功能如下:

在context中可以獲得這個服務; 訊息傳到 EchoServer; EchoServer 再原樣返回給呼叫者。

// TODO