Add support to register Java listeners for prox activation
Bug: 175793106 Test: register prox sensor listener, see state changes Change-Id: I7d3984c1fdddd1270a9f89020e8f0205d68aa85e
This commit is contained in:
committed by
Santos Cordon
parent
28c4860610
commit
8f9f09aef9
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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 android.annotation.NonNull;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* Local system service interface for sensors.
|
||||
*
|
||||
* @hide Only for use within system server.
|
||||
*/
|
||||
public abstract class SensorManagerInternal {
|
||||
/**
|
||||
* Adds a listener for changes in proximity sensor state.
|
||||
* @param executor The {@link Executor} to {@link Executor#execute invoke} the listener on.
|
||||
* @param listener The listener to add.
|
||||
*
|
||||
* @throws IllegalArgumentException when adding a listener that is already listening
|
||||
*/
|
||||
public abstract void addProximityActiveListener(@NonNull Executor executor,
|
||||
@NonNull ProximityActiveListener listener);
|
||||
|
||||
/**
|
||||
* Removes a previously registered listener of proximity sensor state changes.
|
||||
* @param listener The listener to remove.
|
||||
*/
|
||||
public abstract void removeProximityActiveListener(@NonNull ProximityActiveListener listener);
|
||||
|
||||
/**
|
||||
* Listener for proximity sensor state changes.
|
||||
*/
|
||||
public interface ProximityActiveListener {
|
||||
/**
|
||||
* Callback invoked when the proximity sensor state changes
|
||||
* @param isActive whether the sensor is being enabled or disabled.
|
||||
*/
|
||||
void onProximityActive(boolean isActive);
|
||||
}
|
||||
}
|
||||
@@ -16,25 +16,41 @@
|
||||
|
||||
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<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 void startNativeSensorService();
|
||||
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);
|
||||
@@ -42,14 +58,19 @@ public class SensorService extends SystemService {
|
||||
mSensorServiceStart = SystemServerInitThreadPool.submit(() -> {
|
||||
TimingsTraceAndSlog traceLog = TimingsTraceAndSlog.newAsyncLog();
|
||||
traceLog.traceBegin(START_NATIVE_SENSOR_SERVICE);
|
||||
startNativeSensorService();
|
||||
long ptr = startSensorServiceNative(new ProximityListenerDelegate());
|
||||
synchronized (mLock) {
|
||||
mPtr = ptr;
|
||||
}
|
||||
traceLog.traceEnd();
|
||||
}, START_NATIVE_SENSOR_SERVICE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() { }
|
||||
public void onStart() {
|
||||
LocalServices.addService(SensorManagerInternal.class, new LocalService());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBootPhase(int phase) {
|
||||
@@ -61,4 +82,70 @@ public class SensorService extends SystemService {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,34 +14,123 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "SensorService"
|
||||
|
||||
#include <nativehelper/JNIHelp.h>
|
||||
#include "android_runtime/AndroidRuntime.h"
|
||||
#include "core_jni_helpers.h"
|
||||
#include "jni.h"
|
||||
#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 void startNativeSensorService(JNIEnv* env, jclass clazz) {
|
||||
char propBuf[PROPERTY_VALUE_MAX];
|
||||
property_get("system_init.startsensorservice", propBuf, "1");
|
||||
if (strcmp(propBuf, "1") == 0) {
|
||||
SensorService::publish(false /* allowIsolated */,
|
||||
IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL);
|
||||
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) {
|
||||
AndroidRuntime::getJNIEnv()->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[] = {
|
||||
{"startNativeSensorService", "()V", (void*)startNativeSensorService},
|
||||
{
|
||||
"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(JNIEnv* env) {
|
||||
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));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user