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

Commit 3fdf934d authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Add support to register Java listeners for prox activation" into sc-dev...

Merge "Add support to register Java listeners for prox activation" into sc-dev am: c05ebb5b am: c31150a9

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/14426685

Change-Id: Ia24ca5407cb6fff251cd52da62720fbc902a61c8
parents ea33df60 c31150a9
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));
}