引文
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