1 /* 2 * Copyright (C) 2022 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.biometrics.sensors; 18 19 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.hardware.biometrics.IBiometricAuthenticator; 23 import android.hardware.biometrics.IBiometricService; 24 import android.hardware.biometrics.SensorPropertiesInternal; 25 import android.os.Handler; 26 import android.os.IInterface; 27 import android.os.Process; 28 import android.os.RemoteCallbackList; 29 import android.os.RemoteException; 30 import android.util.Pair; 31 import android.util.Slog; 32 33 import com.android.internal.annotations.VisibleForTesting; 34 import com.android.server.ServiceThread; 35 36 import java.util.ArrayList; 37 import java.util.Collections; 38 import java.util.List; 39 import java.util.function.Supplier; 40 41 /** 42 * Container for all BiometricServiceProvider implementations. 43 * 44 * @param <T> The service provider type. 45 * @param <P> The internal properties type. 46 * @param <C> The registration callback for {@link #invokeRegisteredCallback(IInterface, List)}. 47 */ 48 public abstract class BiometricServiceRegistry<T extends BiometricServiceProvider<P>, 49 P extends SensorPropertiesInternal, 50 C extends IInterface> { 51 52 private static final String TAG = "BiometricServiceRegistry"; 53 54 // Volatile so they can be read without a lock once all services are registered. 55 // But, ideally remove this and provide immutable copies via the callback instead. 56 @Nullable 57 private volatile List<T> mServiceProviders; 58 @Nullable 59 private volatile List<P> mAllProps; 60 61 @NonNull 62 private final Supplier<IBiometricService> mBiometricServiceSupplier; 63 @NonNull 64 private final RemoteCallbackList<C> mRegisteredCallbacks = new RemoteCallbackList<>(); 65 BiometricServiceRegistry(@onNull Supplier<IBiometricService> biometricSupplier)66 public BiometricServiceRegistry(@NonNull Supplier<IBiometricService> biometricSupplier) { 67 mBiometricServiceSupplier = biometricSupplier; 68 } 69 70 /** 71 * Register an implementation by creating a new authenticator and initializing it via 72 * {@link IBiometricService#registerAuthenticator(int, int, int, IBiometricAuthenticator)} 73 * using the given properties. 74 * 75 * @param service service to register with 76 * @param props internal properties to initialize the authenticator 77 */ registerService(@onNull IBiometricService service, @NonNull P props)78 protected abstract void registerService(@NonNull IBiometricService service, @NonNull P props); 79 80 /** 81 * Invoke the callback to notify clients that all authenticators have been registered. 82 * 83 * @param callback callback to invoke 84 * @param allProps properties of all authenticators 85 */ invokeRegisteredCallback(@onNull C callback, @NonNull List<P> allProps)86 protected abstract void invokeRegisteredCallback(@NonNull C callback, 87 @NonNull List<P> allProps) throws RemoteException; 88 89 /** 90 * Register all authenticators in a background thread. 91 * 92 * @param serviceProvider Supplier function that will be invoked on the background thread. 93 */ registerAll(Supplier<List<T>> serviceProvider)94 public void registerAll(Supplier<List<T>> serviceProvider) { 95 // Some HAL might not be started before the system service and will cause the code below 96 // to wait, and some of the operations below might take a significant amount of time to 97 // complete (calls to the HALs). To avoid blocking the rest of system server we put 98 // this on a background thread. 99 final ServiceThread thread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND, 100 true /* allowIo */); 101 thread.start(); 102 final Handler handler = new Handler(thread.getLooper()); 103 handler.post(() -> registerAllInBackground(serviceProvider)); 104 thread.quitSafely(); 105 } 106 107 /** Register authenticators now, only called by {@link #registerAll(Supplier).} */ 108 @VisibleForTesting registerAllInBackground(Supplier<List<T>> serviceProvider)109 public void registerAllInBackground(Supplier<List<T>> serviceProvider) { 110 List<T> providers = serviceProvider.get(); 111 if (providers == null) { 112 providers = new ArrayList<>(); 113 } 114 115 final IBiometricService biometricService = mBiometricServiceSupplier.get(); 116 if (biometricService == null) { 117 throw new IllegalStateException("biometric service cannot be null"); 118 } 119 120 // Register each sensor individually with BiometricService 121 final List<P> allProps = new ArrayList<>(); 122 for (T provider : providers) { 123 final List<P> props = provider.getSensorProperties(); 124 for (P prop : props) { 125 registerService(biometricService, prop); 126 } 127 allProps.addAll(props); 128 } 129 130 finishRegistration(providers, allProps); 131 } 132 finishRegistration( @onNull List<T> providers, @NonNull List<P> allProps)133 private synchronized void finishRegistration( 134 @NonNull List<T> providers, @NonNull List<P> allProps) { 135 mServiceProviders = Collections.unmodifiableList(providers); 136 mAllProps = Collections.unmodifiableList(allProps); 137 broadcastAllAuthenticatorsRegistered(); 138 } 139 140 /** 141 * Add a callback that will be invoked once the work from {@link #registerAll(Supplier)} 142 * has finished registering all providers (executes immediately if already done). 143 * 144 * @param callback registration callback 145 */ addAllRegisteredCallback(@ullable C callback)146 public synchronized void addAllRegisteredCallback(@Nullable C callback) { 147 if (callback == null) { 148 Slog.e(TAG, "addAllRegisteredCallback, callback is null"); 149 return; 150 } 151 152 final boolean registered = mRegisteredCallbacks.register(callback); 153 final boolean allRegistered = mServiceProviders != null; 154 if (registered && allRegistered) { 155 broadcastAllAuthenticatorsRegistered(); 156 } else if (!registered) { 157 Slog.e(TAG, "addAllRegisteredCallback failed to register callback"); 158 } 159 } 160 broadcastAllAuthenticatorsRegistered()161 private synchronized void broadcastAllAuthenticatorsRegistered() { 162 final int n = mRegisteredCallbacks.beginBroadcast(); 163 for (int i = 0; i < n; ++i) { 164 final C cb = mRegisteredCallbacks.getBroadcastItem(i); 165 try { 166 invokeRegisteredCallback(cb, mAllProps); 167 } catch (RemoteException e) { 168 Slog.e(TAG, "Remote exception in broadcastAllAuthenticatorsRegistered", e); 169 } finally { 170 mRegisteredCallbacks.unregister(cb); 171 } 172 } 173 mRegisteredCallbacks.finishBroadcast(); 174 } 175 176 /** 177 * Get a list of registered providers. 178 * 179 * Undefined until {@link #registerAll(Supplier)} has fired the completion callback. 180 */ 181 @NonNull getProviders()182 public List<T> getProviders() { 183 return mServiceProviders != null ? mServiceProviders : Collections.emptyList(); 184 } 185 186 /** 187 * Gets the provider for given sensor id or null if not registered. 188 * 189 * Undefined until {@link #registerAll(Supplier)} has fired the completion callback. 190 */ 191 @Nullable getProviderForSensor(int sensorId)192 public T getProviderForSensor(int sensorId) { 193 if (mServiceProviders != null) { 194 for (T provider : mServiceProviders) { 195 if (provider.containsSensor(sensorId)) { 196 return provider; 197 } 198 } 199 } 200 return null; 201 } 202 203 /** 204 * Finds the provider for devices with only a single sensor. 205 * 206 * If no providers returns null. If multiple sensors are present this method 207 * will return the first one that is found (this is a legacy for test devices that 208 * use aidl/hidl concurrently and should not occur on real devices). 209 * 210 * Undefined until {@link #registerAll(Supplier)} has fired the completion callback. 211 */ 212 @Nullable getSingleProvider()213 public Pair<Integer, T> getSingleProvider() { 214 if (mAllProps == null || mAllProps.isEmpty()) { 215 Slog.e(TAG, "No sensors found"); 216 return null; 217 } 218 219 // TODO(b/242837110): remove the try-catch once the bug is fixed. 220 try { 221 if (mAllProps.size() > 1) { 222 Slog.e(TAG, "getSingleProvider() called but multiple sensors present: " 223 + mAllProps.size()); 224 } 225 226 final int sensorId = mAllProps.get(0).sensorId; 227 final T provider = getProviderForSensor(sensorId); 228 if (provider != null) { 229 return new Pair<>(sensorId, provider); 230 } 231 232 Slog.e(TAG, "Single sensor: " + sensorId + ", but provider not found"); 233 return null; 234 } catch (NullPointerException e) { 235 final String extra; 236 if (mAllProps == null) { 237 extra = "mAllProps: null"; 238 } else { 239 extra = "mAllProps.size(): " + mAllProps.size(); 240 } 241 Slog.e(TAG, "This shouldn't happen. " + extra, e); 242 throw e; 243 } 244 } 245 246 /** 247 * Get the properties for all providers. 248 * 249 * Undefined until {@link #registerAll(Supplier)} has fired the completion callback. 250 */ 251 @NonNull getAllProperties()252 public List<P> getAllProperties() { 253 return mAllProps != null ? mAllProps : Collections.emptyList(); 254 } 255 } 256