Sensors are often used in daily life, such as stair lights in buildings, street lights on roads and so on. So what is the role of sensors in mobile phones in particular? Android phones provide acceleration sensors, magnetic fields, directions, gyroscopes, light, pressure, temperature and other sensors. In Android system. The code distribution information of the sensor is as follows:
1) The Java part of the sensor system, and the implementation file is sensor * java.
Code path: frameworks/base/include/core/java/android/hardware
2) JNI part of sensor system, which demonstrates Android hardware. Sensor. Intrinsic support for the manager class.
Code path: frameworks/base/core/jni/android_hardware_SensorManager.cpp.
3) The HAL layer of sensor system demonstrates that the hardware abstraction layer of sensor system needs specific implementation.
Header file path: Hardware / libhardware / include / hardware / sensor h
4) Driving layer
Code path: kernel/driver/hwmon/$(PROJECT)/sensor
1. Sensor code of HAL layer
1) Android files mk
The code of HAL layer is in c/cpp format, and the general saving path is hardware/$(PROJECT)/sensor / Among them, the file Android The implementation code of MK is as follows;
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: = adapter file
LOCAL_MODULE := sensors.$(PROJECT)
include $(BUILD_SHARED_LIBRARY)
Note LOCAL_MODULE assignment. The module names here are pre-defined. For details, please refer to hardware / libhardware / hardware c
Here, we can see the loading order. When loading sensors, check whether these so exist once, and then load them to the corresponding adapter.
2) Filled structure
In HAL layer, special attention should be paid to the following filling structures.
(1) The code that defines the sensor module is as follows:
struct sensor_module_t {
struct hw_module_t common;
int (*get_sensors_list) (struct sensors_module_t *module, struct sensor_t const**list);
};
Where, get_sensors_list() is used to represent the list of sensors.
(2) sensor_t represents the description of a sensor, and the specific code is as follows:
struct sensor_t {
const char* name ; / / sensor name
const char* vendor ; / / vendor of sensor
int version; / / sensor version
int handle ; / / handle of the sensor
int type ; / / sensor type
float maxRange; / / maximum range of sensor
float resolution; / / resolution of the sensor
float power; / / the energy consumption of the sensor is mA
void * reserved[9];
}
(3) The structure and consortium are defined, and the specific codes are as follows:
typedef struct {
int sensor; / / sensor flag
unio {
sensors_vec_t vector; / / x,y,z} vector
sensors_vec_t orientation; / / direction key, unit: angle
sensors_vec_t acceleration; / / acceleration value, unit: m/s2
sensors_vec_t magnetic ; / / magnetic vector, unit: ut
float temperature; / / temperature, unit. c
float distance; / / distance in cm
float light; / / brightness of light, in lux
}
int64_t time; //ns
uint32_t reserved;
} sensors_data_t;
3) Adaptation layer function interface
In the HAL layer, you need to pay attention to the following function.
static int a_device_open(const struct hw_module_t* module,
const char* name,
struct hw_device_t** device)
Special attention should be paid to the following assignment:
if (! strcmp(name,SENSORS_HARDWARE_CONTROL)) {/ / command path
···
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)) {/ / data path
···
dev->device.common.close=dev_data_close;
dev->device.data_open=data_open;
dev->device.data_close=data_close;
dev->device.poll=poll;
```
}
In the function, you can know according to the name that JNI should use the poll method to obtain data, that is, the tape provided in the driver should implement file_operation.
Note: the value of the Sensor register obtained in the driver code is not necessarily the value we actually report to the application. For example, g-sensor, it should not be greater than 10 in all directions. It must be noted that other factors should also be considered.
3) Summary of Sensor programming process
The process of Sensor programming is as follows:
(1) The process of Sensor programming is as follows:
The SENSOR_SERVICE returns a Sensormanager object.
sensormanager = (SensoerManager) getSystemSeriver (SENSOR_SERVICE);
(2) Get the corresponding Sensor type object through the SensorManager object.
sensorObject= sensormanager.getDefaultSensor(sensor Type);
(3) Declare a SensorEventListener object to listen for Sensor events and overload the onSensorChanged method.
SensorEventListener sensorListener = new SensorEventListener() {};
(4) Register the corresponding SensorService
sensormanager.registerListener(sensorListener, sensorobject,Sensor TYPE);
(5) Destroy the corresponding SensorService
sensormanager.unregisterListener(sensorListener,sensorObject);
The SensorListener interface here is the core of the whole sensor application. It includes the following two necessary methods.
- onSensorChanged(int sensor,float values[]); This method is called when the sensor changes and is only called on sensors monitored by this application. This method contains the following two parameters:
An integer indicating the changed sensor.
An array of floating point numbers representing the sensor data itself.
- onAccuracyChanged(int sensor,int accuracy); This function is called when the exact value of the sensor changes. This method contains two integers, one represents the sensor and the other represents the exact value of the sensor.
2. Analyze the connection between Sensor source code API layer and hardware platform
Next, let's take the gravity Sensor as an example to see how the gravity Sensor interacts with applications and application framework.
1) First, in the file platform / hardware / libardware / include / sensors H defines the operation of the gravity sensor on the driver, and the code is as follows:
/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) File framework / JNI / onload CPP is used to load the access program of the driver. The specific code is as follows:
/frameworks/base/services/core/jni/onload.cpp
int register_android_server_SerialService(JNIEnv* env);
(3) File framework / JNI / COM_ androidserver_ SensorService. CPP is used to provide an interface to the Application Framework. The specific codes are as follows:
/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 <android-base/properties.h> #include <android_runtime/AndroidRuntime.h> #include <core_jni_helpers.h> #include <cutils/properties.h> #include <jni.h> #include <sensorservice/SensorService.h> #include <utils/Log.h> #include <utils/misc.h> #include <mutex> #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<SensorService> mService; class ProximityActiveListenerDelegate : public SensorService::ProximityActiveListener { public: ProximityActiveListenerDelegate(JNIEnv* env, jobject listener); ~ProximityActiveListenerDelegate(); void onProximityActive(bool isActive) override; private: jobject mListener; }; sp<ProximityActiveListenerDelegate> mProximityActiveListenerDelegate; }; NativeSensorService::NativeSensorService(JNIEnv* env, jobject listener) : mProximityActiveListenerDelegate(new ProximityActiveListenerDelegate(env, listener)) { if (base::GetBoolProperty("system_init.startsensorservice", true)) { sp<IServiceManager> 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<jboolean>(isActive)); } static jlong startSensorServiceNative(JNIEnv* env, jclass, jobject listener) { NativeSensorService* service = new NativeSensorService(env, listener); return reinterpret_cast<jlong>(service); } static void registerProximityActiveListenerNative(JNIEnv* env, jclass, jlong ptr) { auto* service = reinterpret_cast<NativeSensorService*>(ptr); service->registerProximityActiveListener(); } static void unregisterProximityActiveListenerNative(JNIEnv* env, jclass, jlong ptr) { auto* service = reinterpret_cast<NativeSensorService*>(ptr); service->unregisterProximityActiveListener(); } static const JNINativeMethod methods[] = { { "startSensorServiceNative", "(L" PROXIMITY_ACTIVE_CLASS ";)J", reinterpret_cast<void*>(startSensorServiceNative) }, { "registerProximityActiveListenerNative", "(J)V", reinterpret_cast<void*>(registerProximityActiveListenerNative) }, { "unregisterProximityActiveListenerNative", "(J)V", reinterpret_cast<void*>(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
so far, the underlying functions in the file system have been completed. It can be seen that for the underlying class library, the bridge between Android API and hardware device driver can be established through HAL. For different hardware platforms, it is necessary to write the implementation of the above functions, and control the hardware behavior through the driver in the Android kernel. For the upper layer, it can be seen as providing an access interface for the top-level Java implementation of Android API. Because the file is a *. Compiled into the system so library file, which is the same as loading a *. For the system in DK so and its similarity.
(4) Listen to the physical data of the Sensor. Next, see how the Application Framework layer listens to the physical data of the Sensor. At this time, you can use system Load ("*. So") to get access to a library and use the functions in it to do the operations we want. In order to facilitate the operation of programmers, Google uses the Java language to provide a convenient access Application Framework. They encapsulate the drivers or other details of the underlying C/C + + implementation, which is actually the prototype of the API.
Now go back to the Android API layer and the file/ frameworks/base/services/core/java/com/android/server/sensors/SensorService.java The implementation code is as follows:
/* * 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; /* Class for managing sensor devices Customer registration is required to activate the sensor, and the sensor event itself does not play this service Instead, a file descriptor is provided to each client */ 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<ProximityActiveListener, ProximityListenerProxy> 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); } } } }
The final code is the API provided by the Core for us to use, which is not listed in detail here.
In fact, a driver can also be called directly in Android. Of course, this is for relatively simple subsystems. These systems do not have a hardware abstraction layer, that is, the functional part of realizing hardware abstraction is not in a separate code. For example, the device node of the driver directly called by JNi code or using SYS file system.
Article from:
Detailed information of android underlying interface driveable development technology