Android中多个Sensor客户端注册“First flush Pending”问题

        引言:近期在项目上遇到一个“FLP”问题。 本文借此问题来分析:同一个sensor被多个App监听SensorEventListener事件时,app client被"First flush Pending"问题;


1. App Java层的常规步骤

private void registerListener() {
	Log.d(TAG, "registerListener");

	mAccel = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
	mGyro = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE_UNCALIBRATED);

	mSensorManager.registerListener(mSensorEventListener, mAccel,
			SENSOR_DELAY_NORMAL, SENSOR_DELAY_NORMAL, mHandler);
	mSensorManager.registerListener(mSensorEventListener, mGyro,
			SENSOR_DELAY_NORMAL, SENSOR_DELAY_NORMAL, mHandler);
}

2. registerListener()函数

        App侧调用的registerListener()接口,将会调用 SensorManager中的相应接口。进而调用SystemSensorManager中的registerListenerImpl()接口。

public boolean registerListener(SensorEventListener listener, Sensor sensor,
		int samplingPeriodUs, int maxReportLatencyUs, Handler handler) {
	int delayUs = getDelay(samplingPeriodUs);
	return registerListenerImpl(listener, sensor, delayUs, handler, maxReportLatencyUs, 0);
}

3. registerListenerImpl()函数

        从代码上看:

        ①. Sensor Events的种类有:REPORTING_MODE_CONTINUOUS、REPORTING_MODE_ON_CHANGE、REPORTING_MODE_ONE_SHOT三种类型;

        ②. 在SystemSersorManager中,最多的Listerner Client数量为128个;

        ③. 获取SensorEventQueue,执行addSensor()操作;

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 < 0) {
		Log.e(TAG, "maxBatchReportLatencyUs and delayUs should be non-negative");
		return false;
	}
	if (mSensorListeners.size() >= MAX_LISTENER_COUNT) {	// MAX_LISTENER_COUNT:128
		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 looper
	synchronized (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();
            // 一个App,将会创建一个新的queue
			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);
		}
	}
}

4. addSensor()函数

        先判断同一个App,是否对同一个sensor进行的注册监听。如果,同一个App之前已经对相同 的Sensor进行了操作,则直接返回;

        如果是一个App的第一次操作,则执行enableSensor()操作;

public boolean addSensor(
		Sensor sensor, int delayUs, int maxBatchReportLatencyUs) {
	// Check if already present.
	int handle = sensor.getHandle();
	if (mActiveSensors.get(handle)) return false;

	// Get ready to receive events before calling enable.
	mActiveSensors.put(handle, true);
	addSensorEvent(sensor);
	if (enableSensor(sensor, delayUs, maxBatchReportLatencyUs) != 0) {
		// Try continuous mode if batching fails.
		if (maxBatchReportLatencyUs == 0
				|| maxBatchReportLatencyUs > 0 && enableSensor(sensor, delayUs, 0) != 0) {
			removeSensor(sensor, false);
			return false;
		}
	}
	return true;
}

5. enableSensor()函数

        enableSensor()调用native的方法:nativeEnableSensor()

private int enableSensor(
		Sensor sensor, int rateUs, int maxBatchReportLatencyUs) {
	if (mNativeSensorEventQueue == 0) throw new NullPointerException();
	if (sensor == null) throw new NullPointerException();
	if (mManager.isSensorInCappedSet(sensor.getType())
			&& rateUs < CAPPED_SAMPLING_PERIOD_US
			&& mManager.mIsPackageDebuggable
			&& !mManager.hasHighSamplingRateSensorsPermission()
			&& Compatibility.isChangeEnabled(CHANGE_ID_SAMPLING_RATE_SENSORS_PERMISSION)) {
		throw new SecurityException("To use the sampling rate of " + rateUs
				+ " microseconds, app needs to declare the normal permission"
				+ " HIGH_SAMPLING_RATE_SENSORS.");
	}
	return nativeEnableSensor(mNativeSensorEventQueue, sensor.getHandle(), rateUs,
			maxBatchReportLatencyUs);
}

6. nativeEnableSensor()函数

         receiver->getSensorEventQueue()返回的是SensorEventQueue,即nativeEnableSensor()调用的是SensorEventQueue中的enableSensor()接口

// file located in: frameworks/base/core/jni/android_hardware_SensorManager.cpp

static jlong nativeInitSensorEventQueue(JNIEnv *env, jclass clazz, jlong sensorManager,
                                        jobject eventQWeak, jobject msgQ, jstring packageName,
                                        jint mode, jstring opPackageName, jstring attributionTag) {
    // native层的SensorManager
    SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
	
	//省略部分代码
	
    // native层的SensorService
    sp<SensorEventQueue> queue(mgr->createEventQueue(clientName, mode, attributionTagName));
    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, msgQ);
	
	//省略部分代码

    sp<Receiver> receiver = new Receiver(queue, messageQueue, eventQWeak);
    receiver->incStrong((void*)nativeInitSensorEventQueue);
    return jlong(receiver.get());
}

static jint nativeEnableSensor(JNIEnv *env, jclass clazz, jlong eventQ, jint handle, jint rate_us,
                               jint maxBatchReportLatency) {
    sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
    return receiver->getSensorEventQueue()->enableSensor(handle, rate_us, maxBatchReportLatency,
                                                         0);
}

