Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8f9f09ae authored by Michael Wright's avatar Michael Wright Committed by Santos Cordon
Browse files

Add support to register Java listeners for prox activation

Bug: 175793106
Test: register prox sensor listener, see state changes

Change-Id: I7d3984c1fdddd1270a9f89020e8f0205d68aa85e
parent 28c48606
Loading
Loading
Loading
Loading
+55 −0
Original line number Diff line number Diff line
/*
 * 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);
    }
}
+90 −3
Original line number Diff line number Diff line
@@ -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);
            }
        }
    }
}
+102 −13
Original line number Diff line number Diff line
@@ -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));
}