锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

sensor 传感器在 HAL 层的表现

时间:2022-12-15 10:00:01 hal880传感器传感器mk72sp2880角度传感器sp2801角度传感器vetor温度传感器sp2801传感器

人们在日常生活中经常使用传感器,如建筑物的楼梯灯、道路上的路灯等。那么手机中的传感器特别有什么作用呢?Android 提供加速传感器、磁场、方向、陀螺仪、光线、压力、温度等传感器。Android 在系统中。传感器的代码分布信息如下:

1) 传感器系统 Java 实现文件的部分为 Sensor*.java.

代码路径: frameworks/base/include/core/java/android/hardware

2) 传感器系统的JNI 部分,这部分演示 android.hardware.Sensor.Manager 类的本质支持。

代码路径: frameworks/base/core/jni/android_hardware_SensorManager.cpp.

3) 传感器系统 HAL 层,演示了传感器系统硬件抽象层需要具体的实现。

头文件路径:hardware/libhardware/include/hardware/sensor.h

4) 驱动层

代码路径: kernel/driver/hwmon/$(PROJECT)/sensor

1、 HAL 层的Sensor 代码

1) 文件 Android.mk

HAL 层的 代码 都是 c/cpp 格式,一般保存路径是 hardware/$(PROJECT)/sensor/. 其中,文件Android.mk 实现代码如下;

LOCAL_PATH : = $(call my-dir)

LOCAL_PRELINK_MODULE := false

LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw

LOCAL_SHARED_LIBARIES := libcutils libc liblog

LOCAL_SRC_FILES:= 适配文件

LOCAL_MODULE := sensors.$(PROJECT)

include $(BUILD_SHARED_LIBRARY)

注意 LOCAL_MODULE 这里的模块名称是提前定义的,具体可以参考 hardware/libhardware/hardware.c

在这里,我们可以看到加载顺序 Sensor 一次去找 这些 so 它是否存在,然后加载到相应的适。

2) 填充结构体

在 HAL 层,需要特别注意以下填充结构。

(1) 定义sensor 模块代码如下:

struct sensor_module_t {

struct hw_module_t common;

int (*get_sensors_list) (struct sensors_module_t *module, struct sensor_t const**list);

};

其中,get_sensors_list() 用来表示获取传感器的列表。

(2) sensor_t 具体代码如下:

struct sensor_t {

const char* name ; // 传感器名称

const char* vendor ; // 传感器的 vendor

int version; // 传感器版本

int handle ; // 传感器句柄

int type ; // 传感器类型

float maxRange; // 最大范围的传感器

float resolution; // 传感器的分析

float power; // 代替传感器的能耗 mA

void * reserved[9];

}

(3) 具体代码如下:

typedef struct {

int sensor; // sensor 标志符

unio {

sensors_vec_t vector; // x,y,z 矢量

sensors_vec_t orientation; // 方向键,单位为角度

sensors_vec_t acceleration; // 加速度值,单位为 m/s2

sensors_vec_t magnetic ; // 单位为磁矢量ut

float temperature; // 温度,单位 。c

float distance; // 距离, 单位 cm

float light; // 光线亮度, 单位 lux

}

int64_t time; //ns

uint32_t reserved;

} sensors_data_t;

3) 适配层 函数接口

在HAL 层中应注意以下函数。

static int a_device_open(const struct hw_module_t* module,

const char* name,

struct hw_device_t** device)

特别注意 以下赋值:

if (!strcmp(name,SENSORS_HARDWARE_CONTROL)) { // 命令通路

···

dev->device.common.close = dev_control_close;

dev->device.open_data_source=open_data_source;

dev->device.activate=activate;

dev->device.set_delay=set_delay;

```

} else if (!strcmp(name, SENSORS_HARDWARE_DATA)) { // 数据通路

···

dev->device.common.close=dev_data_close;

dev->device.data_open=data_open;

dev->device.data_close=data_close;

dev->device.poll=poll;

```

}

函数中可以根据名称知道 JNI 应该采用 poll 获取数据的方法,也就是说,驱动中提供的带是否应该实现 file_operation.

注意: 在驱动代码中获得 Sensor 寄存器的值不一定是我们实际报告给应用程序的值,例如g-sensor,每个方向不应大于 一定要注意其它因素。

3) Sensor 编程过程总结

Sensor 编程流程如下:

(1)Sensor 编程流程如下:

获取系统服务(SENSOR_SERVICE)返回一个 Sensormanager 对象。

