1 /*
2  * Copyright (C) 2015 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.locksettings;
18 
19 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED;
20 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT;
21 
22 import android.app.AlarmManager;
23 import android.app.AlarmManager.OnAlarmListener;
24 import android.app.admin.DevicePolicyManager;
25 import android.app.trust.IStrongAuthTracker;
26 import android.content.Context;
27 import android.content.pm.PackageManager;
28 import android.hardware.fingerprint.FingerprintManager;
29 import android.os.Handler;
30 import android.os.Message;
31 import android.os.RemoteCallbackList;
32 import android.os.RemoteException;
33 import android.os.SystemClock;
34 import android.os.UserHandle;
35 import android.util.ArrayMap;
36 import android.util.Slog;
37 import android.util.SparseIntArray;
38 
39 import com.android.internal.widget.LockPatternUtils.StrongAuthTracker;
40 
41 /**
42  * Keeps track of requests for strong authentication.
43  */
44 public class LockSettingsStrongAuth {
45 
46     private static final String TAG = "LockSettings";
47 
48     private static final int MSG_REQUIRE_STRONG_AUTH = 1;
49     private static final int MSG_REGISTER_TRACKER = 2;
50     private static final int MSG_UNREGISTER_TRACKER = 3;
51     private static final int MSG_REMOVE_USER = 4;
52     private static final int MSG_SCHEDULE_STRONG_AUTH_TIMEOUT = 5;
53 
54     private static final String STRONG_AUTH_TIMEOUT_ALARM_TAG =
55             "LockSettingsStrongAuth.timeoutForUser";
56 
57     private final RemoteCallbackList<IStrongAuthTracker> mTrackers = new RemoteCallbackList<>();
58     private final SparseIntArray mStrongAuthForUser = new SparseIntArray();
59     private final ArrayMap<Integer, StrongAuthTimeoutAlarmListener>
60             mStrongAuthTimeoutAlarmListenerForUser = new ArrayMap<>();
61     private final int mDefaultStrongAuthFlags;
62     private final Context mContext;
63 
64     private AlarmManager mAlarmManager;
65     private FingerprintManager mFingerprintManager;
66 
LockSettingsStrongAuth(Context context)67     public LockSettingsStrongAuth(Context context) {
68         mContext = context;
69         mDefaultStrongAuthFlags = StrongAuthTracker.getDefaultFlags(context);
70         mAlarmManager = context.getSystemService(AlarmManager.class);
71     }
72 
systemReady()73     public void systemReady() {
74         final PackageManager pm = mContext.getPackageManager();
75         if (pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
76             mFingerprintManager = mContext.getSystemService(FingerprintManager.class);
77         }
78     }
79 
handleAddStrongAuthTracker(IStrongAuthTracker tracker)80     private void handleAddStrongAuthTracker(IStrongAuthTracker tracker) {
81         mTrackers.register(tracker);
82 
83         for (int i = 0; i < mStrongAuthForUser.size(); i++) {
84             int key = mStrongAuthForUser.keyAt(i);
85             int value = mStrongAuthForUser.valueAt(i);
86             try {
87                 tracker.onStrongAuthRequiredChanged(value, key);
88             } catch (RemoteException e) {
89                 Slog.e(TAG, "Exception while adding StrongAuthTracker.", e);
90             }
91         }
92     }
93 
handleRemoveStrongAuthTracker(IStrongAuthTracker tracker)94     private void handleRemoveStrongAuthTracker(IStrongAuthTracker tracker) {
95         mTrackers.unregister(tracker);
96     }
97 
handleRequireStrongAuth(int strongAuthReason, int userId)98     private void handleRequireStrongAuth(int strongAuthReason, int userId) {
99         if (userId == UserHandle.USER_ALL) {
100             for (int i = 0; i < mStrongAuthForUser.size(); i++) {
101                 int key = mStrongAuthForUser.keyAt(i);
102                 handleRequireStrongAuthOneUser(strongAuthReason, key);
103             }
104         } else {
105             handleRequireStrongAuthOneUser(strongAuthReason, userId);
106         }
107     }
108 
handleRequireStrongAuthOneUser(int strongAuthReason, int userId)109     private void handleRequireStrongAuthOneUser(int strongAuthReason, int userId) {
110         int oldValue = mStrongAuthForUser.get(userId, mDefaultStrongAuthFlags);
111         int newValue = strongAuthReason == STRONG_AUTH_NOT_REQUIRED
112                 ? STRONG_AUTH_NOT_REQUIRED
113                 : (oldValue | strongAuthReason);
114         if (oldValue != newValue) {
115             mStrongAuthForUser.put(userId, newValue);
116             notifyStrongAuthTrackers(newValue, userId);
117         }
118     }
119 
handleRemoveUser(int userId)120     private void handleRemoveUser(int userId) {
121         int index = mStrongAuthForUser.indexOfKey(userId);
122         if (index >= 0) {
123             mStrongAuthForUser.removeAt(index);
124             notifyStrongAuthTrackers(mDefaultStrongAuthFlags, userId);
125         }
126     }
127 
handleScheduleStrongAuthTimeout(int userId)128     private void handleScheduleStrongAuthTimeout(int userId) {
129         final DevicePolicyManager dpm =
130                 (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
131         long when = SystemClock.elapsedRealtime() + dpm.getRequiredStrongAuthTimeout(null, userId);
132         // cancel current alarm listener for the user (if there was one)
133         StrongAuthTimeoutAlarmListener alarm = mStrongAuthTimeoutAlarmListenerForUser.get(userId);
134         if (alarm != null) {
135             mAlarmManager.cancel(alarm);
136         } else {
137             alarm = new StrongAuthTimeoutAlarmListener(userId);
138             mStrongAuthTimeoutAlarmListenerForUser.put(userId, alarm);
139         }
140         // schedule a new alarm listener for the user
141         mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, when, STRONG_AUTH_TIMEOUT_ALARM_TAG,
142                 alarm, mHandler);
143     }
144 
notifyStrongAuthTrackers(int strongAuthReason, int userId)145     private void notifyStrongAuthTrackers(int strongAuthReason, int userId) {
146         int i = mTrackers.beginBroadcast();
147         try {
148             while (i > 0) {
149                 i--;
150                 try {
151                     mTrackers.getBroadcastItem(i).onStrongAuthRequiredChanged(
152                             strongAuthReason, userId);
153                 } catch (RemoteException e) {
154                     Slog.e(TAG, "Exception while notifying StrongAuthTracker.", e);
155                 }
156             }
157         } finally {
158             mTrackers.finishBroadcast();
159         }
160     }
161 
registerStrongAuthTracker(IStrongAuthTracker tracker)162     public void registerStrongAuthTracker(IStrongAuthTracker tracker) {
163         mHandler.obtainMessage(MSG_REGISTER_TRACKER, tracker).sendToTarget();
164     }
165 
unregisterStrongAuthTracker(IStrongAuthTracker tracker)166     public void unregisterStrongAuthTracker(IStrongAuthTracker tracker) {
167         mHandler.obtainMessage(MSG_UNREGISTER_TRACKER, tracker).sendToTarget();
168     }
169 
removeUser(int userId)170     public void removeUser(int userId) {
171         final int argNotUsed = 0;
172         mHandler.obtainMessage(MSG_REMOVE_USER, userId, argNotUsed).sendToTarget();
173     }
174 
requireStrongAuth(int strongAuthReason, int userId)175     public void requireStrongAuth(int strongAuthReason, int userId) {
176         if (userId == UserHandle.USER_ALL || userId >= UserHandle.USER_SYSTEM) {
177             mHandler.obtainMessage(MSG_REQUIRE_STRONG_AUTH, strongAuthReason,
178                     userId).sendToTarget();
179         } else {
180             throw new IllegalArgumentException(
181                     "userId must be an explicit user id or USER_ALL");
182         }
183     }
184 
reportUnlock(int userId)185     public void reportUnlock(int userId) {
186         requireStrongAuth(STRONG_AUTH_NOT_REQUIRED, userId);
187     }
188 
reportSuccessfulStrongAuthUnlock(int userId)189     public void reportSuccessfulStrongAuthUnlock(int userId) {
190         if (mFingerprintManager != null) {
191             byte[] token = null; /* TODO: pass real auth token once fp HAL supports it */
192             mFingerprintManager.resetTimeout(token);
193         }
194 
195         final int argNotUsed = 0;
196         mHandler.obtainMessage(MSG_SCHEDULE_STRONG_AUTH_TIMEOUT, userId, argNotUsed).sendToTarget();
197     }
198 
199     private class StrongAuthTimeoutAlarmListener implements OnAlarmListener {
200 
201         private final int mUserId;
202 
StrongAuthTimeoutAlarmListener(int userId)203         public StrongAuthTimeoutAlarmListener(int userId) {
204             mUserId = userId;
205         }
206 
207         @Override
onAlarm()208         public void onAlarm() {
209             requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_TIMEOUT, mUserId);
210         }
211     }
212 
213     private final Handler mHandler = new Handler() {
214         @Override
215         public void handleMessage(Message msg) {
216             switch (msg.what) {
217                 case MSG_REGISTER_TRACKER:
218                     handleAddStrongAuthTracker((IStrongAuthTracker) msg.obj);
219                     break;
220                 case MSG_UNREGISTER_TRACKER:
221                     handleRemoveStrongAuthTracker((IStrongAuthTracker) msg.obj);
222                     break;
223                 case MSG_REQUIRE_STRONG_AUTH:
224                     handleRequireStrongAuth(msg.arg1, msg.arg2);
225                     break;
226                 case MSG_REMOVE_USER:
227                     handleRemoveUser(msg.arg1);
228                     break;
229                 case MSG_SCHEDULE_STRONG_AUTH_TIMEOUT:
230                     handleScheduleStrongAuthTimeout(msg.arg1);
231                     break;
232             }
233         }
234     };
235 
236 }
237