文章目录
- 前言
- 一、 源码解析
- ServerManager
- getIServiceManager 的实现
- ()
- javaObjectForIBinder
- 二、 ServiceManager的总结与完整流程
- 流程
- 1. 发布服务
- 2.
- 3. 与 Native 层交互
- 4. IBinder 转换为代理对象
- 5. 服务代理与管理
- 服务管理的应用场景
- 系统服务启动与管理
- 进程间通信(IPC)
- 隔离进程与权限管理
- 动态服务管理
- 三、新增系统服务
- 1. 定义你的服务
- 1.1 创建自定义服务类
- 2. 修改 SystemServer 启动自定义服务
- 2.1 修改 注册自定义服务
- 3. 编写 AIDL 接口(如果需要跨进程调用)
- 3.1 定义 AIDL 接口
- 3.2 服务端实现 AIDL 接口
- 3.3 客户端调用服务
- 4. 修改 或
- 5. 注册服务到 ServiceManager
- 6. 重启系统或服务
- 总结
前言
在上次的讨论中,我们介绍了 Wifi服务启动流程,点击查看 本文将继续深入探讨服务管理器的工作机制。
特别是 中的 publishBinderService 方法及其背后的 流程。
Wifi服务启动流程(1)
一、 源码解析
ServerManager
的 publishBinderService 方法将service添加到ServiceManager
(frameworks\base\services\core\java\com\android\server\)
protected final void publishBinderService(String name, IBinder service,boolean allowIsolated, int dumpPriority) {
//将service添加到ServiceManager
ServiceManager.addService(name, service, allowIsolated, dumpPriority);
}
在这里,publishBinderService 方法接受四个参数:
- name:服务的名称;
- service:实现了 IBinder 接口的服务对象;
- allowIsolated:一个布尔值,表示是否允许服务在隔离沙盒中运行;
-
dumpPriority:转储服务时的优先级,值为位掩码。
该方法的作用是通过 将服务添加到系统的服务管理器中。
(路径:frameworks\base\core\java\android\os\)
/**
* 将一个名为@a 名称的新@a 服务放入服务管理器中。
*
* @param name 新服务的名称
* @param service 服务对象
* @param allowIsolated 设置为 true 以允许隔离沙盒进程
* @param dumpPriority 支持转储优先级作为访问此服务的位掩码
*/
public static void addService(String name, IBinder service, boolean allowIsolated,
int dumpPriority) {
try {
getIServiceManager().addService(name, service, allowIsolated, dumpPriority);
} catch (RemoteException e) {
Log.e(TAG, "error in addService", e);
}
}
在此方法中,getIServiceManager() 获取到一个接口 IServiceManager,该接口是系统与 native 层交互的桥梁。
getIServiceManager 的实现
private static IServiceManager getIServiceManager() {
//单例模式
if (sServiceManager != null) {
return sServiceManager;
}
// Find the service manager
//获得与native层交互的媒介
sServiceManager = ServiceManagerNative
.asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
return sServiceManager;
}
该方法通过调用 获取 IServiceManager 的实例,并使用 确保接口可以进行阻塞调用。() 获取系统全局的上下文对象。
(路径:frameworks\base\core\java\android\os\)
/**
* 允许在给定接口上阻塞调用,覆盖请求
* {@link #setWarnOnBlocking(boolean)} 的值。
* <p>
* 只有当你绝对是很少调用确保远程接口是内置系统组件永远无法升级。 特别是,这必须
永远不会调用由包托管的接口,这些接口可以升级或更换,否则您将面临系统不稳定的风险
那个远程接口楔入。
*
* @隐藏
*/
public static IBinder allowBlocking(IBinder binder) {
try {
if (binder instanceof BinderProxy) {
((BinderProxy) binder).mWarnOnBlocking = false;
} else if (binder != null && binder.getInterfaceDescriptor() != null
&& binder.queryLocalInterface(binder.getInterfaceDescriptor()) == null) {
Log.w(TAG, "Unable to allow blocking on interface " + binder);
}
} catch (RemoteException ignored) {
}
return binder;
}
该方法的作用是让某些接口调用支持阻塞操作,这对于访问系统级服务非常重要。注意, 需要确保调用的接口是由系统内建的,而不是由外部包管理的接口。
()
是一个本地方法,用于返回系统的全局上下文对象。其实现如下:
/**
* 返回系统的全局“上下文对象”。 这通常是IServiceManager 的实现,您可以使用它来查找其他服务。
*/
public static final native IBinder getContextObject();
对应的Native层方法
路径:frameworks\base\core\jni\android_util_Binder.cpp
static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)
{
sp<IBinder> b = ProcessState::self()->getContextObject(NULL);
return javaObjectForIBinder(env, b);
}
javaObjectForIBinder
javaObjectForIBinder 是一个将本地 IBinder 对象转化为 Java 对象的函数。其实现如下:
jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
{
if (val == NULL) return NULL;
if (val->checkSubclass(&gBinderOffsets)) {
// // 这是一个由 ibinderForJavaObject 创建的 JavaBBinder。已经有的 Java 对象。
jobject object = static_cast<JavaBBinder*>(val.get())->object();
LOGDEATH("objectForBinder %p: it's our own %p!\n", val.get(), object);
return object;
}
// 对于函数的其余部分,我们将持有这个锁,以进行序列化
// 查找/创建/销毁本机 Binder 代理的 Java 代理。
AutoMutex _l(gProxyLock);
BinderProxyNativeData* nativeData = gNativeDataCache;
if (nativeData == nullptr) {
nativeData = new BinderProxyNativeData();
}
// gNativeDataCache 现在逻辑上是空的。
jobject object = env->CallStaticObjectMethod(gBinderProxyOffsets.mClass,
gBinderProxyOffsets.mGetInstance, (jlong) nativeData, (jlong) val.get());
if (env->ExceptionCheck()) {
// 在异常情况下,getInstance 仍然拥有 nativeData 的所有权。
gNativeDataCache = nullptr;
return NULL;
}
BinderProxyNativeData* actualNativeData = getBPNativeData(env, object);
if (actualNativeData == nativeData) {
// 新的 BinderProxy; 我们仍然拥有独家访问权。
nativeData->mOrgue = new DeathRecipientList;
nativeData->mObject = val;
gNativeDataCache = nullptr;
++gNumProxies;
if (gNumProxies >= gProxiesWarned + PROXY_WARN_INTERVAL) {
ALOGW("Unexpectedly many live BinderProxies: %d\n", gNumProxies);
gProxiesWarned = gNumProxies;
}
} else {
// 未使用 nativeData。 下次再用。
gNativeDataCache = nativeData;
}
return object;
}
该方法会根据本地 IBinder 对象创建一个 Java 代理对象,并返回该对象给框架层使用。
方法用于将一个 IBinder 对象转换为 IServiceManager 接口的代理对象:
static public IServiceManager asInterface(IBinder obj)
{
if (obj == null) {
return null;
}
IServiceManager in = (IServiceManager)obj.queryLocalInterface(descriptor);
if (in != null) {
return in;
}
return new ServiceManagerProxy(obj);
}
如果该 IBinder 对象已经实现了 IServiceManager 接口,直接返回;否则,创建一个新的 ServiceManagerProxy 代理对象。
二、 ServiceManager的总结与完整流程
从 SystemService 的 publishBinderService 方法到 ServiceManager 和底层的 IServiceManager 交互,我们可以总结出整个服务发布的流程:
流程
1. 发布服务
当一个系统服务需要被启动时,它会调用 publishBinderService 方法,将服务通过 注册到服务管理器中。这样,系统的其他组件就能够通过该服务名访问到这个服务。
2.
在 ServiceManager 中,addService 方法最终会调用 getIServiceManager().addService,此方法将服务的注册请求转发到 native 层。
3. 与 Native 层交互
getIServiceManager() 获取到的 IServiceManager 接口,实际上是一个连接到本地服务的桥梁。通过 和 等方法,我们确保了服务可以正确地与底层系统进行交互。这一部分在 ServiceManagerNative 中以 JNI 的形式完成。
4. IBinder 转换为代理对象
当 IServiceManager 的接口方法被调用时,IBinder 可能需要被转换成相应的 Java 对象,这个过程是通过 javaObjectForIBinder 来实现的。它通过本地方法与 IBinder 进行绑定,并为其创建一个代理对象(BinderProxy),以便于 Java 层的操作。
5. 服务代理与管理
通过 ,我们可以将一个普通的 IBinder 对象转换为 IServiceManager 代理对象。这使得 Framework 层能够通过标准接口访问底层的服务管理功能。这样,整个系统中的服务就形成了一个清晰的层次结构,便于管理与调用。
服务管理的应用场景
通过上述流程,Android 的 ServiceManager 提供了一种高效且灵活的方式来管理系统级服务。具体应用场景包括:
系统服务启动与管理
通过 ServiceManager,Android 系统能够启动、管理以及查询各种核心系统服务,如 WifiService、LocationService 等。这些服务通过 IBinder 接口与其他组件进行通信。
进程间通信(IPC)
由于 Android 系统中的服务通常运行在不同的进程中,服务管理器提供了一种安全且高效的 IPC 机制。通过 Binder 机制,系统中的各个组件能够在不同进程之间高效地交换数据。
隔离进程与权限管理
通过 allowIsolated 参数,系统服务可以指定是否允许其运行在隔离沙盒进程中,从而增强系统安全性,避免不同服务间的互相干扰。
动态服务管理
服务的动态加载与卸载是 Android 系统的核心特性之一。在运行时,服务可以随时根据需要启动或销毁,而 ServiceManager 的注册与注销机制正是实现这一功能的关键。
三、新增系统服务
在 系统层新增服务(例如在 Android framework 层)时,通常涉及到以下几个步骤:
定义服务类、修改系统启动代码(SystemServer),注册服务到 ServiceManager,并确保客户端可以访问这些服务。详细流程如下:
1. 定义你的服务
在 Android 的 framework 层添加服务时,通常会继承 SystemService 类,或者直接实现一个 IBinder 接口(如果是跨进程服务)。以下是一个创建自定义系统服务的基础步骤。
1.1 创建自定义服务类
假设你要创建一个名为 MyCustomService 的服务类。它可以继承 SystemService 类,这样可以方便地管理服务的启动与停止。
// 文件:com/example/
package com.example;
import android.content.Context;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import com.android.server.SystemService;
public class MyCustomService extends SystemService {
private static final String TAG = "MyCustomService";
public MyCustomService(Context context) {
super(context);
}
@Override
public void onStart() {
Log.d(TAG, "MyCustomService started");
}
@Override
public void onStop() {
Log.d(TAG, "MyCustomService stopped");
}
public String getServiceInfo() throws RemoteException {
return "This is My Custom Service!";
}
}
2. 修改 SystemServer 启动自定义服务
SystemServer 是 Android 启动过程中负责启动所有系统服务的核心文件。我们需要在 中修改代码,确保系统启动时加载和启动我们的自定义服务。
2.1 修改 注册自定义服务
你需要在 SystemServer 中创建自定义服务的实例,并通过 () 注册该服务。
注册后,其他模块就可以通过 ServiceManager 获取并调用你的服务。
// 文件:com/android/server/
package com.android.server;
import android.os.ServiceManager;
import android.util.Log;
import com.example.MyCustomService;
import com.example.IMyCustomService;
public class SystemServer {
private static final String TAG = "SystemServer";
public static void main(String[] args) {
try {
// 启动自定义服务
startMyCustomService();
} catch (Exception e) {
Log.e(TAG, "Error starting system services", e);
}
}
private static void startMyCustomService() {
// 创建 MyCustomService 实例
MyCustomService myCustomService = new MyCustomService();
// 将服务注册到 ServiceManager
ServiceManager.addService("my_custom_service", myCustomService);
Log.d(TAG, "MyCustomService started successfully");
}
}
3. 编写 AIDL 接口(如果需要跨进程调用)
如果你的服务需要提供跨进程访问,你需要创建一个 AIDL 接口定义,并在服务端和客户端都实现它。AIDL 提供了 Android 系统间通信的机制。
3.1 定义 AIDL 接口
创建一个名为 的文件,定义服务的接口方法。
// 文件:com/example/
package com.example;
interface IMyCustomService {
String getServiceInfo();
}
3.2 服务端实现 AIDL 接口
服务端实现该接口时,需要实现 类。
// 文件:com/example/
package com.example;
import android.os.RemoteException;
public class MyCustomService extends IMyCustomService.Stub {
@Override
public String getServiceInfo() throws RemoteException {
return "This is My Custom Service!";
}
}
3.3 客户端调用服务
客户端通过 ServiceManager 获取服务,然后调用接口的方法。
package com.example;
import android.os.IBinder;
import android.os.ServiceManager;
import android.util.Log;
public class ClientApp {
private static final String TAG = "ClientApp";
public static void main(String[] args) {
try {
// 获取 MyCustomService
IBinder binder = ServiceManager.getService("my_custom_service");
// 将 IBinder 转换为 MyCustomService 接口
IMyCustomService myCustomService = IMyCustomService.Stub.asInterface(binder);
// 调用服务方法
String serviceInfo = myCustomService.getServiceInfo();
Log.d(TAG, "Service Info: " + serviceInfo);
} catch (Exception e) {
Log.e(TAG, "Failed to access MyCustomService", e);
}
}
}
4. 修改 或
如果你是通过 AOSP 添加服务,那么你需要确保在 或 文件中定义了你的服务类和依赖关系。这样系统编译时会包含你的服务。
例如,在 中添加:
# 文件:frameworks/base/Android.mk
LOCAL_SRC_FILES := \
com/example/MyCustomService.java
5. 注册服务到 ServiceManager
在 Android 启动过程中,SystemServer 会通过 () 将你的服务注册到系统服务管理器。这个过程允许系统中的其他模块或应用通过服务名来访问和调用你的服务。
// 注册到 ServiceManager
ServiceManager.addService("my_custom_service", myCustomService);
6. 重启系统或服务
为了使修改生效,你需要重新编译 framework 层并重启设备。具体步骤如下:
- 重新编译 AOSP:
make -j # 编译 AOSP 项目
- 重启设备:重新启动系统,或者你可以通过 ADB 重启系统服务。
adb reboot //命令行输入
总结
整个 ServiceManager 的实现展示了 Android 系统如何通过 Binder 机制高效地实现跨进程通信、服务的动态管理以及底层系统的服务协调。对于开发者来说,理解这个过程可以帮助我们更好地利用 Android 提供的服务框架,同时也为我们调试与优化系统服务提供了深入的视角。
通过这些细节,我们不仅能理解 Android 系统如何管理服务,还能在自定义服务或调试现有服务时,避免常见的陷阱和问题。