sensormanager = (SensoerManager) getSystemSeriver (SENSOR_SERVICE);

(2)通过 SensorMnager 对象获取相应的 Sensor 类型的对象。

sensorObject= sensormanager.getDefaultSensor(sensor Type);

(3)声明一个 SensorEventListener 对象用于监听 Sensor 事件,并重载onSensorChanged方法。

SensorEventListener sensorListener = new SensorEventListener() {};

(4) 注册相应的SensorService.

sensormanager.registerListener(sensorListener, sensorobject,Sensor TYPE);

(5) 销毁相应的 SensorService.

sensormanager.unregisterListener(sensorListener,sensorObject);

此处的SensorListener 接口是整个传感器应用的核心,他包括如下两个必须的方法。

  • onSensorChanged(int sensor,float values[]); 此方法在传感器更改时调用,该方法只对受此应用程序监视的传感器调用。该方法包含如下两个参数:

        一个整数,指示更改的传感器。

        一个浮点数数组,表示传感器数据本身。

  • onAccuracyChanged(int sensor,int accuracy); 当传感器的准确值更改时调用此函数,此方法包含两个整数,一个表示传感器,一个表示传感器额精确值。

2、分析Sensor 源码API层 和硬件平台的衔接

接下来我们依照重力感应器Sensor 为例,看重力感应器如何与Applications, Appliaction Framwork 实现交互。

1) 首先在 文件 platform/hardware/Libardware/Include/Sensors.h 中看定义重力感应器对驱动程序的操作,代码如下:

/hardware/libhardware/include/hardware/sensors.h

/**
 * The id of this module
 */
#define SENSORS_HARDWARE_MODULE_ID "sensors"

/**
 * Name of the sensors device to open
 */
#define SENSORS_HARDWARE_POLL       "poll"