static const JNINativeMethod gBaseEventQueueMethods[] = {
        {"nativeInitBaseEventQueue",
         "(JLjava/lang/ref/WeakReference;Landroid/os/MessageQueue;Ljava/lang/String;ILjava/lang/"
         "String;Ljava/lang/String;)J",
         (void *)nativeInitSensorEventQueue},

        {"nativeEnableSensor", "(JIII)I", (void *)nativeEnableSensor},

        {"nativeDisableSensor", "(JI)I", (void *)nativeDisableSensor},

        {"nativeDestroySensorEventQueue", "(J)V", (void *)nativeDestroySensorEventQueue},

        {"nativeFlushSensor", "(J)I", (void *)nativeFlushSensor},

        {"nativeInjectSensorData", "(JI[FIJ)I", (void *)nativeInjectSensorData},
};

7. SensorEventQueue的enableSensor()函数

        从代码上看可知:enable时,会设置一个默认的采样率;

        同时 ,会调用SensorEventConnection中的enableDisable()接口;

// file located in: frameworks/native/libs/sensor/SensorEventQueue.cpp

status_t SensorEventQueue::enableSensor(Sensor const* sensor) const {
    return enableSensor(sensor, SENSOR_DELAY_NORMAL);
}

status_t SensorEventQueue::enableSensor(Sensor const* sensor, int32_t samplingPeriodUs) const {
    return mSensorEventConnection->enableDisable(sensor->getHandle(), true,
                                                 us2ns(samplingPeriodUs), 0, 0);
}

8. SensorEventConnection中的enableDisable()函数

        从代码上看,最终调用了SensorService的enable()接口

status_t SensorService::SensorEventConnection::enableDisable(
        int handle, bool enabled, nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs,
        int reservedFlags)
{
	// 省略部分代码;
    status_t err = mService->enable(this, handle, samplingPeriodNs, maxBatchReportLatencyNs,
                               reservedFlags, mOpPackageName);
        if (err == OK && isSensorCapped) {
            if ((requestedSamplingPeriodNs >= SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS) ||
                !isRateCappedBasedOnPermission()) {
                mMicSamplingPeriodBackup[handle] = requestedSamplingPeriodNs;
            } else {
                mMicSamplingPeriodBackup[handle] = SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS;
            }
        }

    } else {
        err = mService->disable(this, handle);
        mMicSamplingPeriodBackup.erase(handle);
    }
    return err;
}

9.  SensorService的enable()函数

        ①. 一个App会有一个connection;

        ②. 一个类型的Sensor仅有一个SensorRecord;

        . 一个SensorRecord可以对应多个connection,但之后的connnection会被设置为"First flush pending"状态;

// filed located in: frameworks/native/services/sensorservice/SensorService.cpp#

status_t SensorService::enable(const sp<SensorEventConnection>& connection,
        int handle, nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs, int reservedFlags,
        const String16& opPackageName) {
	// 省略部分代码;

    SensorRecord* rec = mActiveSensors.valueFor(handle);
    if (rec == nullptr) {
        rec = new SensorRecord(connection);
        mActiveSensors.add(handle, rec);
		// 省略部分代码;
    } else {
        if (rec->addConnection(connection)) {
			// 省略部分代码;
        }
    }

    if (connection->addSensor(handle)) {
		// 省略部分代码;
    } else {
        ALOGW("sensor %08x already enabled in connection %p (ignoring)",
            handle, connection.get());
    }

    // Check maximum delay for the sensor.
    nsecs_t maxDelayNs = sensor->getSensor().getMaxDelay() * 1000LL;
    if (maxDelayNs > 0 && (samplingPeriodNs > maxDelayNs)) {
        samplingPeriodNs = maxDelayNs;
    }

    nsecs_t minDelayNs = sensor->getSensor().getMinDelayNs();
    if (samplingPeriodNs < minDelayNs) {
        samplingPeriodNs = minDelayNs;
    }
	
	// 调用SensorHal的batch()
    status_t err = sensor->batch(connection.get(), handle, 0, samplingPeriodNs,
                                 maxBatchReportLatencyNs);

    // Call flush() before calling activate() on the sensor. Wait for a first
    // flush complete event before sending events on this connection. Ignore
    // one-shot sensors which don't support flush(). Ignore on-change sensors
    // to maintain the on-change logic (any on-change events except the initial
    // one should be trigger by a change in value). Also if this sensor isn't
    // already active, don't call flush().
    if (err == NO_ERROR &&
            sensor->getSensor().getReportingMode() == AREPORTING_MODE_CONTINUOUS &&
            rec->getNumConnections() > 1) {
        connection->setFirstFlushPending(handle, true);
        status_t err_flush = sensor->flush(connection.get(), handle);
        // Flush may return error if the underlying h/w sensor uses an older HAL.
        if (err_flush == NO_ERROR) {
            rec->addPendingFlushConnection(connection.get());
        } else {
            connection->setFirstFlushPending(handle, false);
        }
    }

	// 调用SensorHal的activate()方法
    if (err == NO_ERROR) {
        ALOGD_IF(DEBUG_CONNECTIONS, "Calling activate on %d", handle);
        err = sensor->activate(connection.get(), true);
    }

	// 省略部分代码;
}

9.1 getNumConnections() > 1的处理

       在检测到同一个类型的sensor有不同的App connect连接后:

        ①. 先把first flush pending状态切为true;

        ② 然后调用SensorHal层的flush;

从代码上看,想要支持多client,可在SensorHal层的flush操作后,返回给系统一个非0值,将first flush pending状态切为false,即可;

  • 22
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值