我一直在阅读所有我能找到的东西,试图弄清楚Android的BINDER IPC机制背后的软件架构。据我所知,BINDER位于内核空间,暂时为用户空间应用程序提供共享内存分配,通过它可以在进程之间中继消息。
我开始失去控制力的是实际实施的工作方式 - 特别是与 parcels 有关。
我正在网上查找并发现了Android提供的任意服务的实现,例如Network / Wifi / Notificaiton / Battery,ect(Docs)。从我的阅读中我了解到,用户空间程序本身不应该实例化服务类,而是通过Context.getSystemService(Context.X)
获取对它的引用。因此,我认为这是间接说明Android 已经运行的服务,或者至少有资源在需要时启动它。实施基本上是这样的:
Battery.class
BatteryManager.setBatteryState(){
Parcel parcelLocal = Parcel.obtain();
parcelLocal.writeInterfaceToken("android.power.BatteryManager");
parcelLocal.writeInt(1/0); //Depending on requested state
BinderObject.transact //Send the data using BINDER
CheckForExceptions(); //Upon return, check for exceptions
ReadResponse(); //If none, read the response from the target
DoAppropriateAction(); //Whatever we need to do after setting the state
parcelLocal.recycle(); //Return the parcel resource
}
起初看起来很简单:当用户执行以下操作时:
BatteryMonitor bMonitor = Context.getSystemService(Context.POWER_SERVICE);
bMonitor.setBatteryStatus(1);
然后user's
实例将使用BINDER机制与system's
实际服务控制器(哪个是同一个类的实例?)进行通信。但是,上面显示的代码 IS 是系统电池监控服务的实现,那么谁实际上正在接收BINDER数据呢?
TL; DR :如果这一切都非常令人困惑,这很可能就像我试图将一千行代码压缩成10行一样,摘要是:当用户打算控制时硬件的状态 - 例如网络/ Wifi /位置/通知(触摸屏) - 在Android中实际是什么 >控制与这些抽象服务相关的硬件?
注意:上述代码完全是伪造的,仅用于显示一般结构。
答案 0 :(得分:1)
大多数系统服务在system_server
进程中作为线程运行。在启动时,他们会将来电邀请(请参阅addService()
中SystemServer.java
的来电)传递给servicemanager
,然后getSystemService
可以将邀请分发给正在呼叫LocationManagerService
的应用。
一旦滚动,您可以将整个设置视为一种客户端 - 服务器架构,其中您的应用程序是客户端(远程或代理端),服务器(本地或存根端)是您的系统服务在说话。客户端和服务器通过称为binder的进程间通信(IPC)子系统进行通信。绑定器有不同的部分:框架组件执行包裹的编组和解组,而内核驱动程序向/从ioctl调用执行实际的内存复制,并跟踪谁被邀请在进程和线程级别调用。
通过代理与活页夹的应用程序界面。例如,当您使用android.location.ILocationManager
时,您会获得getLastLocation()
的实例。 Proxy类中的一个方法是...
@Override public android.location.Location getLastLocation(android.location.LocationRequest request, java.lang.String packageName) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
android.location.Location _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((request!=null)) {
_data.writeInt(1);
request.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}
_data.writeString(packageName);
mRemote.transact(Stub.TRANSACTION_getLastLocation, _data, _reply, 0);
_reply.readException();
if ((0!=_reply.readInt())) {
_result = android.location.Location.CREATOR.createFromParcel(_reply);
}
else {
_result = null;
}
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
...
:
TRANSACTION_getLastLocation
在这里,您可以看到事务代码onTransact()
与任何必要的数据一起写入接口,并读取结果。在存根端,有一个...
case TRANSACTION_getLastLocation:
{
data.enforceInterface(DESCRIPTOR);
android.location.LocationRequest _arg0;
if ((0!=data.readInt())) {
_arg0 = android.location.LocationRequest.CREATOR.createFromParcel(data);
}
else {
_arg0 = null;
}
java.lang.String _arg1;
_arg1 = data.readString();
android.location.Location _result = this.getLastLocation(_arg0, _arg1);
reply.writeNoException();
if ((_result!=null)) {
reply.writeInt(1);
_result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
}
else {
reply.writeInt(0);
}
return true;
}
...
方法在服务的进程空间中运行,它根据事务代码处理所有传入的事务:
system_service
简而言之,service_manager
进程代表调用者行事。这允许它在硬件或其他系统资源上执行通常特权操作。安全性基于1)应用程序具有调用邀请(通过getSystemService
从ACCESS_COARSE_LOCATION
获得)和2)传递服务本身实现的任何检查,例如检查ACCESS_FINE_LOCATION
或{ {1}} LocationManagerService
(在清单中声明并在最终用户安装时批准)。
更新:在位置服务的情况下,这些硬件操作需要从GPS硬件获取实际的NMEA数据。目前这种方式是通过GpsLocationProvider
类实现的,该类通过JNI与本机代码连接。此本机代码(com_android_server_location_GpsLocationProvider.cpp
)是打开硬件设备的位置(通过hw_module_t
结构中保存的抽象层),进行位置回调(例如,location_callback()
)等。所有这在具有特权UID system_server
的{{1}}进程空间内运行。您可以通过运行启用位置的应用程序来验证这一点,在logcat中查找system
标记并确认记录的PID是GpsLocationProvider
的PID。例如:
system_server
和
$ adb logcat | grep -i gps
...
D/GpsLocationProvider( 731): Reset GPS properties, previous size = 8
...
最后,我强烈推荐视频教程Deep Dive Into Android IPC/Binder Framework以了解有关此内容的更多信息。可以找到谈话的幻灯片here。