大多数系统服务在system_server
进程中作为线程运行。在启动时,它们会传递一个呼叫邀请(请参阅 call to addService()
in SystemServer.java
)servicemanager
,然后可以将邀请分发给正在呼叫的应用程序getSystemService
。
一旦事情进展顺利,您可以将整个设置视为一种客户端-服务器架构,其中您的应用程序是客户端(远程或代理端),服务器(本地或存根端)是您正在谈论的系统服务至。客户端和服务器通过称为 binder 的进程间通信 (IPC) 子系统进行通信。绑定器有不同的部分:框架组件执行包的编组和解组,而内核驱动程序执行与 ioctl 调用之间的实际内存复制,并在进程和线程级别跟踪谁被邀请调用。
应用程序通过代理与活页夹交互。例如,当您使用 时LocationManagerService
,您会得到一个android.location.ILocationManager
. Proxy 类中的方法之一是getLastLocation()
:
...
@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
进程代表调用者进行操作。这允许它对硬件或其他系统资源执行通常具有特权的操作。安全性基于 1) 具有调用邀请的应用程序(从service_manager
via获得getSystemService
)和 2) 通过服务本身实施的任何检查,例如检查ACCESS_COARSE_LOCATION
或ACCESS_FINE_LOCATION
在LocationManagerService
(在清单中声明并在安装时由最终用户)。
更新:在定位服务的情况下,这些硬件操作需要从 GPS 硬件获取实际的 NMEA 数据。目前实现这一点的方式是通过GpsLocationProvider
通过 JNI 与本机代码接口的类。本机代码 ( com_android_server_location_GpsLocationProvider.cpp
) 是打开硬件设备的地方(通过hw_module_t
结构中保存的抽象层),进行位置回调(例如,location_callback()
)等。所有这些都在system_server
具有特权 UID 的进程空间内运行system
。您可以通过运行支持定位的应用程序、GpsLocationProvider
在 logcat 中查找标签并确认记录的 PID 是system_server
. 例如:
$ adb logcat | grep -i gps
...
D/GpsLocationProvider( 731): Reset GPS properties, previous size = 8
...
和
$ adb shell ps | grep system_server
system 731 441 1094884 89232 ffffffff b74d1d05 S system_server
$
最后,我强烈推荐视频教程Deep Dive Into Android IPC/Binder Framework来了解更多相关信息。演讲的幻灯片可以在这里找到。