本篇文档主要分析安卓 Sensor框架Native层如何实现SensorEvent的分发。下面是我分析的主要源码的路径
2.传感器堆栈下图显示了Android传感器组件堆栈。各个组件仅可与其上方和下方紧邻的组件通信,控制信号从应用向下流向传感器数据从传感器向上流向应用。
2.1 SDK
应用通过Sensor SDK API访问传感器。SDK包含列出可用传感器和注册监听传感器数据的函数。在注册到传感器时应用可以指定自己的首选采样率和延迟要求。
2.2 Framework层
Sensor Framework负责将多个应用关联到HAL。HAL本身是单一客户端。如果框架级别没有发生这种多路复用则任何指定时间内每个传感器都只能被一个应用访问。 ● 当第一个应用注册到传感器时框架会向HAL发送请求以激活传感器。 ● 当其他应用注册到相同的传感器时框架会考虑每个应用的要求并将更新的已请求参数发送到HAL。 1.采样率将是请求的采用率的最大值这意味着一些应用接收事件的频率会高于所请求的频率 2.最大报告延迟将是请求的延迟的最小值。如果某个应用的最大报告延迟是0若它请求传感器则所有应用将以连续模 式从该传感器接收事件即使某些应用请求传感器时的最大报告延迟不是0也是如此。 ● 当注册到某个传感器的最后一个应用取消注册后框架会向HAL发送请求以停用该传感器从而避免不必要的功耗。
2.3HAL
Sensors Hardware Abstraction Layer(HAL)API是硬件驱动程序和Android框架之间的接口。它包含一个HAL接口sensors.h(hardware/libhardware/include/hardware/sensors.h)和一个被称为sensors.cpp的HAL实现。 接口由Android和AOSP贡献者定义并由设备制造商提供实现。
3.Native类的调用关系和启动流程3.1调用关系
下图大致展示了Sensor框架各个主要类的调用关系
3.2 启动流程
Sensor框架在系统中主要分两条路线启动 一条是系统启动时SensorService的启动另一条是系统启动时SensorManager.java启动连带着SensorManager.cpp的启动
3.2.1 SensorService的启动
SensorService是在system_server启动的时候被system_server启动的 代码路径frameworks/base/services/java/com/android/server/SystemServer.java
private void startBootstrapServices() {//......mSensorServiceStart SystemServerInitThreadPool.get().submit(() -> {TimingsTraceLog traceLog new TimingsTraceLog(SYSTEM_SERVER_TIMING_ASYNC_TAG, Trace.TRACE_TAG_SYSTEM_SERVER);traceLog.traceBegin(START_SENSOR_SERVICE);startSensorService();//调用JNI接口traceLog.traceEnd();}, START_SENSOR_SERVICE);//......}startSensorService是一个JNI方法其对应的C实现如下/** JNI registration.*/static const JNINativeMethod gMethods[] {/* name, signature, funcPtr *///这边先将该接口注册后面给system_server调用{ "startSensorService", "()V", (void*) android_server_SystemServer_startSensorService }{ "startHidlServices", "()V", (void*) android_server_SystemServer_startHidlServices },};//在这儿创建sensorservicestatic void android_server_SystemServer_startSensorService(JNIEnv* /* env */, jobject /* clazz */) {char propBuf[PROPERTY_VALUE_MAX];property_get("system_init.startsensorservice", propBuf, "1");if (strcmp(propBuf, "1") 0) {SensorService::instantiate();}}
从上面源码看出SensorService实例是通过调用SensorService::instantiate()方法创建的此方法来源于SensorService的父类BinderService所以实质上是调用BinderService::instantiate()来创建实例而BinderService::instantiate()方法内部仅仅调用了BinderService::publish(),相关方法源码如下
//这边SERVICE为SensorService类型templateclass BinderService{//......public:static status_t publish(bool allowIsolated false,int dumpFlags IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT) {sp sm(defaultServiceManager());//创建SensorService实例并且添加到ServiceManagereturn sm->addService(String16(SERVICE::getServiceName()), new SERVICE(), allowIsolated,dumpFlags);}static void instantiate() { publish(); }//......};
看SensorService的构造函数主要是创建了UidPolicy对象此对象功能是管理待机sensor的行为
SensorService::SensorService(): mInitCheck(NO_INIT), mSocketBufferSize(SOCKET_BUFFER_SIZE_NON_BATCHED),mWakeLockAcquired(false) {mUidPolicy new UidPolicy(this);}
在BinderService::publish()函数中创建SensorService实例时会调用onFirstRef()方法这个方法里首先创建并获取SensorDevice实例获取vendor层注册的sensor数据然后遍历每个sensor并将它们注册到SensorList里边创建并运行一个SensorEventAckReceiver线程再创建一个线程运行SensorService::threadLoop(),其代码如下
void SensorService::onFirstRef() {SensorDevice//创建并获取SensorDevice实例sHmacGlobalKeyIsValid initializeHmacKey();if (dev.initCheck() NO_ERROR) {sensor_t const* list;ssize_t count dev.getSensorList(//获取vendor层注册的sensor 数目if (count > 0) {ssize_t orientationIndex -1;bool hasGyro false, hasAccel false, hasMag false;uint32_t virtualSensorsNeeds (1< 下面来看SensorService::threadLoop()方法 bool SensorService::threadLoop() {ALOGD("nuSensorService thread starting...");// each virtual sensor could generate an event per "real" event, thats why we need to size// numEventMax much smaller than MAX_RECEIVE_BUFFER_EVENT_COUNT. in practice, this is too// aggressive, but guaranteed to be enough.const size_t vcount mSensors.getVirtualSensors().size();const size_t minBufferSize SensorEventQueue::MAX_RECEIVE_BUFFER_EVENT_COUNT;const size_t numEventMax minBufferSize / (1 vcount);//比如这边有vcount个虚拟的 sensor跑在framework,//那么比较极端的情况下每从HAL取numEventMax个数据,这边vcount个sensor会各生成numEventMax个数据,//而mSensorEventBuffer 最多只能容纳 MAX_RECEIVE_BUFFER_EVENT_COUNT个数据,//所以 numEventMax minBufferSize / (1 vcount);SensorDeviceconst int halVersion device.getHalDeviceVersion();do {//通过SensorDevice往HAL层取数据, 若没有数据的时候就一直阻塞(这个由前面说的第三方SO库实现)//一般在该so库的poll里边可以采用c标准实现的queue::pop(),来获取数据没数据时就一直阻塞//当驱动有数据上来时另外一个线程将sensor数据往这个队列里边queue::pop就行了ssize_t count device.poll(mSensorEventBuffer, numEventMax);if (count <0) {ALOGE("sensor poll failed (%s)", strerror(-count));break;}// Reset sensors_event_t.flags to zero for all events in the buffer.for (int i 0; i 该方法就是用SensorDevice循环去HAL层取数据若无数据则阻塞当前线程若有数据则封装SensorEventConnection发送出去。至此SensorService已经启动了。 从前一篇分析安卓Sensor 框架 Java API层的源码中我们知道SystemSensorManager继承并实现SensorManager的虚方法应用通过调用SensorManger的方法来达到其监听sensor数据的需求而实际功能的实现者是SystemSensorManager且SystemSensorManager中负责和Native层的SensorManager交互。安卓系统开机时在 frameworks/base/core/java/android/app/SystemServiceRegistry.java中创建SystemSensorManger实例 registerService(Context.SENSOR_SERVICE, SensorManager.class,new CachedServiceFetcher() {Overridepublic SensorManager createService(ContextImpl ctx) {return new SystemSensorManager(ctx.getOuterContext(),ctx.mMainThread.getHandler().getLooper());}});然后跳转到SystemSensorManager的构造方法中public SystemSensorManager(Context context, Looper mainLooper) {synchronized (sLock) {if (!sNativeClassInited) {sNativeClassInited true;nativeClassInit();//native层offset初始化,没做什么其他事情}}Log.e(">lkh", Log.getStackTraceString(new Throwable()));mMainLooper mainLooper;mTargetSdkLevel context.getApplicationInfo().targetSdkVersion;mContext context;mNativeInstance nativeCreate(context.getOpPackageName());//mNativeInstance 保存native创建的 c对象 SensorManager的引用,//该对象通过getOpPackageName()返回的结果作为参数创建,并且2者保存在一个map里边,//注意,此SensorManager为native层c实现的,非面向应用用Java实现的SensorManager// initialize the sensor listfor (int index 0;; index) {Sensor sensor new Sensor();if (!nativeGetSensorAtIndex(mNativeInstance, sensor, index)) break;mFullSensorsList.add(sensor);mHandleToSensor.put(sensor.getHandle(), sensor);}//获取SesorService的sensor list里边的所有sensor,每个sensor创建一个对应的java层的Sensor对象,//并保存到链表里边,并将sensor handle和sensor一并保存到map里边}在加锁的情况下如果没有初始化过Native层的类则调用nativeClassInit() JNI方法初始化调用nativeCreate()方法初始化SensorManager.cpp的实例再调用nativeGetSensorAtIndex() jni方法初始化sensor列表以上分析可知当SystemSensorManager初始化时SensorManager.cpp同时也初始化了。static jlongnativeCreate(JNIEnv *env, jclass clazz, jstring opPackageName){ScopedUtfChars opPackageNameUtf(env, opPackageName);return (jlong) }接下来跳入Native SensorManager的构造函数中SensorManager::SensorManager(const String16re not locked here, but its not needed during constructionassertStateLocked();}status_t SensorManager::assertStateLocked() {bool initSensorManager false;if (mSensorServer NULL) {initSensorManager true;} else {// Ping binder to check if sensorservice is alive.status_t err IInterface::asBinder(mSensorServer)->pingBinder();if (err ! NO_ERROR) {initSensorManager true;}}if (initSensorManager) {waitForSensorService(LOG_ALWAYS_FATAL_IF(mSensorServer nullptr, "getService(SensorService) NULL");class DeathObserver : public IBinder::DeathRecipient {SensorManagervirtual void binderDied(const wpmSensorManager.sensorManagerDied();}public:explicit DeathObserver(SensorManagermDeathObserver new DeathObserver(*const_cast(this));IInterface::asBinder(mSensorServer)->linkToDeath(mDeathObserver);mSensors mSensorServer->getSensorList(mOpPackageName);size_t count mSensors.size();mSensorList static_cast(malloc(count * sizeof(Sensor*)));LOG_ALWAYS_FATAL_IF(mSensorList NULL, "mSensorList NULL");for (size_t i0 ; i 接下来分析SensorService如何将sensor数据分发到应用上面SensorService启动时我们知道SensorService启动了一个线程去执行threadLoop方法这个方法首先调用SensorDevice::getInstance()方法获取其实例引用接下来就进入了一个调用SensorDevice::poll()方法的do while循环中SensorDevice在其中扮演了十分重要的角色主要通过该类从HAL层取数据下面是SensorDevice的部分源码 SensorDevice::SensorDevice(): mHidlTransportErrors(20), mRestartWaiter(new HidlServiceRegistrationWaiter()) {//通过hidl与HAL层建立连接if (!connectHidlService()) {return;}//获取开机时前面所说的第三方SO库注册的sensor这个SO库一般就是直接与驱动进行通信对实际sensor进行开关和数据获取了//比如高通骁龙855的sensors.ssc.so通过qmi与slpi进行通信。//这些sensor_t 类型的结构体需要第三方的so库里边自己实现每个结构体对象存储一个sensor的信息checkReturn(mSensors->getSensorsList([ list.size();mActivationCount.setCapacity(count);Info model;for (size_t i0 ; i 与HAL层如何交互的分析已经远远超出我负责的范畴了这里不做深入分析。我们只需知道Native层的Sensor数据是通过SensorDevice去HAL取得的就行了。当数据上来后通过做一些判断和处理然后再分发给应用其中判断处理包括是否应该丢弃数据是否是flush数据是否需要将数据给融合sensor应用是否已经关闭该sensor等处理后通过SensorService::SensorEventConnection::sendEvents将数据发出senEvent()函数代码如下 status_t SensorService::SensorEventConnection::sendEvents(sensors_event_t const* buffer, size_t numEvents,sensors_event_t* scratch,wp const * mapFlushEventsToConnections) {// filter out events not for this connectionsensors_event_t* sanitizedBuffer nullptr;int count 0;Mutex::Autolock _l(mConnectionLock); if (scratch) {size_t i0;while (i 发现别无他法发送数据唯有SensorEventQueue::write() 对复制得来的的scratch数据进行了处理下面跳进该方法中 ssize_t SensorEventQueue::write(const sp} 该方法仅仅调用了一下BitTube::sendObjects()方法只能进入此方法中查看 ssize_t BitTube::sendObjects(const sp reinterpret_cast(events);ssize_t size tube->write(vaddr, count*objSize);// should never happen because of SOCK_SEQPACKETLOG_ALWAYS_FATAL_IF((size > 0) %zu, size%zu), res%zd (partial events were sent!)",count, objSize, size);看到tube->write(),则继续跟进去看ssize_t BitTube::write(void const* vaddr, size_t size){ssize_t err, len;do {//这边通过 unix域套接字 发出去len ::send(mSendFd, vaddr, size, MSG_DONTWAIT | MSG_NOSIGNAL);// cannot return less than size, since were using SOCK_SEQPACKETerr len <0 ? errno : 0;} while (err EINTR);return err 0 ? len : -err;} 这个send方法是 sys/socket.h中声明的是Unix套接字这里分析到发送端就结束了。 接下来分析接收端怎么接收的应用是通过SensorManager注册一个SensorEventListener来接收数据的主要是通过调用registerListener方法代码如下 public boolean registerListener(SensorEventListener listener, Sensor sensor,int samplingPeriodUs, Handler handler) {int delay getDelay(samplingPeriodUs);return registerListenerImpl(listener, sensor, delay, handler, 0, 0);}SystemSensorManager是SensorManager的实现类其实现方法如下protected boolean registerListenerImpl(SensorEventListener listener, Sensor sensor,int delayUs, Handler handler, int maxBatchReportLatencyUs, int reservedFlags) {if (listener null || sensor null) {Log.e(TAG, "sensor or listener is null");return false;}// Trigger Sensors should use the requestTriggerSensor call.if (sensor.getReportingMode() Sensor.REPORTING_MODE_ONE_SHOT) {Log.e(TAG, "Trigger Sensors should use the requestTriggerSensor.");return false;}if (maxBatchReportLatencyUs <0 || delayUs MAX_LISTENER_COUNT) {throw new IllegalStateException("register failed, " "the sensor listeners size has exceeded the maximum limit " MAX_LISTENER_COUNT);}// Invariants to preserve:// - one Looper per SensorEventListener// - one Looper per SensorEventQueue// We map SensorEventListener to a SensorEventQueue, which holds the loopersynchronized (mSensorListeners) {SensorEventQueue queue mSensorListeners.get(listener);if (queue null) {Looper looper (handler ! null) ? handler.getLooper() : mMainLooper;final String fullClassName listener.getClass().getEnclosingClass() ! null ?listener.getClass().getEnclosingClass().getName() :listener.getClass().getName();queue new SensorEventQueue(listener, looper, this, fullClassName);if (!queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs)) {queue.dispose();return false;}mSensorListeners.put(listener, queue);return true;} else {return queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs);}}} 在各种合法性判断之后先根据传入的listener获取对应的SensorEventQueue实例如果不为空则调用addSensor方法为空则创建该实例并调用addSensor方法最后将其加入mSensorListeners中而创建实例时会调用android/frameworks/base/core/jni/android_hardware_SensorManager.cpp nativeInitSensorEventQueue()其源码如下 static jlong nativeInitSensorEventQueue(JNIEnv *env, jclass clazz, jlong sensorManager,jobject eventQWeak, jobject msgQ, jstring packageName, jint mode) {SensorManager* mgr reinterpret_cast(sensorManager);ScopedUtfChars packageUtf(env, packageName);String8 clientName(packageUtf.c_str());sp queue(mgr->createEventQueue(clientName, mode));if (queue NULL) {jniThrowRuntimeException(env, "Cannot construct native SensorEventQueue.");return 0;}sp messageQueue android_os_MessageQueue_getMessageQueue(env, msgQ);//获取MessageQueueif (messageQueue NULL) {jniThrowRuntimeException(env, "MessageQueue is not initialized.");return 0;}sp receiver new Receiver(queue, messageQueue, eventQWeak);receiver->incStrong((void*)nativeInitSensorEventQueue);return jlong(receiver.get());} 这里创建了一个接收数据的Receiver对象该类定义也在android_hardwate_SensorManager.cpp中receiver又根据clientName创建了一个Native层的SensorEventQueue Receiver(const sp AndroidRuntime::getJNIEnv();//保存传进来的2个比较关键的对象引用mSensorQueue sensorQueue;mMessageQueue messageQueue;mReceiverWeakGlobal env->NewGlobalRef(receiverWeak);mIntScratch (jintArray) env->NewGlobalRef(env->NewIntArray(16));mFloatScratch (jfloatArray) env->NewGlobalRef(env->NewFloatArray(16));}receiver在执行incStrong时会顺带执行它自己的onFirstRef()方法virtual void onFirstRef() {LooperCallback::onFirstRef();//获取套接字fdmMessageQueue->getLooper()->addFd(mSensorQueue->getFd(), 0,ALOOPER_EVENT_INPUT, this, mSensorQueue.get());} 上面将SensorEventQueue中BitTube里通过unix socket创建的mReceiveFd添加到looper里在Looper::pollInner()方法中通过epoll监听该fd当有事件时就会回调Receiver::hanldeEvent(),接下来看该方法 virtual int handleEvent(int fd, int events, void* data) {JNIEnv* env AndroidRuntime::getJNIEnv();sp q reinterpret_cast(data);ScopedLocalRef receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal));ssize_t n;ASensorEvent buffer[16];//这边最后是通过标准的socket接口recv将数据读取出来,代码在以下位置://android/frameworks/native/libs/sensor//SensorEventQueue::read() > BitTube::recvObjects()>BitTube::read()while ((n q->read(buffer, 16)) > 0) {for (int i0 ; iSetFloatArrayRegion(mFloatScratch, 0, 1, } else if (buffer[i].type SENSOR_TYPE_DYNAMIC_SENSOR_META) {float value[2];value[0] buffer[i].dynamic_sensor_meta.connected ? 1.f: 0.f;value[1] float(buffer[i].dynamic_sensor_meta.handle);env->SetFloatArrayRegion(mFloatScratch, 0, 2, value);} else if (buffer[i].type SENSOR_TYPE_ADDITIONAL_INFO) {env->SetIntArrayRegion(mIntScratch, 0, 14,buffer[i].additional_info.data_int32);env->SetFloatArrayRegion(mFloatScratch, 0, 14,buffer[i].additional_info.data_float);} else {env->SetFloatArrayRegion(mFloatScratch, 0, 16, buffer[i].data);}if (buffer[i].type SENSOR_TYPE_META_DATA) {// This is a flush complete sensor event. Call dispatchFlushCompleteEvent// method.if (receiverObj.get()) {env->CallVoidMethod(receiverObj.get(),gBaseEventQueueClassInfo.dispatchFlushCompleteEvent,buffer[i].meta_data.sensor);}} else if (buffer[i].type SENSOR_TYPE_ADDITIONAL_INFO) {// This is a flush complete sensor event. Call dispatchAdditionalInfoEvent// method.if (receiverObj.get()) {int type buffer[i].additional_info.type;int serial buffer[i].additional_info.serial;env->CallVoidMethod(receiverObj.get(),gBaseEventQueueClassInfo.dispatchAdditionalInfoEvent,buffer[i].sensor,type, serial,mFloatScratch,mIntScratch,buffer[i].timestamp);}}else {int8_t status;switch (buffer[i].type) {case SENSOR_TYPE_ORIENTATION:case SENSOR_TYPE_MAGNETIC_FIELD:case SENSOR_TYPE_ACCELEROMETER:case SENSOR_TYPE_GYROSCOPE:case SENSOR_TYPE_GRAVITY:case SENSOR_TYPE_LINEAR_ACCELERATION:status buffer[i].vector.status;break;case SENSOR_TYPE_HEART_RATE:status buffer[i].heart_rate.status;break;default:status SENSOR_STATUS_ACCURACY_HIGH;break;}//关键就在这里,这边通过jni回调SystemSensorManager::dispatchSensorEvent(),将数据给SensorManagerif (receiverObj.get()) {env->CallVoidMethod(receiverObj.get(),gBaseEventQueueClassInfo.dispatchSensorEvent, buffer[i].sensor,mFloatScratch,status,buffer[i].timestamp);}}if (env->ExceptionCheck()) {mSensorQueue->sendAck(buffer, n);ALOGE("Exception dispatching input event.");return 1;}}//对SensorService::SensorEventConnection发送确认,//SensorService::SensorEventConnection::handleEvent()接收并确认mSensorQueue->sendAck(buffer, n);}if (n<0 -EAGAIN) {// FIXME: error receiving events, what to do in this case?}return 1;}}; 方法里面通过JNI 在C代码里调用了SystemSensorManagre.java 中 BaseEventQueue的 dispatchSensorEvent()下面为该方法SensorEventQueue.java实现类源码 protected void dispatchSensorEvent(int handle, float[] values, int inAccuracy,long timestamp) {final Sensor sensor mManager.mHandleToSensor.get(handle);if (sensor null) {// sensor disconnectedreturn;}SensorEvent t null;synchronized (mSensorsEvents) {t mSensorsEvents.get(handle);}if (t null) {// This may happen if the client has unregistered and there are pending events in// the queue waiting to be delivered. Ignore.return;}// Copy from the values array.System.arraycopy(values, 0, t.values, 0, t.values.length);t.timestamp timestamp;t.accuracy inAccuracy;t.sensor sensor;// call onAccuracyChanged() only if the value changesfinal int accuracy mSensorAccuracies.get(handle);if ((t.accuracy > 0) t.accuracy)) {mSensorAccuracies.put(handle, t.accuracy);mListener.onAccuracyChanged(t.sensor, t.accuracy);}mListener.onSensorChanged(t);//在这边通过多态回调应用开发者自己实现的onSensorChanged(),将sensor事件给到应用} 该方法最后调用了SensorEventListenerlistener的onSensorChanged方法最后回调到了应用。 Sensor数据的分发最终还是走的SocketSensorEventConnection类中持有 sp类型名为mChannel的实例而其也持有一个应用包名字符串和Java虚拟机名字符串一个应用对应一个SensorEventConnection通过SensorEventConnection进行sensor监听的管理。 来自https://www.yuque.com/zestzone/bdds6v/viqstz 如果想要成为架构师或想突破20~30K薪资范畴那就不要局限在编码业务要会选型、扩展提升编程思维。此外良好的职业规划也很重要学习的习惯很重要但是最重要的还是要能持之以恒任何不能坚持落实的计划都是空谈。 如果你没有方向这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》帮大家将杂乱、零散、碎片化的知识进行体系化的整理让大家系统而高效地掌握Android开发的各个知识点。 相对于我们平时看的碎片化内容这份笔记的知识点更系统化更容易理解和记忆是严格按照知识体系编排的。 全套视频资料 一、面试合集 二、源码解析合集 三、开源框架合集 欢迎大家一键三连支持若需要文中资料直接点击文末CSDN官方认证微信卡片免费领取3.2.2 SensorManager的启动流程
3.3 Sensor数据的分发
3.4总结