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