summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/sensors/SensorManagerInternal.java55
-rw-r--r--services/core/java/com/android/server/sensors/SensorService.java93
-rw-r--r--services/core/jni/com_android_server_sensor_SensorService.cpp115
3 files changed, 247 insertions, 16 deletions
diff --git a/services/core/java/com/android/server/sensors/SensorManagerInternal.java b/services/core/java/com/android/server/sensors/SensorManagerInternal.java
new file mode 100644
index 000000000000..fbb6644934f1
--- /dev/null
+++ b/services/core/java/com/android/server/sensors/SensorManagerInternal.java
@@ -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);
+ }
+}
diff --git a/services/core/java/com/android/server/sensors/SensorService.java b/services/core/java/com/android/server/sensors/SensorService.java
index f7ed8e7138fa..8fe2d52f7160 100644
--- a/services/core/java/com/android/server/sensors/SensorService.java
+++ b/services/core/java/com/android/server/sensors/SensorService.java
@@ -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);
+ }
+ }
+ }
}
diff --git a/services/core/jni/com_android_server_sensor_SensorService.cpp b/services/core/jni/com_android_server_sensor_SensorService.cpp
index acad1bc95ce0..d0f56e62f487 100644
--- a/services/core/jni/com_android_server_sensor_SensorService.cpp
+++ b/services/core/jni/com_android_server_sensor_SensorService.cpp
@@ -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));
}