android IPC通讯(上)-sharedUserId&&Messenger
android IPC通讯(中)-ContentProvider&&Socket
这篇咱们将会着重介绍AIDL的使用方式和原理,要介绍AIDL先要简单介绍一下Binder,并且Messenger,ContentProvider和AIDL的最底层都是使用的Binder。javascript
直观来讲,Binder是Android中的一个类,它实现了IBinder接口。从IPC角度来讲,Binder是Android中的一种跨进程通讯方式,Binder还能够理解为一种虚拟的物理设备,它的设备驱动是 /dev/binder,该通讯方式在Linux中没有;从Android Framework 角度来讲,Binder 是 ServiceManager 链接各类Manager (ActivityManager,WindowManager,等等)和相应 ManagerService 的桥梁;从Android 应用层来讲,Binder 是客户端和服务端进行通讯的媒介,当 bindService 的时候,服务端会返回一个包含了服务端业务调用的 Binder 对象,经过这个Binder对象,客户端就能够获取服务端提供的服务或者数据,这里的服务包括普通服务和基于AIDL的服务。
还有两点须要提到,第一点就是当客户端发起远程请求时,因为当前线程会被挂起直至服务端进程返回数据,因此若是一个远程方法是耗时的,那么不能在UI线程中发起此远程请求;其次,因为服务端的Binder方法运行在Binder的线程池中,因此Binder方法无论是否耗时都应该采用同步的方法去实现,由于他已经运行在一个线程中了。下图为Binder的工做机制图:
能够看到Client客户端会block直到方法返回,从图中咱们能够看到 Binder 的调用中有四个角色:Client, Proxy, Binder Driver 和 Server ,他们的关系以下图所示:
这四者的关系相似于网络访问,html
IBinder b = ServiceManager.getService("activity");复制代码
经过 ServiceManager 去获取 AMS 的 Binder 对象,ServiceManager 类的代码很简单:
public final class ServiceManager {
private static final String TAG = "ServiceManager";
private static IServiceManager sServiceManager;
private static HashMap<String, IBinder> sCache = new HashMap<String, IBinder>();
private static IServiceManager getIServiceManager() {
if (sServiceManager != null) {
return sServiceManager;
}
// Find the service manager
sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
return sServiceManager;
}
/
Returns a reference to a service with the given name.
@param name the name of the service to get @return a reference to the service, or <code>null</code> if the service doesn't exist
*/
public static IBinder getService(String name) {
try {
IBinder service = sCache.get(name);
if (service != null) {
return service;
} else {
return getIServiceManager().getService(name);
}
} catch (RemoteException e) {
Log.e(TAG, "error in getService", e);
}
return null;
}
public static void addService(String name, IBinder service) {
...
}
....
}复制代码
public interface IServiceManager extends IInterface
{
/
Retrieve an existing service called @a name from the service manager. Blocks for a few seconds waiting for it to be
published if it does not already exist. /
public IBinder getService(String name) throws RemoteException;
/
Retrieve an existing service called @a name from the service manager. Non-blocking.
*/
public IBinder checkService(String name) throws RemoteException;
/
Place a new @a service called @a name into the service manager.
/
public void addService(String name, IBinder service, boolean allowIsolated)
throws RemoteException;
/** Return a list of all currently running services.
/
public String[] listServices() throws RemoteException;
/** Assign a permission controller to the service manager. After set, this
interface is checked before any services are added. /
public void setPermissionController(IPermissionController controller)
throws RemoteException;
static final String descriptor = "android.os.IServiceManager";
int GET_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION;
int CHECK_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+1;
int ADD_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+2;
int LIST_SERVICES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+3;
int CHECK_SERVICES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+4;
int SET_PERMISSION_CONTROLLER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+5;
}复制代码
// IWeatherManager.aidl
package com.android.aidl;
import com.android.aidl.Weather;
import com.android.aidl.listener.IWeatherChangeListener;
interface IWeatherManager {
List<Weather> getWeather();
void addWeather(in Weather weather);
void addListener(in IWeatherChangeListener listener);
void removeListener(in IWeatherChangeListener listener);
}复制代码
//Weather.aidl
package com.android.aidl;
parcelable Weather;复制代码
// IWeatherChangeListener.aidl
package com.android.aidl.listener;
import com.android.aidl.Weather;
interface IWeatherChangeListener {
void onWeatherChange(in Weather newWeather);
}复制代码
public class Weather implements Parcelable{
public String cityName;
public double temperature;
public double humidity;
public AllWeather weather;
protected Weather(Parcel in) {
temperature = in.readDouble();
humidity = in.readDouble();
//使用该方式来写入枚举
weather = AllWeather.values()[in.readInt()];
cityName = in.readString();
}
public Weather() {
}
public static final Creator<Weather> CREATOR = new Creator<Weather>() {
@Override
public Weather createFromParcel(Parcel in) {
return new Weather(in);
}
@Override
public Weather[] newArray(int size) {
return new Weather[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeDouble(temperature);
dest.writeDouble(humidity);
dest.writeInt(weather.ordinal());
dest.writeString(cityName);
}
public enum AllWeather{
sunny,cloudy,rain,snowy
}
}复制代码
public class WeatherManagerService extends Service{
//支持并发读写的list
public CopyOnWriteArrayList<Weather> weathers = new CopyOnWriteArrayList<>();
public RemoteCallbackList<IWeatherChangeListener> listeners = new RemoteCallbackList<>();
@Override
public void onCreate() {
super.onCreate();
Weather nanshan = new Weather();
nanshan.cityName = "南山";
nanshan.temperature = 20.5;
nanshan.humidity = 45;
nanshan.weather = Weather.AllWeather.cloudy;
Weather futian = new Weather();
futian.cityName = "福田";
futian.temperature = 21.5;
futian.humidity = 48;
futian.weather = Weather.AllWeather.rain;
weathers.add(nanshan);
weathers.add(futian);
}
private Binder mBinder = new IWeatherManager.Stub() {
@Override
public List<Weather> getWeather() throws RemoteException {
L.i("server returns all of the weathers");
return weathers;
}
@Override
public void addWeather(Weather weather) throws RemoteException {
weathers.add(weather);
L.i("server add new Weather:" + weather.cityName);
int N = listeners.beginBroadcast();
for (int i=0; i<N; i++){
IWeatherChangeListener listener = listeners.getBroadcastItem(i);
listener.onWeatherChange(weather);
}
L.i("server notify the listener that weathers have been changed");
listeners.finishBroadcast();
}
@Override
public void addListener(IWeatherChangeListener listener) throws RemoteException {
L.i("server adding listener");
listeners.register(listener);
}
@Override
public void removeListener(IWeatherChangeListener listener) throws RemoteException {
L.i("server removing listener");
listeners.unregister(listener);
}
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
int permission = checkCallingPermission("com.android.permission.WRITEWEATHERPERMISSION");
//检测客户端是否声明权限
if (permission == PackageManager.PERMISSION_DENIED){
L.e("permission denied");
return false;
}
L.i("permission granted");
String[] packages = getPackageManager().getPackagesForUid(getCallingUid());
if (packages != null && packages.length > 0){
String packageName = packages[0];
if (!packageName.startsWith("com.android")){
L.e("package name not accept");
return false;
}
L.i("package name accept");
}
return super.onTransact(code, data, reply, flags);
}
};
@Override
public IBinder onBind(Intent intent) {
// int permission = checkCallingPermission("com.android.permission.WRITEWEATHERPERMISSION");
// //检测客户端是否声明权限
// if (permission == PackageManager.PERMISSION_DENIED){
// L.e("permission denied");
// return null;
// }
return mBinder;
}
}复制代码
ArrayMap<IBinder, Callback> mCallbacks = new ArrayMap<IBinder, Callback>()
IBinder binder = callback.asBinder();
Callback cb = new Callback(callback, cookie);
public class ClientActivity extends BaseActivity implements View.OnClickListener{
private ServiceConnection serviceConnection = null;
private IBinder.DeathRecipient deathRecipient = null;
private IWeatherChangeListener listener = null;
private IWeatherManager weatherManager;
private TextView tv_content;
private TextView tv_add;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_client);
findViewById(R.id.btn_add).setOnClickListener(this);
findViewById(R.id.btn_query).setOnClickListener(this);
findViewById(R.id.btn_remove_listener).setOnClickListener(this);
tv_content = (TextView) findViewById(R.id.tv_content);
tv_add = (TextView) findViewById(R.id.tv_add);
listener = new IWeatherChangeListener.Stub(){
@Override
public void onWeatherChange(Weather newWeather) throws RemoteException {
L.i("client has been notified that "+newWeather.cityName+" has been added");
tv_add.setText(newWeather.cityName + "has been added");
}
};
serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
weatherManager = IWeatherManager.Stub.asInterface(service);
try {
weatherManager.asBinder().linkToDeath(deathRecipient, 0);
weatherManager.addListener(listener);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
weatherManager = null;
}
};
deathRecipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
//移出以前的死亡容器
weatherManager.asBinder().unlinkToDeath(deathRecipient, 0);
weatherManager = null;
//从新链接
bindServer();
}
};
bindServer();
}
private void bindServer(){
Intent intent = new Intent(this, WeatherManagerService.class);
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.btn_query){
try {
//调用远程服务端接口时,客户端进程会挂起,勿在主线程中调用耗时远程操做
L.i("client is getting weather");
List<Weather> weathers = weatherManager.getWeather();
L.i("client has gotten weather");
StringBuilder sb = new StringBuilder();
for (Weather weather : weathers){
sb.append(weather.cityName).append("\n");
sb.append("humidity:").append(weather.humidity)
.append("temperature").append(weather.temperature)
.append("weather").append(weather.weather).append("\n");
}
tv_content.setText(sb);
} catch (RemoteException e) {
e.printStackTrace();
}
}else if (v.getId() == R.id.btn_add){
Weather weather = new Weather();
weather.weather = Weather.AllWeather.cloudy;
weather.humidity = 25.5;
weather.temperature = 19.5;
weather.cityName = "罗湖";
try {
//调用远程服务端接口时,客户端进程会挂起,勿在主线程中调用耗时远程操做
L.i("client is adding weather " + weather.cityName);
weatherManager.addWeather(weather);
L.i("client has added weather " + weather.cityName);
} catch (RemoteException e) {
e.printStackTrace();
}
}else if (v.getId() == R.id.btn_remove_listener){
try {
weatherManager.removeListener(listener);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(serviceConnection);
try {
weatherManager.asBinder().linkToDeath(deathRecipient, 0);
} catch (RemoteException e) {
e.printStackTrace();
}
}复制代码
I/PID:28533: [TID:7035] 1.onTransact(line:90): permission granted
I/PID:28533: [TID:7035] 1.onTransact(line:99): package name accept
I/PID:28533: [TID:7035] 1.addListener(line:72): server adding listener
//client add click
I/PID:28502: [TID:1] ClientActivity.onClick(line:115): client is adding weather 罗湖
I/PID:28533: [TID:7036] 1.onTransact(line:90): permission granted
I/PID:28533: [TID:7036] 1.onTransact(line:99): package name accept
I/PID:28533: [TID:7036] 1.addWeather(line:59): server add new Weather:罗湖
I/PID:28502: [TID:1] 1.onWeatherChange(line:47): client has been notified that 罗湖 has been added
I/PID:28533: [TID:7036] 1.addWeather(line:66): server has notified the listener that weathers have been changed
I/PID:28502: [TID:1] ClientActivity.onClick(line:117): client has added weather 罗湖
//client remove listener click
I/PID:28533: [TID:7035] 1.onTransact(line:90): permission granted
I/PID:28533: [TID:7035] 1.onTransact(line:99): package name accept
I/PID:28533: [TID:7035] 1.removeListener(line:78): server removing listener
//*client get click
I/PID:28502: [TID:1] ClientActivity.onClick(line:93): client is getting weather
I/PID:28533: [TID:7036] 1.onTransact(line:90): permission granted
I/PID:28533: [TID:7036] 1.onTransact(line:99): package name accept
I/PID:28533: [TID:7036] 1.getWeather(line:52): server returns all of the weathers
I/PID:28502: [TID:1] ClientActivity.onClick(line:95): client has gotten weather复制代码
上面差很少就把AIDL的用法详细介绍完了,可是有的时候咱们可能须要不止一个业务模块,也就是不仅仅须要一个天气模块,咱们还须要一个计算温度平均值的模块(虽然能够写在一个模块中,可是咱们仍是假设要用两个模块吧~),是否是须要为每一个模块都单独创建一个Service呢?固然不是,会很耗资源的好吗,解决方法就是先为每个模块创建一个单独的aidl文件,最后再创建一个总体的aidl文件用来管理这些单独的aidl。
看看这三个文件,IWeatherManager.aidl,IComputerManager.aidl和IBinderPoolManager.aidl:java
// IWeatherManager.aidl
package com.android.binderpool;
import com.android.binderpool.Weather;
interface IWeatherManager {
List<Weather> getWeather();
void addWeather(in Weather weather);
}复制代码
// IComputerManager.aidl
package com.android.binderpool;
import com.android.binderpool.Weather;
interface IComputerManager {
double computeAverageTemperature(in List<Weather> weathers);
}复制代码
// IBinderPoolManager.aidl
package com.android.binderpool;复制代码
interface IBinderPoolManager {
IBinder queryCode(int code);
}IBinderPoolManager.aidl文件用来统一管理全部的AIDL接口,queryCode函数经过code值来肯定须要返回给客户端的IBinder对象。
来看看服务端的代码的变更:node
public class BinderPoolService extends Service{
public static final int CODE_WEATHER = 1;
public static final int CODE_COMPUTER = 2;复制代码
<span class="hljs-keyword">private</span> IBinderPoolManager iBinderPoolManager;
<span class="hljs-comment">//支持并发读写的list</span>
<span class="hljs-keyword">public</span> CopyOnWriteArrayList<Weather> weathers = <span class="hljs-keyword">new</span> CopyOnWriteArrayList<>();
<span class="hljs-annotation">@Override</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onCreate</span>() {
<span class="hljs-keyword">super</span>.onCreate();
Weather nanshan = <span class="hljs-keyword">new</span> Weather();
nanshan.cityName = <span class="hljs-string">"南山"</span>;
nanshan.temperature = <span class="hljs-number">20.5</span>;
nanshan.humidity = <span class="hljs-number">45</span>;
nanshan.weather = Weather.AllWeather.cloudy;
Weather futian = <span class="hljs-keyword">new</span> Weather();
futian.cityName = <span class="hljs-string">"福田"</span>;
futian.temperature = <span class="hljs-number">21.5</span>;
futian.humidity = <span class="hljs-number">48</span>;
futian.weather = Weather.AllWeather.rain;
weathers.add(nanshan);
weathers.add(futian);
iBinderPoolManager = <span class="hljs-keyword">new</span> IBinderPoolManager.Stub(){
<span class="hljs-annotation">@Override</span>
<span class="hljs-keyword">public</span> IBinder <span class="hljs-title">queryCode</span>(<span class="hljs-keyword">int</span> code) <span class="hljs-keyword">throws</span> RemoteException {
<span class="hljs-keyword">switch</span> (code){
<span class="hljs-keyword">case</span> CODE_WEATHER:
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> IWeatherManager.Stub(){
<span class="hljs-annotation">@Override</span>
<span class="hljs-keyword">public</span> List<Weather> <span class="hljs-title">getWeather</span>() <span class="hljs-keyword">throws</span> RemoteException {
<span class="hljs-keyword">return</span> weathers;
}
<span class="hljs-annotation">@Override</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">addWeather</span>(Weather weather) <span class="hljs-keyword">throws</span> RemoteException {
weathers.add(weather);
}
};
<span class="hljs-keyword">case</span> CODE_COMPUTER:
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> IComputerManager.Stub() {
<span class="hljs-annotation">@Override</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> <span class="hljs-title">computeAverageTemperature</span>(List<Weather> weathers) <span class="hljs-keyword">throws</span> RemoteException {
<span class="hljs-keyword">double</span> sum = <span class="hljs-number">0</span>;
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i=<span class="hljs-number">0</span>; i<weathers.size(); i++){
sum += weathers.get(i).temperature;
}
<span class="hljs-keyword">return</span> sum/weathers.size();
}
};
<span class="hljs-keyword">default</span>:
<span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;
}
}
};
}
<span class="hljs-annotation">@Override</span>
<span class="hljs-keyword">public</span> IBinder <span class="hljs-title">onBind</span>(Intent intent) {
<span class="hljs-keyword">return</span> iBinderPoolManager.asBinder();
}复制代码
} 根据code的不一样返回不一样的IBinder对象,这样在客户端中就可以获取对应AIDL接口的IBinder对象,最终就能在客户端调用不一样AIDL模块中的方法。客户端代码很简单,在这里就不介绍了,感兴趣的能够去看看源码:
github.com/zhaozepeng/…
关于IPC相关知识的介绍就到这了,若是有什么疑问,你们能够多多交流啊,谢谢~android