Analysis of Android Sensor Framework

Keywords: Java Android Unix Linux

The original phase heart rate sensor is taken as an example for analysis.

The original heart rate sensor drives pixart_hc_driver.c. It mainly collects register data into the structure of _ppg_mems_data, and then reports the event through the input subsystem.

input_report_abs(ofndata.pah8001_input_dev, ABS_X,
                     *(uint32_t
                       *) (_ppg_mems_data
                           [_write_index].HRD_Data));
            input_report_abs(ofndata.pah8001_input_dev, ABS_Y,
                     *(uint32_t
                       *) (_ppg_mems_data
                           [_write_index].HRD_Data +
                           4));
            input_report_abs(ofndata.pah8001_input_dev, ABS_Z,
                     *(uint32_t
                       *) (_ppg_mems_data
                           [_write_index].HRD_Data +
                           8));
            input_sync(ofndata.pah8001_input_dev);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

Finally, all reported events will be written into the device files of the sensor, and the reported events can be obtained by monitoring the device files.  
The specific hal layer implementation is implemented by the manufacturer itself, while the hal layer code of the original heart rate sensor is implemented in HerateSensor Pixart. cpp. The main function of this layer is to read the events in the device file, that is, 13 data in the structure of _ppg_mems_data. The synthesis of heart rate data consists of these 13 data and three data of gsensor. So the gsensor sensor is also opened and the data of three gsensors are obtained. A series of methods are implemented for the upper layer to call.
First, a sensor type is defined.