```````


/** convenience API for opening and closing a device */

static inline int sensors_open(const struct hw_module_t* module,
        struct sensors_poll_device_t** device) {
    return module->methods->open(module,
            SENSORS_HARDWARE_POLL, TO_HW_DEVICE_T_OPEN(device));
}

static inline int sensors_close(struct sensors_poll_device_t* device) {
    return device->common.close(&device->common);
}

static inline int sensors_open_1(const struct hw_module_t* module,
        sensors_poll_device_1_t** device) {
    return module->methods->open(module,
            SENSORS_HARDWARE_POLL, TO_HW_DEVICE_T_OPEN(device));
}

static inline int sensors_close_1(sensors_poll_device_1_t* device) {
    return device->common.close(&device->common);
}

(2) 文件 framwork/Jni/onLoad.cpp 用于加载该驱动的访问程序,具体代码如下:

/frameworks/base/services/core/jni/onload.cpp

 int register_android_server_SerialService(JNIEnv* env);

(3) 文件 framwork/Jni/com_androidserver_SensorService.cpp 用于向 Application Framework 提供接口。具体代码如下:

 /frameworks/base/services/core/jni/com_android_server_sensor_SensorService.cpp

/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define LOG_TAG "NativeSensorService"

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include 

#define PROXIMITY_ACTIVE_CLASS \
    "com/android/server/sensors/SensorManagerInternal$ProximityActiveListener"

namespace android {

static JavaVM* sJvm = nullptr;
static jmethodID sMethodIdOnProximityActive;

class NativeSensorService {
public:
    NativeSensorService(JNIEnv* env, jobject listener);

    void registerProximityActiveListener();
    void unregisterProximityActiveListener();

private:
    sp mService;

    class ProximityActiveListenerDelegate : public SensorService::ProximityActiveListener {
    public:
        ProximityActiveListenerDelegate(JNIEnv* env, jobject listener);
        ~ProximityActiveListenerDelegate();

        void onProximityActive(bool isActive) override;

    private:
        jobject mListener;
    };
    sp mProximityActiveListenerDelegate;
};

NativeSensorService::NativeSensorService(JNIEnv* env, jobject listener)
      : mProximityActiveListenerDelegate(new ProximityActiveListenerDelegate(env, listener)) {
    if (base::GetBoolProperty("system_init.startsensorservice", true)) {
        sp sm(defaultServiceManager());
        mService = new SensorService();
        sm->addService(String16(SensorService::getServiceName()), mService,
                       false /* allowIsolated */, IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL);
    }
}

void NativeSensorService::registerProximityActiveListener() {
    if (mService == nullptr) {
        ALOGD("Dropping registerProximityActiveListener, sensor service not available.");
        return;
    }
    mService->addProximityActiveListener(mProximityActiveListenerDelegate);
}

void NativeSensorService::unregisterProximityActiveListener() {
    if (mService == nullptr) {
        ALOGD("Dropping unregisterProximityActiveListener, sensor service not available.");
        return;
    }

    mService->removeProximityActiveListener(mProximityActiveListenerDelegate);
}

NativeSensorService::ProximityActiveListenerDelegate::ProximityActiveListenerDelegate(
        JNIEnv* env, jobject listener)
      : mListener(env->NewGlobalRef(listener)) {}

NativeSensorService::ProximityActiveListenerDelegate::~ProximityActiveListenerDelegate() {
    AndroidRuntime::getJNIEnv()->DeleteGlobalRef(mListener);
}

void NativeSensorService::ProximityActiveListenerDelegate::onProximityActive(bool isActive) {
    auto jniEnv = GetOrAttachJNIEnvironment(sJvm);
    jniEnv->CallVoidMethod(mListener, sMethodIdOnProximityActive, static_cast(isActive));
}

static jlong startSensorServiceNative(JNIEnv* env, jclass, jobject listener) {
    NativeSensorService* service = new NativeSensorService(env, listener);
    return reinterpret_cast(service);
}

static void registerProximityActiveListenerNative(JNIEnv* env, jclass, jlong ptr) {
    auto* service = reinterpret_cast(ptr);
    service->registerProximityActiveListener();
}

static void unregisterProximityActiveListenerNative(JNIEnv* env, jclass, jlong ptr) {
    auto* service = reinterpret_cast(ptr);
    service->unregisterProximityActiveListener();
}

static const JNINativeMethod methods[] = {
        {
                "startSensorServiceNative", "(L" PROXIMITY_ACTIVE_CLASS ";)J",
                reinterpret_cast(startSensorServiceNative)
        },
        {
                "registerProximityActiveListenerNative", "(J)V",
                reinterpret_cast(registerProximityActiveListenerNative)
        },
        {
                "unregisterProximityActiveListenerNative", "(J)V",
                reinterpret_cast(unregisterProximityActiveListenerNative)
         },

};

int register_android_server_sensor_SensorService(JavaVM* vm, JNIEnv* env) {
    sJvm = vm;
    jclass listenerClass = FindClassOrDie(env, PROXIMITY_ACTIVE_CLASS);
    sMethodIdOnProximityActive = GetMethodIDOrDie(env, listenerClass, "onProximityActive", "(Z)V");
    return jniRegisterNativeMethods(env, "com/android/server/sensors/SensorService", methods,
                                    NELEM(methods));
}

}; // namespace android

 到目前为止,完成了文件系统中的底层部分功能,由此可以看出,对于下层类库来说,可以通过HAL 的方式建立Android API 和硬件设备驱动链接的桥梁。针对不同的硬件平台,需要编写上述函数的实现方式,并且通过 Android kernel 中驱动来控制硬件行为。对于上层来说,可以看成是给顶层Java 实现 Android API 提供一个访问接口。因为该文件是一个编译成系统的*.so  库文件,这和 DK 里面为系统加载一个 *.so 及其相似。

(4) 监听 Sensor 的物理数据,接下来看 Application Framwork 层怎样监听Sensor的物理数据,此时可以通过 system.load("*.so") 来获取对某个库的访问,并使用其中的函数进行我们想要的操作。Google 为了方便程序员操作,使用Java 语言提供了便捷访问的Application Framework , 他们将底层的 C/C++ 实现的驱动或其他细节封装起来,其实就是 API 的原型。

下面回到 Android API 层,文件 /frameworks/base/services/core/java/com/android/server/sensors/SensorService.java 的实现代码如下:

/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.sensors;

import static com.android.server.sensors.SensorManagerInternal.ProximityActiveListener;

import android.annotation.NonNull;
import android.content.Context;
import android.util.ArrayMap;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.ConcurrentUtils;
import com.android.server.LocalServices;
import com.android.server.SystemServerInitThreadPool;
import com.android.server.SystemService;
import com.android.server.utils.TimingsTraceAndSlog;

import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;

/*
管理传感器装置的类
需要客户注册来激活传感器,传感器事件本身不播放这一服务
相反,一个文件描述符是提供给每一个客户的
*/

public class SensorService extends SystemService {
    private static final String START_NATIVE_SENSOR_SERVICE = "StartNativeSensorService";
    private final Object mLock = new Object();
    @GuardedBy("mLock")
    private final ArrayMap mProximityListeners =
            new ArrayMap<>();
    @GuardedBy("mLock")
    private Future mSensorServiceStart;
    @GuardedBy("mLock")
    private long mPtr;


    /** Start the sensor service. This is a blocking call and can take time. */
    private static native long startSensorServiceNative(ProximityActiveListener listener);

    private static native void registerProximityActiveListenerNative(long ptr);
    private static native void unregisterProximityActiveListenerNative(long ptr);


    public SensorService(Context ctx) {
        super(ctx);
        synchronized (mLock) {
            mSensorServiceStart = SystemServerInitThreadPool.submit(() -> {
                TimingsTraceAndSlog traceLog = TimingsTraceAndSlog.newAsyncLog();
                traceLog.traceBegin(START_NATIVE_SENSOR_SERVICE);
                long ptr = startSensorServiceNative(new ProximityListenerDelegate());
                synchronized (mLock) {
                    mPtr = ptr;
                }
                traceLog.traceEnd();
            }, START_NATIVE_SENSOR_SERVICE);
        }
    }

    @Override
    public void onStart() {
        LocalServices.addService(SensorManagerInternal.class, new LocalService());
    }

    @Override
    public void onBootPhase(int phase) {
        if (phase == SystemService.PHASE_WAIT_FOR_SENSOR_SERVICE) {
            ConcurrentUtils.waitForFutureNoInterrupt(mSensorServiceStart,
                    START_NATIVE_SENSOR_SERVICE);
            synchronized (mLock) {
                mSensorServiceStart = null;
            }
        }
    }

    class LocalService extends SensorManagerInternal {
        @Override
        public void addProximityActiveListener(@NonNull Executor executor,
                @NonNull ProximityActiveListener listener) {
            Objects.requireNonNull(executor, "executor must not be null");
            Objects.requireNonNull(listener, "listener must not be null");
            ProximityListenerProxy proxy = new ProximityListenerProxy(executor, listener);
            synchronized (mLock) {
                if (mProximityListeners.containsKey(listener)) {
                    throw new IllegalArgumentException("listener already registered");
                }
                mProximityListeners.put(listener, proxy);
                if (mProximityListeners.size() == 1) {
                    registerProximityActiveListenerNative(mPtr);
                }
            }
        }

        @Override
        public void removeProximityActiveListener(@NonNull ProximityActiveListener listener) {
            Objects.requireNonNull(listener, "listener must not be null");
            synchronized (mLock) {
                ProximityListenerProxy proxy = mProximityListeners.remove(listener);
                if (proxy == null) {
                    throw new IllegalArgumentException(
                            "listener was not registered with sensor service");
                }
                if (mProximityListeners.isEmpty()) {
                    unregisterProximityActiveListenerNative(mPtr);
                }
            }
        }
    }

    private static class ProximityListenerProxy implements ProximityActiveListener {
        private final Executor mExecutor;
        private final ProximityActiveListener mListener;

        ProximityListenerProxy(Executor executor, ProximityActiveListener listener) {
            mExecutor = executor;
            mListener = listener;
        }

        @Override
        public void onProximityActive(boolean isActive) {
            mExecutor.execute(() -> mListener.onProximityActive(isActive));
        }
    }

    private class ProximityListenerDelegate implements ProximityActiveListener {
        @Override
        public void onProximityActive(boolean isActive) {
            final ProximityListenerProxy[] listeners;
            // We can't call out while holding the lock because clients might be calling into us
            // while holding their own  locks (e.g. when registering / unregistering their
            // listeners).This would break lock ordering and create deadlocks. Instead, we need to
            // copy the listeners out and then only invoke them once we've dropped the lock.
            synchronized (mLock) {
                listeners = mProximityListeners.values().toArray(new ProximityListenerProxy[0]);
            }
            for (ProximityListenerProxy listener : listeners) {
                listener.onProximityActive(isActive);
            }
        }
    }
}

最后的代码就是Core 提供给我们使用的 API 了,这里就不在详细列出。

其实在 Android 中 还可以直接调用 一个驱动,当然这针对的是比较简单的子系统,这些系统并没有存在硬件抽象层,也就是说,实现硬件抽象的功能部分不在单独的代码中。例如 由JNi 代码直接调用的驱动程序的设备节点或者使用SYS 文件系统。

文章摘自:

android底层接口可驱动开发技术详解资料

锐单商城拥有海量元器件数据手册IC替代型号,打造电子元器件IC百科大全!

相关文章