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