static sensor_t sSensor = {
        "Heart rate sensor",
        "PixArt",
        1,
        SENSORS_PIXART_HEART_RATE_HANDLE,
        SENSOR_TYPE_HEART_RATE,
        1100.0f,
        0.005f,
        0.005f,
        10000,
        { }
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

Then we define some global variables and open the device file to return fd:

HeartRateSensorPixArt::HeartRateSensorPixArt()
    : SensorBase(PIXART_DEVICE_PATH, NULL),
      mExit(false),
      gsensor_fd(-1),
      mExist(false),
      mEnabled(false),
      mDelay(-1),
      mMainReadFd(-1),
      mMainWriteFd(-1),
      mWorkerReadFd(-1),
      mWorkerWriteFd(-1),
      mStartThread(false),
      mHeartRate(-1),
      mHeartRateStatus(0),
      mStatusChanged(false),
      mTouchStatus(false),
      mGradeChanged(false),
      mSensorName("PixArt Heart Rate"),
      mAlgHeartRatePixArt(NULL),
      mSensorListener(NULL)
{
    open_device();
    if (dev_fd >= 0) {
        mExist = initialize();
    }

    if (!mExist)
        LOGI("NO PixArt Heart Rate sensor!");
    else
        LOGI("PixArt Heart Rate sensor initialize done.");
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
A pipeline is initialized for data transmission, and the synthetic heart rate data is obtained and transmitted to the pipeline.
        if (heartRate >= 0)
            hs->mHeartRate = heartRate;

        if (hs->mStatusChanged || heartRateChange) {
            char msg = 'h';
            retval = write(hs->mWorkerWriteFd, &msg, 1);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

There is also a function connectToSensorService(), which implements the registration of sensors on the Senor EventListener. Only by registering this interface can the thread be started.

void HeartRateSensorPixArt::connectToSensorService()
{
    int retval = 0;
    mSensorListener = new SensorListener();
    if ((mSensorListener != NULL) && mSensorListener.get()) {

        retval = mSensorListener->initialize();
        if (retval != NO_ERROR) {
            mSensorListener.clear();
            mSensorListener = NULL;
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

Next, a new one from the upper Sensor_mpl.cpp

HeartRateSensorPixArt Object gets the method inside.
 if (!strcmp(gId, SENSORS_HARDWARE_POLL_FOR_IWDS)) {
        mHeartRateSensorPixArt = new HeartRateSensorPixArt();
        if (!mHeartRateSensorPixArt->isExist()) {
            delete mHeartRateSensorPixArt;
            mHeartRateSensorPixArt = NULL;
        } else {
            sensorsForIwds += mHeartRateSensorPixArt->populateSensorList(&sSensorListForIwds[sensorsForIwds]);
        }
    } else {
        mHeartRateSensorPixArt = NULL;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

Get the fd of the read data at the other end of the pipeline by mHeartRateSensorPixArt - > getFd () method, and finally open the pipeline to read the data.

else if (fd == pixart_heart_rate) {
                    if (mHeartRateSensorPixArt != NULL) {
                        mPollFds[i].revents = 0;
                        char buf[8];
                        int ret = read(mPollFds[i].fd, buf, sizeof(buf));
                        if (ret == -1) {
                            ALOGE("poll pixart heart pipe fd error!%d %c", ret,
                                    buf[0]);
                        } else {
                            nb = mHeartRateSensorPixArt->readEvents(data, count);
                            if (nb > 0) {
                                count -= nb;
                                nbEvents += nb;
                                data += nb;
                            }
                        }
                    }
                }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

open_sensor contains a series of methods of operation, most of which are implemented in HerateSensorPixart.cpp.

static int open_sensors(const struct hw_module_t* module, const char* id,
                        struct hw_device_t** device)
{
    FUNC_LOG;
    int status = -EINVAL;

    gId = strdup(id);

    sensors_poll_context_t *dev = new sensors_poll_context_t();

    memset(&dev->device, 0, sizeof(sensors_poll_device_t));

    dev->device.common.tag = HARDWARE_DEVICE_TAG;
    dev->device.common.version  = 0;
    dev->device.common.module   = const_cast<hw_module_t*>(module);
    dev->device.common.close    = poll__close;
    dev->device.activate        = poll__activate;
    dev->device.setDelay        = poll__setDelay;
    dev->device.poll            = poll__poll;
    dev->device.calibrate  = poll__calibrate;
    dev->device.setRightHand        = poll__setRightHand;

    *device = &dev->device.common;
    status = 0;

    return status;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

Next is the implementation of JNI layer. The code is implemented in SenorDevice. cpp, which mainly implements the access of dynamic link libraries, such as opening dynamic link libraries and converting functions.

SensorDevice::SensorDevice()
    :  mSensorDevice(0),
       mSensorModule(0)
{
    status_t err = hw_get_module(SENSORS_HARDWARE_MODULE_ID,
            (hw_module_t const**)&mSensorModule);

    ALOGE_IF(err, "couldn't load %s module (%s)",
            SENSORS_HARDWARE_MODULE_ID, strerror(-err));

    if (mSensorModule) {
        err = sensors_open(&mSensorModule->common, &mSensorDevice);

        ALOGE_IF(err, "couldn't open device for module %s (%s)",
                SENSORS_HARDWARE_MODULE_ID, strerror(-err));

        if (mSensorDevice) {
            sensor_t const* list;
            ssize_t count = mSensorModule->get_sensors_list(mSensorModule, &list);
            mActivationCount.setCapacity(count);
            Info model;
            for (size_t i=0 ; i<size_t(count) ; i++) {
                mActivationCount.add(list[i].handle, model);
                mSensorDevice->activate(mSensorDevice, list[i].handle, 0);
            }
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

The key to getting HAL layer calls through the interface hw_get_module is the unique identifier SENSORS_HARDWARE_MODULE_ID. Finally, the structure of mSensorDevice is obtained, which contains all functions in HAL layer, including the ability to implement sensors.

Next is the analysis of the Framwork layer.


Here we divide it into client and server. The server mainly reads data from HAL and writes data into pipeline. The client mainly reads data from pipeline.  
Client Main Classes
SensorManager.Java 
Starting with Android 4.1, SensorManager is defined as an abstract class, and some main methods are defined. Classes are mainly classes directly used by the application layer, which provide interfaces to the application layer.
SystemSensorManager.java 
Inherited from Sensor Manager, the client-side message processing entity, the application obtains sensor data by acquiring its instance and registering the listening interface.
sensorEventListener interface
Interfaces for registration monitoring
sensorThread 
Is an internal class of SystemSensor Manager, which opens a new thread responsible for reading and reading sensor data. Threads are started only when the sensorEventListener interface is registered.
android_hardware_SensorManager.cpp 
JNI interface responsible for communication with java layer
SensorManager.cpp 
sensor's client in the Native layer is responsible for communication with SensorService.cpp.
SenorEventQueue.cpp 
Message queue

Server main classes
SensorService.cpp 
Server-side Data Processing Center
SensorEventConnection 
Inheritance from BnSensorEventConnection implements some methods of interface ISensorEventConnection. ISensorEventConnection saves a pointer in the ensorEventQueue, pointing to the ensorEventConnection object created by invoking the service interface.
Bittube.cpp 
In this class, a pipeline is created to read and write data between the server and the client.
SensorDevice 
Responsible for reading data with HAL

The client mainly implements:
APK monitoring
Get the sensor service object

mService = (SensorServiceManager) serviceClient.getServiceManagerContext();
    private void registerSensors() {
        /* Getting individual Sensor s through getDefaultSensor */
        mHeartRateSensor = mService.getDefaultSensor(Sensor.TYPE_HEART_RATE);
        if (mHeartRateSensor != null) {
            mService.registerListener(mListener, mHeartRateSensor, 0);
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

Obtaining Heart Rate Data by Monitoring Data Changes

 private SensorEventListener mListener = new SensorEventListener() {

        /*
         * Monitor Sensor data changes
         */
        @Override
        public void onSensorChanged(SensorEvent event) {
            if (event.sensorType == Sensor.TYPE_HEART_RATE) {
                Log.d(SUB_TAG, "Update Heart Rate : " + event.values[0]);
                mHeartRateData = event.values[0];
            }
            mHeartRateText.setText("Heart Rate: " + mHeartRateData);
        }
//Initialize System Sensor Manager
    public SystemSensorManager(Context context,Looper mainLooper) {
        mMainLooper = mainLooper;       
              mContext = context;

        synchronized(sListeners) {
            if (!sSensorModuleInitialized) {
                sSensorModuleInitialized = true;

                nativeClassInit();

                // initialize the sensor list
                sensors_module_init();
                final ArrayList<Sensor> fullList = sFullSensorsList;
                int i = 0;
                do {
                    Sensor sensor = new Sensor();
                    i = sensors_module_get_next_sensor(sensor, i);

                    if (i>=0) {
                        //Log.d(TAG, "found sensor: " + sensor.getName() +
                        //        ", handle=" + sensor.getHandle());
                        fullList.add(sensor);
                        sHandleToSensor.append(sensor.getHandle(), sensor);
                    }
                } while (i>0);

                sPool = new SensorEventPool( sFullSensorsList.size()*2 );
                sSensorThread = new SensorThread();
            }
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

When the system boots up, an instance of System Sensor Manager is created. In its constructor, four main things are done:
Initialize JNI
Initialize by calling the JNI function nativeClassInit()
Initialize Sensor List
Initialize the Sensor module by calling the JNI function sensors_module_init. An instance of Sensor Manager in the native layer is created.  
Get the Sensor list
Call the JNI function sensors_module_get_next_sensor() to get the Sensor and it exists in the sHandleToSensor list
Constructing SensorThread class
Construct class functions for threads, and do not start threads. Threads are started only when applications are registered.
Start SensorThread thread to read data in message queue

protected boolean registerListenerImpl(SensorEventListener listener, Sensor sensor,
            int delay, Handler handler) {

        synchronized (sListeners) {
            ListenerDelegate l = null;
            for (ListenerDelegate i : sListeners) {
                if (i.getListener() == listener) {
                    l = i;
                }
            }
            …….
            // if we don't find it, add it to the list
            if (l == null) {
                l = new ListenerDelegate(listener, sensor, handler);
                sListeners.add(l);
                  ……
                    if (sSensorThread.startLocked()) {
                        if (!enableSensorLocked(sensor, delay)) {
                          …….
                        }
                 ……
            } else if (!l.hasSensor(sensor)) {
                l.addSensor(sensor);
                if (!enableSensorLocked(sensor, delay)) {
                    ……
                }
            }
        }
        return result;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

When an application calls the registerListenerImpl() method to register the listener, it calls SensorThread.startLoacked() to start the thread only once, and calls the enableSensorLocked() interface to enable the specified sensor and set the sampling time.

SensorThreadRunnable Realized Runnable Interface, in SensorThread Class is started
  boolean startLocked() {
            try {
                if (mThread == null) {
                    SensorThreadRunnable runnable = new SensorThreadRunnable();
                    Thread thread = new Thread(runnable, SensorThread.class.getName());
                    thread.start();
                    synchronized (runnable) {  //Queue creation success, thread synchronization
                        while (mSensorsReady == false) {
                            runnable.wait();
                        }
                    }

        }
private class SensorThreadRunnable implements Runnable {
            SensorThreadRunnable() {
            }
            private boolean open() {
                sQueue = sensors_create_queue();
                return true;
            }
            public void run() {
                …….
                if (!open()) {
                    return;
                }
                synchronized (this) {
                    mSensorsReady = true;
                    this.notify();
                }
                while (true) {
                    final int sensor = sensors_data_poll(sQueue, values, status, timestamp);
                    …….
            }
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

The JNI function sensors_create_queue() is called in the open function to create the message queue, and then SensorManager. createEventQueue() is called to create the message queue.  
After starting a new thread in the startLocked function, a while waiting (mSensorsReady == false) is done. Only when mSensorsReady equals true, can the enableSensorLocked() function be executed to enable the sensor. The mSensorsReady variable is true only after the open() call creates the message queue successfully, so we think that the order of the three function calls is as follows:
Call the open function to create a message queue
Call the enableSensorLocked() function to enable sensor
Call sensors_data_poll to read data from the message queue and read it all the time in the while (true) loop
Let's first analyze the implementation of the server.
Start the SensorService service
In the main function of the System Server process, it is invoked through JNI to ____________
The android_server_SystemServer_init1() method of com_android_server_SystemServer.cpp calls system_init() in system_init.cpp:

extern "C" status_t system_init()
{
    ……
    property_get("system_init.startsensorservice", propBuf, "1");
    if (strcmp(propBuf, "1") == 0) {
        // Start the sensor service
        SensorService::instantiate();
    }
    …..
    return NO_ERROR;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

An example of SensorService is created here.  
SensorService initialization
After the SensorService is created, the SensorService::onFirstRef() method is invoked to complete the initialization.  
Firstly, an instance of Sensor Device is obtained. In its constructor, the initialization of the Sensor module HAL is completed.

SensorDevice::SensorDevice()
    :  mSensorDevice(0),
       mSensorModule(0)
{
    status_t err = hw_get_module(SENSORS_HARDWARE_MODULE_ID,
            (hw_module_t const**)&mSensorModule);

    if (mSensorModule) {
        err = sensors_open(&mSensorModule->common, &mSensorDevice);

        ALOGE_IF(err, "couldn't open device for module %s (%s)",
                SENSORS_HARDWARE_MODULE_ID, strerror(-err));

        if (mSensorDevice) {
            sensor_t const* list;
            ssize_t count = mSensorModule->get_sensors_list(mSensorModule, &list);
            mActivationCount.setCapacity(count);
            Info model;
            for (size_t i=0 ; i<size_t(count) ; i++) {
                mActivationCount.add(list[i].handle, model);
                mSensorDevice->activate(mSensorDevice, list[i].handle, 0);
            }
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

Three main tasks have been done here:
Call the hw_get_modele() method of HAL layer to load the Sensor module so file
Call sensor_open method of sensor.h to open the device
Call sensors_poll_device_t-> activate () to enable the Sensor module

Let's look again at the SensorService::onFirstRef() method:

void SensorService::onFirstRef()
{
    SensorDevice& dev(SensorDevice::getInstance());

    if (dev.initCheck() == NO_ERROR) {
        sensor_t const* list;
        ssize_t count = dev.getSensorList(&list);
        if (count > 0) {
            ……
            for (ssize_t i=0 ; i<count ; i++) {
                registerSensor( new HardwareSensor(list[i]) );
                ……
            }

            // it's safe to instantiate the SensorFusion object here
            // (it wants to be instantiated after h/w sensors have been
            // registered)
            const SensorFusion& fusion(SensorFusion::getInstance());

            if (hasGyro) {
               ……
            }
            ……
            run("SensorService", PRIORITY_URGENT_DISPLAY);
            mInitCheck = NO_ERROR;
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

In this method, four main things are done:
Create SensorDevice instances
Get the Sensor list
Call SensorDevice.getSensorList() to get a list of all sensors in the Sensor module
Register listeners for each sensor

registerSensor( new HardwareSensor(list[i]) );
void SensorService::registerSensor(SensorInterface* s)
{
    sensors_event_t event;
    memset(&event, 0, sizeof(event));

    const Sensor sensor(s->getSensor());
    // Add to Sensor list for client
    mSensorList.add(sensor);
    // add to our handle->SensorInterface mapping
    mSensorMap.add(sensor.getHandle(), s);
    // create an entry in the mLastEventSeen array
    mLastEventSeen.add(sensor.getHandle(), event);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

Hardware Sensor implements the SensorInterface interface.  
Start threads to read data
Calling the run method to start a new thread calls the SensorService::threadLoop() method.  
Read HAL Layer Data in New Threads
SensorService implements the Thread class, and when the run method is called in onFirstRef, the SensorService::threadLoop() method is called in the new thread.

bool SensorService::threadLoop()
{
    ……
    do {
        count = device.poll(buffer, numEventMax);

        recordLastValue(buffer, count);
        ……

        // send our events to clients...
        const SortedVector< wp<SensorEventConnection> > activeConnections(
                getActiveConnections());
        size_t numConnections = activeConnections.size();
        for (size_t i=0 ; i<numConnections ; i++) {
            sp<SensorEventConnection> connection(
                    activeConnections[i].promote());
            if (connection != 0) {
                connection->sendEvents(buffer, count, scratch);
            }
        }
    } while (count >= 0 || Thread::exitPending());
    return false;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

In the while loop, the HAL layer data is read all the time, and then the Sensor Event Connection - > sendEvents is called to write the data to the pipeline.  
Communication between client and server
Data transmission

Client Server Thread
In the figure, we can see that there are two threads, one is a thread on the server side, which is responsible for continuously reading data from HAL. The other is a thread of the client, which reads data from the message queue.  
Create message queues
Clients can create multiple message queues, and one message queue corresponds to a connection interface to communicate with the server.
Create a connection interface
The bridge between the server and the client. When the server reads the HAL layer data, it scans how many interfaces it has to connect with the client, and then writes data to the pipeline of each interface.
Creating Pipelines
Each connection interface has a corresponding pipeline.  
The above is the design principle of data transmission, but at present the data transmission on Android 4.1 can not fully follow the above understanding. Because in actual use, message queue can only be created, that is to say, there is only one connection interface between client and server, and only one pipeline to transmit data. So how does the form of data transfer from HAL layer to JAVA layer? In fact, the data is transferred from HAL layer to JNI layer in the form of sensors_event_t. Look at the sensor_event_t structure of HAL:

typedef struct sensors_event_t {
    int32_t version;
    int32_t sensor;            //identifier
    int32_t type;             //Sensor type
    int32_t reserved0;
    int64_t timestamp;        //time stamp
    union {
        float           data[16];
        sensors_vec_t   acceleration;   //acceleration
        sensors_vec_t   magnetic;      //Magnetic vector
        sensors_vec_t   orientation;     //direction
        sensors_vec_t   gyro;          //gyroscope
        float           temperature;     //temperature
        float           distance;        //distance
        float           light;           //Illumination
        float           pressure;         //pressure
        float           relative_humidity;  //relative humidity
    };
    uint32_t        reserved1[4];
} sensors_event_t;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

There is an ASensor Event structure corresponding to sensors_event_t in JNI layer.
frameworks/native/include/Android/sensor.h:

typedef struct ASensorEvent {
    int32_t version;
    int32_t sensor;
    int32_t type;
    int32_t reserved0;
    int64_t timestamp;
    union {
        float           data[16];
        ASensorVector   vector;
        ASensorVector   acceleration;
        ASensorVector   magnetic;
        float           temperature;
        float           distance;
        float           light;
        float           pressure;
    };
    int32_t reserved1[4];
} ASensorEvent;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

In the JNI layer, only part of the information in the structure data is transmitted to the JAVA layer:

After the previous introduction, we know the way to realize the client and the implementation of the server, but we do not specifically talk about how the two communicate. In this section, we specifically introduce the communication between the client and the server.  
Inter-process communication, including IBind and pipeline communication, is mainly involved here. The client obtains the remote call from the server through IBind communication, and then transmits sensor data through the pipeline.  
Pipeline is one of the first Unix IPC forms supported by Linux. It has the following characteristics:
Pipeline is half-duplex and data can only flow in one direction; when communication between two parties is needed, two pipes need to be established; they can only be used between parent and child processes or sibling processes (processes with affinity); they can form an independent file system separately: pipes are a file for processes at both ends of the pipeline, but they are not ordinary files, and they do not belong to a certain category. A file system, rather than a self-supporting portal, constitutes a single file system and only exists in memory. Reading and writing of data: The content written by a process to the pipeline is read by the process at the other end of the pipeline. Written content is added at the end of the pipeline buffer each time, and data is read out from the head of the buffer each time. Both ends of the pipeline can be described by the descriptors fd[0] and fd[1]. It should be noted that both ends of the pipeline are fixed tasks. That is, one end can only be used for reading, expressed by the descriptor fd[0], called the pipeline reader; the other end can only be used for writing, expressed by the descriptor fd[1], called the pipeline writer. If you attempt to read data from the pipeline reader, or write data to the pipeline reader, errors will occur. I/O functions of general files can be used for pipelines, such as close, read, write, and so on.  
Server side
native layer implements the core implementation of sensor service. The main process of sensor service is implemented in the sensor service class. The following focuses on the analysis of the process of this class.

class SensorService :
        public BinderService<SensorService>,
        public BnSensorServer,
        protected Thread
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

Look at the sensorService inherited classes:
Inheriting BinderService, a template class, is added to the system service for Ibinder inter-process communication.

template<typename SERVICE>
class BinderService
{
public:
    static status_t publish() {
        sp<IServiceManager> sm(defaultServiceManager());
        return sm->addService(String16(SERVICE::getServiceName()), new SERVICE());
    }

    static void publishAndJoinThreadPool() {
        sp<ProcessState> proc(ProcessState::self());
        sp<IServiceManager> sm(defaultServiceManager());
        sm->addService(String16(SERVICE::getServiceName()), new SERVICE());
        ProcessState::self()->startThreadPool();
        IPCThreadState::self()->joinThreadPool();
    }

    static void instantiate() { publish(); }
};
}; // namespace android
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

In the previous introduction, an instance of SensorService service was created by calling SensorService::instantiate() in System_init.cpp, which calls the instantiate() method above, and then publish(), in which we saw an instance of new SensorService and called defaultServiceManager::addService() to add Sensor service to system service management. The client can get an instance of the Sensor service through defaultServiceManager:getService().

Inheritance of BnSensor Server is the abstract interface class of sensor service provided for client invocation:

class Sensor;
class ISensorEventConnection;

class ISensorServer : public IInterface
{
public:
    DECLARE_META_INTERFACE(SensorServer);
    //Get Sensor List
virtual Vector<Sensor> getSensorList() = 0;
//Create a connection interface, which is an abstract interface provided to the client and must be implemented when the server is instantiated
    virtual sp<ISensorEventConnection> createSensorEventConnection() = 0;
};
class BnSensorServer : public BnInterface<ISensorServer>
{
public:
    //Communication interface for transmitting packaged data is implemented in BnSensor Server
    virtual status_t    onTransact( uint32_t code,
                                    const Parcel& data,
                                    Parcel* reply,
                                    uint32_t flags = 0);
};
}; // namespace android
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

ISensorServer interface provides two abstract methods for client invocation, the key is
createSensorEventConnection() method, which is implemented on the server side, called on the client side, and returns an instance of SensorEventConnection to create a connection. After the client gets the instance of SensorEventConnection, it can communicate with the sensor. It is only used as a communication interface. It is not used to transmit Sensor data, because the amount of Sensor data is comparatively large, IB. IND is difficult to implement. Pipeline is the real implementation of Sensor data transmission. In creating an instance of Sensor Event Connection, a BitTube object is created, in which pipes are created for communication between client and server.  
Client side
The client creates the message queue mainly in SensorManager.cpp

class ISensorEventConnection;
class Sensor;
class Looper;

// ----------------------------------------------------------------------------

class SensorEventQueue : public ASensorEventQueue, public RefBase
{
public:
            SensorEventQueue(const sp<ISensorEventConnection>& connection);
    virtual ~SensorEventQueue();
    virtual void onFirstRef();
    //Getting Pipeline Handles
    int getFd() const;
    //Write data to the pipeline
    static ssize_t write(const sp<BitTube>& tube,
            ASensorEvent const* events, size_t numEvents);
    //Read the data to the pipeline
    ssize_t read(ASensorEvent* events, size_t numEvents);

    status_t waitForEvent() const;
    status_t wake() const;
    //Enabling Sensor Sensor Sensor
    status_t enableSensor(Sensor const* sensor) const;
    status_t disableSensor(Sensor const* sensor) const;
    status_t setEventRate(Sensor const* sensor, nsecs_t ns) const;

    // these are here only to support SensorManager.java
    status_t enableSensor(int32_t handle, int32_t us) const;
    status_t disableSensor(int32_t handle) const;

private:
sp<Looper> getLooper() const;
//Connection interface, created in ensorService
sp<ISensorEventConnection> mSensorEventConnection;
//Pipe pointer
    sp<BitTube> mSensorChannel;
    mutable Mutex mLock;
    mutable sp<Looper> mLooper;
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

As a message queue, the SensorEventQueue class plays an important role. When creating its instance, an instance of SensorEventConnection is passed in. SensorEventConnection inherits from ISensorEventConnection. SensorEventConnection is actually created by the client calling the createSensorEventConnection() method of SensorService. It is a bridge between the client and the server through which the task can be accomplished:
Get the handle of the pipe
Read and write data to the pipeline
Notify the server to enable Sensor
Process analysis
Client obtains SensorService service instance
When the client is initialized, that is, in the constructor of System Sensor Manager, it creates an instance of Sensor Manager in the native layer through JNI call, and then invokes the Sensor Manager:: assertStateLocked () method to do some initialization actions.

status_t SensorManager::assertStateLocked() const {
    if (mSensorServer == NULL) {
        // try for one second
        const String16 name("sensorservice");
        ……
            status_t err = getService(name, &mSensorServer);
        ……
        mSensors = mSensorServer->getSensorList();
        size_t count = mSensors.size();
        mSensorList = (Sensor const**)malloc(count * sizeof(Sensor*));
        for (size_t i=0 ; i<count ; i++) {
            mSensorList[i] = mSensors.array() + i;
        }
    }
    return NO_ERROR;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

As we mentioned earlier, when SensorService was created, defaultServiceManager:getService() was called to add services to system service management. Now we call defaultService Manager:: geService () to get an instance of the SensorService service. By communicating with IBind, you can get the Sensor list, so when the client initializes, you do two things:
n Gets SensorService instance references
n Gets Sensor Sensor Sensor List
Create message queues
When the client registers the listener for the first time, it needs to create a message queue. That is to say, in the current implementation of android, only one message queue is created. There is a pipeline in a message queue for the server to disconnect from the client to transmit Sensor data.  
The createEventQueue method in SonsorManager.cpp creates a message queue:

sp<SensorEventQueue> SensorManager::createEventQueue()
{
    sp<SensorEventQueue> queue;
    Mutex::Autolock _l(mLock);
while (assertStateLocked() == NO_ERROR) {
    //Create a connection interface
        sp<ISensorEventConnection> connection =
                mSensorServer->createSensorEventConnection();
        if (connection == NULL) {
            // SensorService just died.
            LOGE("createEventQueue: connection is NULL. SensorService died.");
            continue;
        }
//Create message queues
        queue = new SensorEventQueue(connection);
        break;
    }
    return queue;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

The client and server create a Sensor Event Connection connection interface, and a message queue contains a connection interface.  
Create a connection interface:

sp<ISensorEventConnection> SensorService::createSensorEventConnection()
{
    sp<SensorEventConnection> result(new SensorEventConnection(this));
    return result;
}
SensorService::SensorEventConnection::SensorEventConnection(
        const sp<SensorService>& service)
    : mService(service), mChannel(new BitTube ())
{
}
//The key is BitTube, which creates pipes in constructors:
BitTube::BitTube()
    : mSendFd(-1), mReceiveFd(-1)
{
    int sockets[2];
    if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets) == 0) {
        int size = SOCKET_BUFFER_SIZE;
        setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
        setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
        setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
        setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
        fcntl(sockets[0], F_SETFL, O_NONBLOCK);
        fcntl(sockets[1], F_SETFL, O_NONBLOCK);
        mReceiveFd = sockets[0];
        mSendFd = sockets[1];
    } else {
        mReceiveFd = -errno;
        ALOGE("BitTube: pipe creation failed (%s)", strerror(-mReceiveFd));
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

Among them: fds[0] is the corresponding mReceive Fd, which is the reading end of the pipeline, the reading end of the sensor data, and the corresponding access of the client process. fds[1] corresponds to mSendFd, which is the writing end of the pipeline and the sensor data writing end, which is the access end of the sensor's service process. Pipeline is created by pipe(fds), and operation pipes are set by fcntl. The operation mode at both ends of the channel is O_NONBLOCK, non-blocking IO, read or write calls Return-1 and EAGAIN errors.  
Summarize the message queue:
The first time a client registers a listener, it needs to create a message queue. The client creates a SensorThread thread to read data from the message queue.  
SensorEventQueue has a reference to a SensorEventConnection instance, and SensorEventConnection has a reference to a BitTube instance.  
Enabling Sensor
After the client creates the connection interface Sensor Event Connection, it can call its method to enable the Sensor sensor:

status_t SensorService::SensorEventConnection::enableDisable(
        int handle, bool enabled)
{
    status_t err;
    if (enabled) {
        err = mService->enable(this, handle);
    } else {
        err = mService->disable(this, handle);
    }
    return err;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

Handle corresponds to the handle of the Sensor sensor.
The server writes data to the pipeline

bool SensorService::threadLoop()
{
    ……
    do {
        count = device.poll(buffer, numEventMax);

        recordLastValue(buffer, count);
        ……

        // send our events to clients...
        const SortedVector< wp<SensorEventConnection> > activeConnections(
                getActiveConnections());
        size_t numConnections = activeConnections.size();
        for (size_t i=0 ; i<numConnections ; i++) {
            sp<SensorEventConnection> connection(
                    activeConnections[i].promote());
            if (connection != 0) {
                connection->sendEvents(buffer, count, scratch);
            }
        }
    } while (count >= 0 || Thread::exitPending());
    return false;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

As mentioned earlier, in the Sensor Service, a thread is created to continuously read Sensor data from the HAL layer, which is in the threadLoop method. The key is a for loop that scans how many client connection interfaces there are, and then writes data to pipes that do not have each connection.

status_t SensorService::SensorEventConnection::sendEvents(
        sensors_event_t const* buffer, size_t numEvents,
        sensors_event_t* scratch)
{
    // filter out events not for this connection
    size_t count = 0;
    if (scratch) {
      ……
    }
    ……
    if (count == 0)
        return 0;

    ssize_t size = mChannel->write(scratch, count*sizeof(sensors_event_t));
    ……
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

BitTube::write():

ssize_t BitTube::write(void const* vaddr, size_t size)
{
    ssize_t err, len;
    do {
        len = ::send(mSendFd, vaddr, size, MSG_DONTWAIT | MSG_NOSIGNAL);
        err = len < 0 ? errno : 0;
    } while (err == EINTR);
    return err == 0 ? len : -err;

} }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

At this point, the server completes writing data to the pipeline's writing end.  
Client reads pipeline data

ssize_t SensorEventQueue::read(ASensorEvent* events, size_t numEvents)
{
    return BitTube::recvObjects(mSensorChannel, events, numEvents);
}
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

Called to BitTube::read ():

static ssize_t recvObjects(const sp<BitTube>& tube,
            T* events, size_t count) {
        return recvObjects(tube, events, count, sizeof(T));
    }
ssize_t BitTube::recvObjects(const sp<BitTube>& tube,
        void* events, size_t count, size_t objSize)
{
    ssize_t numObjects = 0;
    for (size_t i=0 ; i<count ; i++) {
        char* vaddr = reinterpret_cast<char*>(events) + objSize * i;
        ssize_t size = tube->read(vaddr, objSize);
        if (size < 0) {
            // error occurred
            return size;
        } else if (size == 0) {
            // no more messages
            break;
        }
        numObjects++;
    }
    return numObjects;
}

ssize_t BitTube::read(void* vaddr, size_t size)
{
    ssize_t err, len;
    do {
        len = ::recv(mReceiveFd, vaddr, size, MSG_DONTWAIT);
        err = len < 0 ? errno : 0;
    } while (err == EINTR);
    if (err == EAGAIN || err == EWOULDBLOCK) {
        return 0;
    }
    return err == 0 ? len : -err;
}

Posted by luckybob on Tue, 26 Mar 2019 02:54:29 -0700