• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 android.hardware.face;
18 
19 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
20 
21 import android.annotation.Nullable;
22 import android.content.Context;
23 import android.hardware.biometrics.face.IFace;
24 import android.hardware.biometrics.face.SensorProps;
25 import android.hardware.biometrics.face.virtualhal.IVirtualHal;
26 import android.os.Binder;
27 import android.os.Parcel;
28 import android.os.Parcelable;
29 import android.os.RemoteException;
30 import android.os.ServiceManager;
31 import android.util.Log;
32 import android.util.Slog;
33 
34 import androidx.annotation.NonNull;
35 
36 import java.util.ArrayList;
37 import java.util.HashMap;
38 import java.util.List;
39 import java.util.Map;
40 import java.util.Optional;
41 
42 /**
43  * Provides the sensor props for face sensor, if available.
44  * @hide
45  */
46 public class FaceSensorConfigurations implements Parcelable {
47     private static final String TAG = "FaceSensorConfigurations";
48 
49     private final boolean mResetLockoutRequiresChallenge;
50     private final Map<String, SensorProps[]> mSensorPropsMap;
51 
52     public static final Creator<FaceSensorConfigurations> CREATOR =
53             new Creator<FaceSensorConfigurations>() {
54                 @Override
55                 public FaceSensorConfigurations createFromParcel(Parcel in) {
56                     return new FaceSensorConfigurations(in);
57                 }
58 
59                 @Override
60                 public FaceSensorConfigurations[] newArray(int size) {
61                     return new FaceSensorConfigurations[size];
62                 }
63             };
64 
FaceSensorConfigurations(boolean resetLockoutRequiresChallenge)65     public FaceSensorConfigurations(boolean resetLockoutRequiresChallenge) {
66         mResetLockoutRequiresChallenge = resetLockoutRequiresChallenge;
67         mSensorPropsMap = new HashMap<>();
68     }
69 
FaceSensorConfigurations(Parcel in)70     protected FaceSensorConfigurations(Parcel in) {
71         mResetLockoutRequiresChallenge = in.readByte() != 0;
72         mSensorPropsMap = in.readHashMap(null, String.class, SensorProps[].class);
73     }
74 
75     /**
76      * Process AIDL instances to extract sensor props and add it to the sensor map.
77      * @param aidlInstances available face AIDL instances
78      */
addAidlConfigs(@onNull String[] aidlInstances)79     public void addAidlConfigs(@NonNull String[] aidlInstances) {
80         for (String aidlInstance : aidlInstances) {
81             mSensorPropsMap.put(aidlInstance, null);
82         }
83     }
84 
85     /**
86      * Parse through HIDL configuration and add it to the sensor map.
87      */
addHidlConfigs(@onNull String[] hidlConfigStrings, @NonNull Context context)88     public void addHidlConfigs(@NonNull String[] hidlConfigStrings,
89             @NonNull Context context) {
90         final List<HidlFaceSensorConfig> hidlFaceSensorConfigs = new ArrayList<>();
91         for (String hidlConfig: hidlConfigStrings) {
92             final HidlFaceSensorConfig hidlFaceSensorConfig = new HidlFaceSensorConfig();
93             try {
94                 hidlFaceSensorConfig.parse(hidlConfig, context);
95             } catch (Exception e) {
96                 Log.e(TAG, "HIDL sensor configuration format is incorrect.");
97                 continue;
98             }
99             if (hidlFaceSensorConfig.getModality() == TYPE_FACE) {
100                 hidlFaceSensorConfigs.add(hidlFaceSensorConfig);
101             }
102         }
103         final String hidlHalInstanceName = "defaultHIDL";
104         mSensorPropsMap.put(hidlHalInstanceName, hidlFaceSensorConfigs.toArray(
105                 new SensorProps[hidlFaceSensorConfigs.size()]));
106     }
107 
108     /**
109      * Returns true if any face sensors have been added.
110      */
hasSensorConfigurations()111     public boolean hasSensorConfigurations() {
112         return mSensorPropsMap.size() > 0;
113     }
114 
115     /**
116      * Returns true if there is only a single face sensor configuration available.
117      */
isSingleSensorConfigurationPresent()118     public boolean isSingleSensorConfigurationPresent() {
119         return mSensorPropsMap.size() == 1;
120     }
121 
122     /**
123      * Checks if {@param instance} exists.
124      */
125     @Nullable
doesInstanceExist(String instance)126     public boolean doesInstanceExist(String instance) {
127         return mSensorPropsMap.containsKey(instance);
128     }
129 
130     /**
131      * Return the first HAL instance, which does not correspond to the given {@param instance}.
132      * If another instance is not available, then null is returned.
133      */
134     @Nullable
getSensorNameNotForInstance(String instance)135     public String getSensorNameNotForInstance(String instance) {
136         Optional<String> notAVirtualInstance = mSensorPropsMap.keySet().stream().filter(
137                 (instanceName) -> !instanceName.equals(instance)).findFirst();
138         return notAVirtualInstance.orElse(null);
139     }
140 
141     /**
142      * Returns the first instance that has been added to the map.
143      */
144     @Nullable
getSensorInstance()145     public String getSensorInstance() {
146         Optional<String> optionalInstance = mSensorPropsMap.keySet().stream().findFirst();
147         return optionalInstance.orElse(null);
148     }
149 
getResetLockoutRequiresChallenge()150     public boolean getResetLockoutRequiresChallenge() {
151         return mResetLockoutRequiresChallenge;
152     }
153 
154     @Override
describeContents()155     public int describeContents() {
156         return 0;
157     }
158 
159     @Override
writeToParcel(@onNull Parcel dest, int flags)160     public void writeToParcel(@NonNull Parcel dest, int flags) {
161         dest.writeByte((byte) (mResetLockoutRequiresChallenge ? 1 : 0));
162         dest.writeMap(mSensorPropsMap);
163     }
164     /**
165      * Remap fqName of VHAL because the `virtual` instance is registered
166      * with IVirtulalHal now (IFace previously)
167      * @param fqName fqName to be translated
168      * @return real fqName
169      */
remapFqName(String fqName)170     public static String remapFqName(String fqName) {
171         if (!fqName.contains(IFace.DESCRIPTOR + "/virtual")) {
172             return fqName;  //no remap needed for real hardware HAL
173         } else {
174             //new Vhal instance name
175             return fqName.replace("IFace", "virtualhal.IVirtualHal");
176         }
177     }
178     /**
179      * @param fqName aidl interface instance name
180      * @return aidl interface
181      */
getIFace(String fqName)182     public static IFace getIFace(String fqName) {
183         if (fqName.contains("virtual")) {
184             String fqNameMapped = remapFqName(fqName);
185             Slog.i(TAG, "getIFace fqName is mapped: " + fqName + "->" + fqNameMapped);
186             try {
187                 IVirtualHal vhal = IVirtualHal.Stub.asInterface(
188                         Binder.allowBlocking(ServiceManager.waitForService(fqNameMapped)));
189                 return vhal.getFaceHal();
190             } catch (RemoteException e) {
191                 Slog.e(TAG, "Remote exception in vhal.getFaceHal() call" + fqNameMapped);
192             }
193         }
194 
195         return IFace.Stub.asInterface(
196                 Binder.allowBlocking(ServiceManager.waitForDeclaredService(fqName)));
197     }
198 
199 
200     /**
201      * Returns face sensor props for the HAL {@param instance}.
202      */
203     @Nullable
getSensorPropForInstance(String instance)204     public SensorProps[] getSensorPropForInstance(String instance) {
205         SensorProps[] props = mSensorPropsMap.get(instance);
206 
207         //Props should not be null for HIDL configs
208         if (props != null) {
209             return props;
210         }
211 
212         try {
213             final String fqName = IFace.DESCRIPTOR + "/" + instance;
214             final IFace fp = getIFace(fqName);
215             if (fp != null) {
216                 props = fp.getSensorProps();
217             } else {
218                 Log.d(TAG, "IFace null for instance " + instance);
219             }
220         } catch (RemoteException e) {
221             Log.d(TAG, "Unable to get sensor properties!");
222         }
223         return props;
224     }
225 }
226