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.Objects;
33 import java.util.concurrent.Executor;
34 import java.util.concurrent.Future;
35 
36 public class SensorService extends SystemService {
37     private static final String START_NATIVE_SENSOR_SERVICE = "StartNativeSensorService";
38     private final Object mLock = new Object();
39     @GuardedBy("mLock")
40     private final ArrayMap<ProximityActiveListener, ProximityListenerProxy> mProximityListeners =
41             new ArrayMap<>();
42     @GuardedBy("mLock")
43     private Future<?> mSensorServiceStart;
44     @GuardedBy("mLock")
45     private long mPtr;
46 
47 
48     /** Start the sensor service. This is a blocking call and can take time. */
startSensorServiceNative(ProximityActiveListener listener)49     private static native long startSensorServiceNative(ProximityActiveListener listener);
50 
registerProximityActiveListenerNative(long ptr)51     private static native void registerProximityActiveListenerNative(long ptr);
unregisterProximityActiveListenerNative(long ptr)52     private static native void unregisterProximityActiveListenerNative(long ptr);
53 
54 
SensorService(Context ctx)55     public SensorService(Context ctx) {
56         super(ctx);
57         synchronized (mLock) {
58             mSensorServiceStart = SystemServerInitThreadPool.submit(() -> {
59                 TimingsTraceAndSlog traceLog = TimingsTraceAndSlog.newAsyncLog();
60                 traceLog.traceBegin(START_NATIVE_SENSOR_SERVICE);
61                 long ptr = startSensorServiceNative(new ProximityListenerDelegate());
62                 synchronized (mLock) {
63                     mPtr = ptr;
64                 }
65                 traceLog.traceEnd();
66             }, START_NATIVE_SENSOR_SERVICE);
67         }
68     }
69 
70     @Override
onStart()71     public void onStart() {
72         LocalServices.addService(SensorManagerInternal.class, new LocalService());
73     }
74 
75     @Override
onBootPhase(int phase)76     public void onBootPhase(int phase) {
77         if (phase == SystemService.PHASE_WAIT_FOR_SENSOR_SERVICE) {
78             ConcurrentUtils.waitForFutureNoInterrupt(mSensorServiceStart,
79                     START_NATIVE_SENSOR_SERVICE);
80             synchronized (mLock) {
81                 mSensorServiceStart = null;
82             }
83         }
84     }
85 
86     class LocalService extends SensorManagerInternal {
87         @Override
addProximityActiveListener(@onNull Executor executor, @NonNull ProximityActiveListener listener)88         public void addProximityActiveListener(@NonNull Executor executor,
89                 @NonNull ProximityActiveListener listener) {
90             Objects.requireNonNull(executor, "executor must not be null");
91             Objects.requireNonNull(listener, "listener must not be null");
92             ProximityListenerProxy proxy = new ProximityListenerProxy(executor, listener);
93             synchronized (mLock) {
94                 if (mProximityListeners.containsKey(listener)) {
95                     throw new IllegalArgumentException("listener already registered");
96                 }
97                 mProximityListeners.put(listener, proxy);
98                 if (mProximityListeners.size() == 1) {
99                     registerProximityActiveListenerNative(mPtr);
100                 }
101             }
102         }
103 
104         @Override
removeProximityActiveListener(@onNull ProximityActiveListener listener)105         public void removeProximityActiveListener(@NonNull ProximityActiveListener listener) {
106             Objects.requireNonNull(listener, "listener must not be null");
107             synchronized (mLock) {
108                 ProximityListenerProxy proxy = mProximityListeners.remove(listener);
109                 if (proxy == null) {
110                     throw new IllegalArgumentException(
111                             "listener was not registered with sensor service");
112                 }
113                 if (mProximityListeners.isEmpty()) {
114                     unregisterProximityActiveListenerNative(mPtr);
115                 }
116             }
117         }
118     }
119 
120     private static class ProximityListenerProxy implements ProximityActiveListener {
121         private final Executor mExecutor;
122         private final ProximityActiveListener mListener;
123 
ProximityListenerProxy(Executor executor, ProximityActiveListener listener)124         ProximityListenerProxy(Executor executor, ProximityActiveListener listener) {
125             mExecutor = executor;
126             mListener = listener;
127         }
128 
129         @Override
onProximityActive(boolean isActive)130         public void onProximityActive(boolean isActive) {
131             mExecutor.execute(() -> mListener.onProximityActive(isActive));
132         }
133     }
134 
135     private class ProximityListenerDelegate implements ProximityActiveListener {
136         @Override
onProximityActive(boolean isActive)137         public void onProximityActive(boolean isActive) {
138             final ProximityListenerProxy[] listeners;
139             // We can't call out while holding the lock because clients might be calling into us
140             // while holding their own  locks (e.g. when registering / unregistering their
141             // listeners).This would break lock ordering and create deadlocks. Instead, we need to
142             // copy the listeners out and then only invoke them once we've dropped the lock.
143             synchronized (mLock) {
144                 listeners = mProximityListeners.values().toArray(new ProximityListenerProxy[0]);
145             }
146             for (ProximityListenerProxy listener : listeners) {
147                 listener.onProximityActive(isActive);
148             }
149         }
150     }
151 }
152