blob: c438bfbdd8fa9902fb77f6120fd2450307837e6a [file] [log] [blame]
Gilad Brettercb51b8b2018-03-22 17:04:51 +02001/*
2 * Copyright (C) 2018 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
Kevin Chyn2ffadb32018-06-19 11:29:38 -070017package com.android.server.biometrics.face;
Gilad Brettercb51b8b2018-03-22 17:04:51 +020018
19import android.content.Context;
Kevin Chyna56dff72018-06-19 18:41:12 -070020import android.hardware.biometrics.BiometricAuthenticator;
Gilad Brettercb51b8b2018-03-22 17:04:51 +020021import android.hardware.face.Face;
Gilad Brettercb51b8b2018-03-22 17:04:51 +020022import android.util.AtomicFile;
23import android.util.Slog;
24import android.util.Xml;
25
Andreas Gamped6d42062018-07-20 13:08:21 -070026import com.android.internal.annotations.GuardedBy;
Kevin Chyna56dff72018-06-19 18:41:12 -070027import com.android.server.biometrics.common.BiometricUserState;
Gilad Brettercb51b8b2018-03-22 17:04:51 +020028
29import libcore.io.IoUtils;
Kevin Chyna56dff72018-06-19 18:41:12 -070030
Gilad Brettercb51b8b2018-03-22 17:04:51 +020031import org.xmlpull.v1.XmlPullParser;
32import org.xmlpull.v1.XmlPullParserException;
33import org.xmlpull.v1.XmlSerializer;
34
Gilad Brettercb51b8b2018-03-22 17:04:51 +020035import java.io.FileOutputStream;
36import java.io.IOException;
Kevin Chyna56dff72018-06-19 18:41:12 -070037import java.util.ArrayList;
Gilad Brettercb51b8b2018-03-22 17:04:51 +020038
39
40/**
41 * Class managing the set of faces per user across device reboots.
Kevin Chyna56dff72018-06-19 18:41:12 -070042 * @hide
Gilad Brettercb51b8b2018-03-22 17:04:51 +020043 */
Kevin Chyna56dff72018-06-19 18:41:12 -070044public class FaceUserState extends BiometricUserState {
Gilad Brettercb51b8b2018-03-22 17:04:51 +020045
46 private static final String TAG = "FaceState";
47 private static final String FACE_FILE = "settings_face.xml";
48
Kevin Chyna56dff72018-06-19 18:41:12 -070049 private static final String TAG_FACES = "faces";
Gilad Brettercb51b8b2018-03-22 17:04:51 +020050 private static final String TAG_FACE = "face";
Kevin Chyna56dff72018-06-19 18:41:12 -070051 private static final String ATTR_NAME = "name";
52 private static final String ATTR_FACE_ID = "faceId";
Gilad Brettercb51b8b2018-03-22 17:04:51 +020053 private static final String ATTR_DEVICE_ID = "deviceId";
54
Gilad Brettercb51b8b2018-03-22 17:04:51 +020055 public FaceUserState(Context ctx, int userId) {
Kevin Chyna56dff72018-06-19 18:41:12 -070056 super(ctx, userId);
57 }
58
59 @Override
60 protected String getBiometricsTag() {
61 return TAG_FACES;
62 }
63
64 @Override
65 protected String getBiometricFile() {
66 return FACE_FILE;
67 }
68
69 @Override
70 protected int getNameTemplateResource() {
71 return com.android.internal.R.string.face_name_template;
72 }
73
74 @Override
75 public void addBiometric(BiometricAuthenticator.Identifier identifier) {
76 if (identifier instanceof Face) {
77 super.addBiometric(identifier);
78 } else {
79 Slog.w(TAG, "Attempted to add non-face identifier");
Gilad Brettercb51b8b2018-03-22 17:04:51 +020080 }
81 }
82
Kevin Chyna56dff72018-06-19 18:41:12 -070083 @Override
84 protected ArrayList getCopy(ArrayList array) {
85 ArrayList<Face> result = new ArrayList<>(array.size());
86 for (int i = 0; i < array.size(); i++) {
87 Face f = (Face) array.get(i);
Kevin Chynb528d692018-07-20 11:53:14 -070088 result.add(new Face(f.getName(), f.getBiometricId(), f.getDeviceId()));
Gilad Brettercb51b8b2018-03-22 17:04:51 +020089 }
Kevin Chyna56dff72018-06-19 18:41:12 -070090 return result;
Gilad Brettercb51b8b2018-03-22 17:04:51 +020091 }
92
Kevin Chyna56dff72018-06-19 18:41:12 -070093 @Override
94 protected void doWriteState() {
Gilad Brettercb51b8b2018-03-22 17:04:51 +020095 AtomicFile destination = new AtomicFile(mFile);
96
Kevin Chyna56dff72018-06-19 18:41:12 -070097 ArrayList<Face> faces;
Gilad Brettercb51b8b2018-03-22 17:04:51 +020098
99 synchronized (this) {
Kevin Chyna56dff72018-06-19 18:41:12 -0700100 faces = getCopy(mBiometrics);
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200101 }
102
103 FileOutputStream out = null;
104 try {
105 out = destination.startWrite();
106
107 XmlSerializer serializer = Xml.newSerializer();
108 serializer.setOutput(out, "utf-8");
109 serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
110 serializer.startDocument(null, true);
Kevin Chyna56dff72018-06-19 18:41:12 -0700111 serializer.startTag(null, TAG_FACES);
112
113 final int count = faces.size();
114 for (int i = 0; i < count; i++) {
115 Face f = faces.get(i);
116 serializer.startTag(null, TAG_FACE);
Kevin Chynb528d692018-07-20 11:53:14 -0700117 serializer.attribute(null, ATTR_FACE_ID, Integer.toString(f.getBiometricId()));
Kevin Chyna56dff72018-06-19 18:41:12 -0700118 serializer.attribute(null, ATTR_NAME, f.getName().toString());
119 serializer.attribute(null, ATTR_DEVICE_ID, Long.toString(f.getDeviceId()));
120 serializer.endTag(null, TAG_FACE);
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200121 }
Kevin Chyna56dff72018-06-19 18:41:12 -0700122
123 serializer.endTag(null, TAG_FACES);
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200124 serializer.endDocument();
125 destination.finishWrite(out);
126
127 // Any error while writing is fatal.
128 } catch (Throwable t) {
129 Slog.wtf(TAG, "Failed to write settings, restoring backup", t);
130 destination.failWrite(out);
Kevin Chyna56dff72018-06-19 18:41:12 -0700131 throw new IllegalStateException("Failed to write faces", t);
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200132 } finally {
133 IoUtils.closeQuietly(out);
134 }
135 }
136
Andreas Gamped6d42062018-07-20 13:08:21 -0700137 @GuardedBy("this")
Kevin Chyna56dff72018-06-19 18:41:12 -0700138 @Override
139 protected void parseBiometricsLocked(XmlPullParser parser)
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200140 throws IOException, XmlPullParserException {
141 final int outerDepth = parser.getDepth();
142 int type;
143 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
144 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
145 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
146 continue;
147 }
148
149 String tagName = parser.getName();
150 if (tagName.equals(TAG_FACE)) {
Kevin Chyna56dff72018-06-19 18:41:12 -0700151 String name = parser.getAttributeValue(null, ATTR_NAME);
152 String faceId = parser.getAttributeValue(null, ATTR_FACE_ID);
153 String deviceId = parser.getAttributeValue(null, ATTR_DEVICE_ID);
154 mBiometrics.add(new Face(name, Integer.parseInt(faceId), Integer.parseInt(deviceId)));
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200155 }
156 }
157 }
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200158}