如果要作为一个Service来提供,我们应该怎么设计呢?
TODO:
QA:怎么设计比较合理。
首先,在Android 系统启动的时候init进程
/system/core/init
int main(int argc, char** argv) { ... parser.ParseConfig("/init.rc"); ... }
/system/core/rootdir/init.rc
on post-fs # Load properties from # /system/build.prop, # /odm/build.prop, # /vendor/build.prop and # /factory/factory.prop load_system_props # start essential services start logd start servicemanager start hwservicemanager start vndservicemanager
post-fs触发之后,在原先(Android O之前)启动servicemanager的时候,把hwservicemanager和vndservicemanager都启动了!
post-fs触发时机:
#节选自system/core/rootdir/init.rc ... on late-init ... trigger post-fs
而late-init是在这触发的:
system/core/init/init.cpp
... std::string bootmode = GetProperty("ro.bootmode", ""); if (bootmode == "charger") { am.QueueEventTrigger("charger"); } else { am.QueueEventTrigger("late-init"); } ...
启动模式不是“charger”就触发这个。。。什么鬼
我们找到hwservicemanager:
先看看编译文件/system/hwservicemanager/Android.bp
... cc_binary { name: "hwservicemanager", init_rc: [ "hwservicemanager.rc", ], srcs: [ "AccessControl.cpp", "HidlService.cpp", "ServiceManager.cpp", "service.cpp", "TokenManager.cpp", "Vintf.cpp", ], ...
/system/hwservicemanager/hwservicemanager.rc
service hwservicemanager /system/bin/hwservicemanager user system disabled group system readproc critical onrestart setprop hwservicemanager.ready false onrestart class_restart hal onrestart class_restart early_hal writepid /dev/cpuset/system-background/tasks class animation
会启动一个二进制可执行程序hwservicemanager,目录在/system/bin/
找main函数
//system/hwservicemanager/service.cpp static std::string serviceName = "default"; int main() { ... ServiceManager *manager = new ServiceManager(); if (!manager->add(serviceName, manager)) { ALOGE("Failed to register hwservicemanager with itself."); } TokenManager *tokenManager = new TokenManager(); if (!manager->add(serviceName, tokenManager)) { ALOGE("Failed to register ITokenManager with hwservicemanager."); } sp<Looper> looper(Looper::prepare(0 /* opts */)); int binder_fd = -1; //请求binder文件描述符 IPCThreadState::self()->setupPolling(&binder_fd); if (binder_fd < 0) { ALOGE("Failed to aquire binder FD. Aborting..."); return -1; } //刷新下 IPCThreadState::self()->flushCommands(); //添加hwbinder文件描述符到Looper sp<BinderCallback> cb(new BinderCallback); if (looper->addFd(binder_fd, Looper::POLL_CALLBACK, Looper::EVENT_INPUT, cb, nullptr) != 1) { ALOGE("Failed to add hwbinder FD to Looper. Aborting..."); return -1; } //告诉IPCThreadState 我们是service manager sp<BnHwServiceManager> service = new BnHwServiceManager(manager); IPCThreadState::self()->setTheContextObject(service); // 告诉binder kernel ioctl(binder_fd, BINDER_SET_CONTEXT_MGR, 0); ... //写入hwservicemanager.ready属性节点 rc = property_set("hwservicemanager.ready", "true"); }
最后这个啰嗦一句
前面hwservicemanager.rc中有这个
onrestart setprop hwservicemanager.ready false
系统重启的时候,会将这个属性设置回去。
第二个点是IPCThreadState::self()->setTheContextObject(service);
搜索了下IPCThreadState,有两个结果
./system/libhwbinder/IPCThreadState.cpp ./frameworks/native/libs/binder/IPCThreadState.cpp
根据前面的#include
那么应该是这个专门给hw设计的(另外那个是给普通的binder用的)
setTheContextObject@android::hardware::IPCThreadState
//system/libhwbinder/IPCThreadState.cpp void IPCThreadState::setTheContextObject(sp<BHwBinder> obj) { mContextObject = obj; }
到这里hwservicemanager算启动完成了。
/hardware/interfaces/automotive/vehicle/2.0/default/Android.mk
... ############################################################################### # Vehicle HAL service ############################################################################### include $(CLEAR_VARS) LOCAL_MODULE := $(vhal_v2_0)-service //LOCAL_INIT_RC的详细解释在 ///system/core/init/README.md中有 LOCAL_INIT_RC := $(vhal_v2_0)-service.rc //是否是设备专有模块 LOCAL_PROPRIETARY_MODULE := true LOCAL_MODULE_RELATIVE_PATH := hw LOCAL_SRC_FILES := \ VehicleService.cpp ...
里面的LOCAL_INIT_RC(Android N之后加入的)说明这个rc会被加入到init里,在mount_all执行完成之后,就会被运行(反正大概是这么个意思)!
我们只看看[email protected]这个:[email protected]
service vehicle-hal-2.0 /vendor/bin/hw/[email protected] //hal类属,方便同时启动或停止, class hal //这个看着眼熟 user vehicle_network group system inet
m01/device/qcom/sepolicy/common/hal_audio.te
# Allow hal_audio to read soundcard state under /proc/asound allow hal_audio proc_audiod:file r_file_perms; allow hal_audio_default audio_data_file:dir rw_dir_perms; allow hal_audio_default audio_data_file:file create_file_perms; # Allow hal_audio_default to read sysfs_thermal dir/files for speaker protection r_dir_file(hal_audio_default, sysfs_thermal) userdebug_or_eng(` diag_use(hal_audio) #Allow access to debug fs allow hal_audio_default debugfs:dir r_dir_perms; allow hal_audio_default qti_debugfs:dir r_dir_perms; allow hal_audio_default qti_debugfs:file rw_file_perms; ') #Allow access to firmware allow hal_audio firmware_file:dir r_dir_perms; allow hal_audio firmware_file:file r_file_perms; #Split A2dp specific binder_call(hal_audio,bluetooth) #for perf hal call hal_client_domain(hal_audio_default, hal_perf) #allow acess to wcd_cpe allow hal_audio sysfs_audio:file rw_file_perms; allow hal_audio sysfs_audio:dir r_dir_perms ;
//VehicleService.cpp
int main(int /* argc */, char* /* argv */ []) { auto store = std::make_unique<VehiclePropertyStore>(); auto hal = std::make_unique<impl::EmulatedVehicleHal>(store.get()); auto emulator = std::make_unique<impl::VehicleEmulator>(hal.get()); auto service = std::make_unique<VehicleHalManager>(hal.get()); configureRpcThreadpool(4, true /* callerWillJoin */); ALOGI("Registering as service..."); service->registerAsService(); ALOGI("Ready"); joinRpcThreadpool(); }
make_unique是C++11中的语法,和new差不多总之,这里就是构造一个VehiclePropertyStore作为参数构造一个EmulatedVehicleHal,再作为参数。。。最后,生成VehicleHalManager对象,然后registerAsService。
registerAsService的实现:
///out/soong/.intermediates/hardware/interfaces/automotive/vehicle/2.0/[email protected]_genc++/gen/android/hardware/automotive/vehicle/2.0/VehicleAll.cpp ::android::status_t IVehicle::registerAsService(const std::string &serviceName) { ::android::hardware::details::onRegistration("[email protected]", "IVehicle", serviceName); const ::android::sp<::android::hidl::manager::V1_0::IServiceManager> sm = ::android::hardware::defaultServiceManager(); if (sm == nullptr) { return ::android::INVALID_OPERATION; } ::android::hardware::Return<bool> ret = sm->add(serviceName.c_str(), this); return ret.isOk() && ret ? ::android::OK : ::android::UNKNOWN_ERROR; }
我们找到defaultServiceManager的位置(这个CPP的名字是XXXXManagement让我极度怀疑是不是作者拼错了)
//system/libhidl/transport/ServiceManagement.cpp sp<IServiceManager> defaultServiceManager() { ... details::gDefaultServiceManager = fromBinder<IServiceManager, BpHwServiceManager, BnHwServiceManager>( ProcessState::self()->getContextObject(NULL)); ... }
上面传的一个参数,所以是这个,另外还有一个重载接受两个参数的
getContextObject@android::hardware::ProcessState
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/) { return getStrongProxyForHandle(0); }
分析不下去了(手动尴尬)!
百度了下,这个是分析普通的binder的:讲的挺好的
http://wangkuiwu.github.io/2014/09/04/Binder-defaultServiceManager/
总之,这个地方的sm应该就是前面特别早就启动的hwservicemanager(虽然流程没接上)。
继续上面的main函数分析
欣喜地可以发现:class VehicleHalManager : public IVehicle
我们要找的就是它啦!它是一个被init.rc起来的后台服务!上文的set调用就流向这里了
//VehicleHalManager::set ... auto status = mHal->set(value); ...
mHal是在VehicleHalManager的构造函数初始化列表里赋值的:
VehicleHalManager(VehicleHal* vehicleHal) : mHal(vehicleHal), ...
vehicleHal就是auto hal = std::make_unique
类似于(new EmulatedVehicleHal).get.
VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::get( const VehiclePropValue& requestedPropValue, StatusCode* outStatus) { VehiclePropValuePtr v = nullptr; auto internalPropValue = mPropStore->readValueOrNull(requestedPropValue); if (internalPropValue != nullptr) { v = getValuePool()->obtain(*internalPropValue); } *outStatus = v != nullptr ? StatusCode::OK : StatusCode::INVALID_ARG; return v; }
v是一个VehicleHal::VehiclePropValuePtr即recyclable_ptr
VehiclePropValue这个struct没有set方法啊。而且命名上来说,它也不应该是mHal的一种类型啊!什么情况。
这个地方,其实应该是EmulatedVehicleHal调用的是它的set方法:
mPropStore->writeValue(propValue) ... getEmulatorOrDie()->doSetValueFromClient(propValue); ...
再然后:VehiclePropertyStore::writeValue,一个很普通的方法!
VehicleEmulator* getEmulatorOrDie() { std::lock_guard<std::mutex> g(mEmulatorLock); if (mEmulator == nullptr) abort(); return mEmulator; } void VehicleEmulator::doSetValueFromClient(const VehiclePropValue& propValue) { emulator::EmulatorMessage msg; emulator::VehiclePropValue *val = msg.add_value(); //这个疑似 populateProtoVehiclePropValue(val, &propValue); msg.set_status(emulator::RESULT_OK); msg.set_msg_type(emulator::SET_PROPERTY_ASYNC); txMsg(msg); } //我的天啊 void VehicleEmulator::populateProtoVehiclePropValue(emulator::VehiclePropValue* protoVal, const VehiclePropValue* val) { protoVal->set_prop(val->prop); protoVal->set_value_type(toInt(getPropType(val->prop))); protoVal->set_timestamp(val->timestamp); protoVal->set_area_id(val->areaId); // Copy value data if it is set. // - for bytes and strings, this is indicated by size > 0 // - for int32, int64, and float, copy the values if vectors have data if (val->value.stringValue.size() > 0) { protoVal->set_string_value(val->value.stringValue.c_str(), val->value.stringValue.size()); } if (val->value.bytes.size() > 0) { protoVal->set_bytes_value(val->value.bytes.data(), val->value.bytes.size()); } for (auto& int32Value : val->value.int32Values) { protoVal->add_int32_values(int32Value); } for (auto& int64Value : val->value.int64Values) { protoVal->add_int64_values(int64Value); } for (auto& floatValue : val->value.floatValues) { protoVal->add_float_values(floatValue); } }
然后呢?没有然后了?类名叫车机仿真。难道这就算设置成功了?看来,需要有具体的Vendor厂家来做实现啊!