Android-Binder之一:簡單IPC
阿新 • • 發佈:2018-12-14
引文
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