diff options
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)); } |