waitForService等待服务
waitForService() 与 getService() 的差别不只是“多等一会儿”。Android 17 的 native CppBackendShim 先做一次真实查询;如果没有 Binder,就注册一个 IServiceCallback,再用条件变量等待注册回调。每等待约一秒,它会重新查询一次,以处理服务死亡通知和 lazy service 启动之间的竞态;返回或失败离开作用域时,RAII 清理会注销通知。
本文面向已经读过 getService查询服务、checkService服务检查、SM的Binder死亡通知 和 Binder线程管理 的读者。本文回答等待 owner、回调消费者、条件变量生效时机、每秒重试和清理路径;不展开 waitForDeclaredService() 的 VINTF 判断,也不把条件变量等待误写成 Binder 驱动自动阻塞。
1. 入口分层
1.1 Java入口
源码文件:frameworks/base/core/java/android/os/ServiceManager.java
相关函数:waitForService()、waitForServiceNative()
public static IBinder waitForService(@NonNull String name) {
return Binder.allowBlocking(waitForServiceNative(name));
}
private static native IBinder waitForServiceNative(@NonNull String name);Java 方法本身没有循环;等待在 JNI 调用的 native libbinder 路径中完成。Binder.allowBlocking() 只调整返回 Binder 的调用策略,不负责等待服务出现。
1.2 JNI桥接
源码文件:frameworks/base/core/jni/android_os_ServiceManager.cpp
相关函数:android_os_ServiceManager_waitForServiceNative()
static jobject android_os_ServiceManager_waitForServiceNative(
JNIEnv* env, jclass /* clazzObj */, jstring serviceNameObj) {
const jchar* serviceName = env->GetStringCritical(
serviceNameObj, nullptr);
if (!serviceName) {
jniThrowNullPointerException(env, nullptr);
return nullptr;
}
String16 nameCopy(reinterpret_cast<const char16_t*>(serviceName),
env->GetStringLength(serviceNameObj));
env->ReleaseStringCritical(serviceNameObj, serviceName);
sp<IBinder> service = defaultServiceManager()->waitForService(nameCopy);
if (!service) return nullptr;
return javaObjectForIBinder(env, service);
}JNI 只负责复制 Java 字符串、调用旧 libbinder IServiceManager 接口并把结果包装成 Java Binder。真正的等待 owner 是 native CppBackendShim::waitForService()。
1.3 旧接口适配
源码文件:frameworks/native/libs/binder/IServiceManager.cpp
相关类型:CppBackendShim
defaultServiceManager() 返回的旧接口由 CppBackendShim 适配到新的 AIDL backend。这样 Java native、旧 C++ 客户端和 AIDL ServiceManager 可以共享同一套等待实现;但 getService() 的旧兼容路径仍可能有不同等待行为,不能只看接口名称判断。
2. 首次查询
2.1 真实查询
源码文件:frameworks/native/libs/binder/IServiceManager.cpp
相关函数:CppBackendShim::waitForService()
const std::string name = String8(name16).c_str();
sp<IBinder> out;
if (Status status = realGetService(name, &out);
!status.isOk()) {
ALOGW("Failed to getService in waitForService for %s: %s",
name.c_str(), status.toString8().c_str());
return nullptr;
}
if (out != nullptr) return out;等待不是无条件注册 callback。先查询可以避免已经运行的服务走回调注册和条件变量;查询失败则立即返回空,查询成功但 Binder 为空才进入等待阶段。
2.2 线程模型警告
sp<ProcessState> self = ProcessState::selfOrNull();
if (self && 0 == self->getThreadPoolMaxTotalThreadCount()) {
ALOGW("Got service, but may be racey because we could not wait efficiently");
}源码明确提示:若进程没有保证的 Binder 线程,回调可能无法被及时消费。等待线程本身不主动调用 getAndExecuteCommand(),因为回调可能由另一个 Binder 线程处理;强行由当前线程消费可能造成“另一个线程收到回调、当前线程永远等不到”的悬挂。
3. 回调等待
3.1 Waiter对象
源码文件:frameworks/native/libs/binder/IServiceManager.cpp
相关类型:CppBackendShim::waitForService() 内部 Waiter
class Waiter : public android::os::BnServiceCallback {
Status onRegistration(const std::string& /*name*/,
const sp<IBinder>& binder) override {
std::unique_lock<std::mutex> lock(mMutex);
mBinder = binder;
lock.unlock();
IPCThreadState::self()->flushCommands();
mCv.notify_one();
return Status::ok();
}
public:
sp<IBinder> mBinder;
std::mutex mMutex;
std::condition_variable mCv;
};Waiter 同时拥有结果、互斥锁和条件变量。回调先在锁内写入 Binder,再解锁并通知;等待方用同一 mutex 检查谓词。flushCommands() 确保回调线程上待发送的 Binder 命令及时提交,避免服务引用状态滞留。
3.2 注册与RAII
sp<Waiter> waiter = sp<Waiter>::make();
if (Status status = mUnifiedServiceManager->registerForNotifications(
name, waiter); !status.isOk()) {
return nullptr;
}
Defer unregister([&] {
mUnifiedServiceManager->unregisterForNotifications(name, waiter);
});注册成功后,无论后续是收到 Binder、重新查询失败还是函数返回,Defer 析构都会注销 callback。这个清理不是可选优化:否则每次等待都会把一个过期 Waiter 留在 ServiceManager 的注册回调表中。
3.3 条件变量
while (true) {
{
std::unique_lock<std::mutex> lock(waiter->mMutex);
waiter->mCv.wait_for(lock, 1s, [&] {
return waiter->mBinder != nullptr;
});
if (waiter->mBinder != nullptr) return waiter->mBinder;
}
ALOGW("Waited one second for %s", name.c_str());
// later realGetService retry follows
}一秒是条件变量的观察周期,不是服务启动超时。wait_for 被虚假唤醒时仍会重新检查谓词;超时后函数不直接失败,而是记录等待日志并进入下一次真实查询。
4. 竞态重试
4.1 重查逻辑
源码文件:frameworks/native/libs/binder/IServiceManager.cpp
相关函数:CppBackendShim::waitForService()
if (Status status = realGetService(name, &out);
!status.isOk()) {
ALOGW("Failed to getService in waitForService on later try");
return nullptr;
}
if (out != nullptr) return out;每次一秒等待后都重新调用 realGetService()。源码注释描述了一个竞态:服务死亡、ServiceManager 处理死亡通知、ServiceManager 发起 lazy 启动请求、init 观察到服务仍像已启动、随后才收到死亡信号。重查是为了再次发出启动请求,避免第一次请求被 init 的状态判断吞掉。
4.2 回调先到
注册 callback 时,如果服务已经在注册前后加入,ServiceManager 的 registerForNotifications() 会立即向 callback 派发当前 Binder;Waiter::onRegistration() 写入 mBinder 并唤醒条件变量。因此等待方不能假设“注册完成后一定要等完整一秒”,谓词可能在首次 wait 前就已为真。
4.3 服务死亡
若服务在首次查询后死亡,ServiceManager 的 binderDied() 会删除服务表项;等待 callback 的下一次循环可能仍为空,然后重新查询触发 lazy 启动。等待机制不直接监听服务 Binder 的死亡,它监听的是服务注册 callback;服务死亡如何清理表项由前一篇死亡通知教材负责。
5. 结束路径
5.1 成功
回调写入 Binder、首次查询或重试查询得到 Binder 时直接返回。返回前 Defer 对象离开作用域,注销等待 callback;Java JNI 将 native Binder 转成 Java 对象。
5.2 失败
首次 realGetService() 返回错误、注册通知失败或后续重试返回错误都会返回 nullptr。源码没有固定总超时;只要服务持续为空且没有错误,循环会继续以一秒为周期等待和重查。
5.3 清理
class Defer {
public:
explicit Defer(std::function<void()>&& f) : mF(std::move(f)) {}
~Defer() { mF(); }
private:
std::function<void()> mF;
};清理动作是注销 (name, waiter) 注册。若线程被进程生命周期终止,C++ 栈展开决定是否执行析构;文章不把 detached lazy 启动线程的生命周期误认为等待线程的可取消任务。
6. 测试边界
6.1 注册通知
源码文件:frameworks/native/cmds/servicemanager/test_sm.cpp
ServiceNotifications.GetNotification 覆盖“先注册 Waiter、后添加服务”;GetNotificationForAlreadyRegisteredService 覆盖“先添加服务、后注册 Waiter”;两者都断言 onRegistration 收到正确 Binder。它们反向验证等待依赖的 callback 两种时序。
6.2 Fake manager
源码文件:frameworks/native/libs/fakeservicemanager/test_sm.cpp
Fake manager 测试覆盖注册后查询和 clear 后查询为空,但不执行 CppBackendShim::waitForService() 的 condition variable、每秒重试、init 属性或真实 Binder callback。当前源码测试能证明服务状态的输入输出,不能证明设备上的等待时长和线程池可用性。
6.3 可执行阅读
rg -n "waitForServiceNative|waitForService\(" \
frameworks/base/core/java/android/os/ServiceManager.java \
frameworks/base/core/jni/android_os_ServiceManager.cpp \
frameworks/native/libs/binder/IServiceManager.cpp
rg -n "class Waiter|registerForNotifications|wait_for|realGetService|Defer" \
frameworks/native/libs/binder/IServiceManager.cpp
rg -n "GetNotification|GetNotificationForAlreadyRegisteredService" \
frameworks/native/cmds/servicemanager/test_sm.cpp遇到 waitForService() 长时间不返回,先检查 Binder 线程池是否能消费 onRegistration 回调,再看 ServiceManager 是否已通过 binderDied() 删除旧项、重试是否重新触发 lazy 启动,最后确认 (name, waiter) 注册是否成功。不要只把“一秒日志”解释成固定总超时:源码没有这样的上限。
