1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.sensors; 18 19 import static com.android.server.sensors.SensorManagerInternal.ProximityActiveListener; 20 21 import android.annotation.NonNull; 22 import android.content.Context; 23 import android.util.ArrayMap; 24 25 import com.android.internal.annotations.GuardedBy; 26 import com.android.internal.util.ConcurrentUtils; 27 import com.android.server.LocalServices; 28 import com.android.server.SystemServerInitThreadPool; 29 import com.android.server.SystemService; 30 import com.android.server.utils.TimingsTraceAndSlog; 31 32 import java.util.HashSet; 33 import java.util.Objects; 34 import java.util.Set; 35 import java.util.concurrent.Executor; 36 import java.util.concurrent.Future; 37 38 public class SensorService extends SystemService { 39 private static final String START_NATIVE_SENSOR_SERVICE = "StartNativeSensorService"; 40 private final Object mLock = new Object(); 41 @GuardedBy("mLock") 42 private final ArrayMap<ProximityActiveListener, ProximityListenerProxy> mProximityListeners = 43 new ArrayMap<>(); 44 @GuardedBy("mLock") 45 private final Set<Integer> mRuntimeSensorHandles = new HashSet<>(); 46 @GuardedBy("mLock") 47 private Future<?> mSensorServiceStart; 48 @GuardedBy("mLock") 49 private long mPtr; 50 51 52 /** Start the sensor service. This is a blocking call and can take time. */ startSensorServiceNative(ProximityActiveListener listener)53 private static native long startSensorServiceNative(ProximityActiveListener listener); 54 registerProximityActiveListenerNative(long ptr)55 private static native void registerProximityActiveListenerNative(long ptr); unregisterProximityActiveListenerNative(long ptr)56 private static native void unregisterProximityActiveListenerNative(long ptr); 57 registerRuntimeSensorNative(long ptr, int deviceId, int type, String name, String vendor, float maximumRange, float resolution, float power, int minDelay, int maxDelay, int flags, SensorManagerInternal.RuntimeSensorCallback callback)58 private static native int registerRuntimeSensorNative(long ptr, int deviceId, int type, 59 String name, String vendor, float maximumRange, float resolution, float power, 60 int minDelay, int maxDelay, int flags, 61 SensorManagerInternal.RuntimeSensorCallback callback); unregisterRuntimeSensorNative(long ptr, int handle)62 private static native void unregisterRuntimeSensorNative(long ptr, int handle); sendRuntimeSensorEventNative(long ptr, int handle, int type, long timestampNanos, float[] values)63 private static native boolean sendRuntimeSensorEventNative(long ptr, int handle, int type, 64 long timestampNanos, float[] values); 65 SensorService(Context ctx)66 public SensorService(Context ctx) { 67 super(ctx); 68 synchronized (mLock) { 69 mSensorServiceStart = SystemServerInitThreadPool.submit(() -> { 70 TimingsTraceAndSlog traceLog = TimingsTraceAndSlog.newAsyncLog(); 71 traceLog.traceBegin(START_NATIVE_SENSOR_SERVICE); 72 long ptr = startSensorServiceNative(new ProximityListenerDelegate()); 73 synchronized (mLock) { 74 mPtr = ptr; 75 } 76 traceLog.traceEnd(); 77 }, START_NATIVE_SENSOR_SERVICE); 78 } 79 } 80 81 @Override onStart()82 public void onStart() { 83 LocalServices.addService(SensorManagerInternal.class, new LocalService()); 84 } 85 86 @Override onBootPhase(int phase)87 public void onBootPhase(int phase) { 88 if (phase == SystemService.PHASE_WAIT_FOR_SENSOR_SERVICE) { 89 ConcurrentUtils.waitForFutureNoInterrupt(mSensorServiceStart, 90 START_NATIVE_SENSOR_SERVICE); 91 synchronized (mLock) { 92 mSensorServiceStart = null; 93 } 94 } 95 } 96 97 class LocalService extends SensorManagerInternal { 98 @Override createRuntimeSensor(int deviceId, int type, @NonNull String name, @NonNull String vendor, float maximumRange, float resolution, float power, int minDelay, int maxDelay, int flags, @NonNull RuntimeSensorCallback callback)99 public int createRuntimeSensor(int deviceId, int type, @NonNull String name, 100 @NonNull String vendor, float maximumRange, float resolution, float power, 101 int minDelay, int maxDelay, int flags, @NonNull RuntimeSensorCallback callback) { 102 synchronized (mLock) { 103 int handle = registerRuntimeSensorNative(mPtr, deviceId, type, name, vendor, 104 maximumRange, resolution, power, minDelay, maxDelay, flags, callback); 105 mRuntimeSensorHandles.add(handle); 106 return handle; 107 } 108 } 109 110 @Override removeRuntimeSensor(int handle)111 public void removeRuntimeSensor(int handle) { 112 synchronized (mLock) { 113 if (mRuntimeSensorHandles.contains(handle)) { 114 mRuntimeSensorHandles.remove(handle); 115 unregisterRuntimeSensorNative(mPtr, handle); 116 } 117 } 118 } 119 120 @Override sendSensorEvent(int handle, int type, long timestampNanos, @NonNull float[] values)121 public boolean sendSensorEvent(int handle, int type, long timestampNanos, 122 @NonNull float[] values) { 123 synchronized (mLock) { 124 if (!mRuntimeSensorHandles.contains(handle)) { 125 return false; 126 } 127 return sendRuntimeSensorEventNative(mPtr, handle, type, timestampNanos, values); 128 } 129 } 130 131 @Override addProximityActiveListener(@onNull Executor executor, @NonNull ProximityActiveListener listener)132 public void addProximityActiveListener(@NonNull Executor executor, 133 @NonNull ProximityActiveListener listener) { 134 Objects.requireNonNull(executor, "executor must not be null"); 135 Objects.requireNonNull(listener, "listener must not be null"); 136 ProximityListenerProxy proxy = new ProximityListenerProxy(executor, listener); 137 synchronized (mLock) { 138 if (mProximityListeners.containsKey(listener)) { 139 throw new IllegalArgumentException("listener already registered"); 140 } 141 mProximityListeners.put(listener, proxy); 142 if (mProximityListeners.size() == 1) { 143 registerProximityActiveListenerNative(mPtr); 144 } 145 } 146 } 147 148 @Override removeProximityActiveListener(@onNull ProximityActiveListener listener)149 public void removeProximityActiveListener(@NonNull ProximityActiveListener listener) { 150 Objects.requireNonNull(listener, "listener must not be null"); 151 synchronized (mLock) { 152 ProximityListenerProxy proxy = mProximityListeners.remove(listener); 153 if (proxy == null) { 154 throw new IllegalArgumentException( 155 "listener was not registered with sensor service"); 156 } 157 if (mProximityListeners.isEmpty()) { 158 unregisterProximityActiveListenerNative(mPtr); 159 } 160 } 161 } 162 } 163 164 private static class ProximityListenerProxy implements ProximityActiveListener { 165 private final Executor mExecutor; 166 private final ProximityActiveListener mListener; 167 ProximityListenerProxy(Executor executor, ProximityActiveListener listener)168 ProximityListenerProxy(Executor executor, ProximityActiveListener listener) { 169 mExecutor = executor; 170 mListener = listener; 171 } 172 173 @Override onProximityActive(boolean isActive)174 public void onProximityActive(boolean isActive) { 175 mExecutor.execute(() -> mListener.onProximityActive(isActive)); 176 } 177 } 178 179 private class ProximityListenerDelegate implements ProximityActiveListener { 180 @Override onProximityActive(boolean isActive)181 public void onProximityActive(boolean isActive) { 182 final ProximityListenerProxy[] listeners; 183 // We can't call out while holding the lock because clients might be calling into us 184 // while holding their own locks (e.g. when registering / unregistering their 185 // listeners).This would break lock ordering and create deadlocks. Instead, we need to 186 // copy the listeners out and then only invoke them once we've dropped the lock. 187 synchronized (mLock) { 188 listeners = mProximityListeners.values().toArray(new ProximityListenerProxy[0]); 189 } 190 for (ProximityListenerProxy listener : listeners) { 191 listener.onProximityActive(isActive); 192 } 193 } 194 } 195 } 196