我们都知道android 是通过IBinder来实现IPC(Inter Process Communication)进程间通信的。。。
参考:Android进程间通信(IPC)机制Binder简要介绍和学习计划
借用一下:
5. Service Manager是一个守护进程,用来管理Server,并向Client提供查询Server接口的能力
aidl是 Android Interface definition language的缩写,它是一种android内部进程通信接口的描述语言,通过它我们可以定义进程间的通信接口
ITestService.aidl文件
package test.aidl;
interface ITestService {
void start();
}
注意在client端和server端中的aidl文件的的包名必须是一样的,此处必须是test.aidl
public static test.aidl.ITestService asInterface(android.os.IBinder obj) {
......
}
Stub的asInterface方法返回了ITestService对象
lbb.demo.first进程中的服务,充当Server角色
package lbb.demo.first;
public class RemoteService extends Service {
private TestService mITestService;
public class TestService extends ITestService.Stub {
public void start() {
Log.d("LiaBin", "RemoteService start");
}
}
@Override
public void onCreate() {
super.onCreate();
//实例化Binder
mITestService = new TestService();
}
@Override
public IBinder onBind(Intent intent) {
return mITestService;
}
}
package lbb.demo.two;
public class MainActivity extends AppCompatActivity {
private static final String REMOT_SERVICE_ACTION = "android.intent.action.MyFirstService";
private ITestService testService;
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
testService = ITestService.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
bindService(new Intent(REMOT_SERVICE_ACTION), connection, BIND_AUTO_CREATE);
}
@OnClick(R.id.but)
void onClick() {
try {
testService.start();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(connection);
}
}
此时lbb.demo.two进程点击button最终会执行start方法,activity通过bindService获得了远程服务的IBinder引用。。
private MyBinder myBinder = new MyBinder();
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return myBinder;
}
public class MyBinder extends Binder{
public void start(){
Log.d("LiaBin","MyBinder start");
}
}
MyBinder binder;
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
binder = (MyBinder)service;
}
};
binder.start();
Binder类默认实现了IBinder接口
activity和service通信能不能用handler,当然不能。因为service没法获取activity中的handler引用,msg跟handler是一一对应的。就是说使用service中的handler发送消息,
只能service中的handler接收得到。。handler只是用来线程间的通信,因为其它一个线程时候,可以把main线程中的handler传递过去。所以实现了通信。。但是启动service,是没法把handler传过去的。。
本质上不管是startactivity,startservice,bindservice其实都是通过AMS服务来调度的。。AMS(ActivityManagerService)属于系统进程,
应用进程跟AMS其实是通过IBinder通信的,以后会分析下AMS,这里简单提一下。。
TelephonyManager telManager = (TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);
telManager.dial("110");//实际这是错的,因为dial方法在TelephonyManager类中被隐藏了,你是看不到滴,为了演示,调用dial方法。。
可以看到其实context.getSystemService获取的并不是系统服务。。只是一个简单的对象而已。。
ContextImpl.java
@Override
public Object getSystemService(String name) {
ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
return fetcher == null ? null : fetcher.getService(this);
}
registerService(TELEPHONY_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
return new TelephonyManager(ctx.getOuterContext());
}});
TelephonyManager.java
/** @hide */
@SystemApi
public void dial(String number) {
try {
getITelephony().dial(number);
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelephony#dial", e);
}
}
private ITelephony getITelephony() {
return ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));
}
public static final String TELEPHONY_SERVICE = "phone";
可以看到此时真正执行的是ITelephony的dial方法。。可以看到“phone”类型的服务返回的一个IBinder
ServiceManager.getService获取的才是真正的系统服务
public class PhoneInterfaceManager extends ITelephony.Stub {
private PhoneInterfaceManager(PhoneGlobals app, Phone phone) {
.......
publish();
}
private void publish() {
if (DBG) log("publish: " + this);
ServiceManager.addService("phone", this);
}
public void dial(String number) {
dialForSubscriber(getPreferredVoiceSubscription(), number);
}
public void dialForSubscriber(int subId, String number) {
if (DBG) log("dial: " + number);
String url = createTelUrl(number);
if (url == null) {
return;
}
// PENDING: should we just silently fail if phone is offhook or ringing?
PhoneConstants.State state = mCM.getState(subId);
if (state != PhoneConstants.State.OFFHOOK && state != PhoneConstants.State.RINGING) {
Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse(url));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mApp.startActivity(intent);
}
}
}
可以看到,构造函数调用publish,然后注册了“phone"这个服务。。ServiceManager.addService("phone", this);
然后dial方法,实际上走的是PhoneInterfaceManager类的dial方法 Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse(url)); 此时调用拨号界面进行拨号
PhoneInterfaceManager实现了ITelephony.Stub,所有最后来看看ITelephony.aidl文件
ITelephony.aidl文件
interface ITelephony {
/**
* Dial a number. This doesn't place the call. It displays
* the Dialer screen.
* @param number the number to be dialed. If null, this
* would display the Dialer screen with no number pre-filled.
*/
void dial(String number);
.......
}
最后:此时可以看到PhoneInterfaceManager可以当作是Server角色,TelephonyManager充当是Client角色。。。
TelephonyManager是公开的,我们代码中可以访问得到,其实只是一个门面,系统暴露给我们的接口(TelephonyManager更多的用到使用它来查询当前通话状态啊等功能),真正还是通过IBinder机制去调用系统服务PhoneInterfaceManager去具体的实现。。PhoneInterfaceManager是隐藏的,我们看不到。。。
总结一下:
不管是AIDL还是在framework中通过ServiceManager进行跨进程调用其实,都是先把IBinder拿到,只有拿到这个两个进程才能够通信
ServiceManager.getService(Context.TELEPHONY_SERVICE)得到的是IBinder
bindservice中的ServiceConnection得到的也是IBinder