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
20         .STRONG_AUTH_NOT_REQUIRED;
21 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker
22         .STRONG_AUTH_REQUIRED_AFTER_TIMEOUT;
23 
24 import android.app.AlarmManager;
25 import android.app.AlarmManager.OnAlarmListener;
26 import android.app.admin.DevicePolicyManager;
27 import android.app.trust.IStrongAuthTracker;
28 import android.content.Context;
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 
LockSettingsStrongAuth(Context context)66     public LockSettingsStrongAuth(Context context) {
67         mContext = context;
68         mDefaultStrongAuthFlags = StrongAuthTracker.getDefaultFlags(context);
69         mAlarmManager = context.getSystemService(AlarmManager.class);
70     }
71 
handleAddStrongAuthTracker(IStrongAuthTracker tracker)72     private void handleAddStrongAuthTracker(IStrongAuthTracker tracker) {
73         mTrackers.register(tracker);
74 
75         for (int i = 0; i < mStrongAuthForUser.size(); i++) {
76             int key = mStrongAuthForUser.keyAt(i);
77             int value = mStrongAuthForUser.valueAt(i);
78             try {
79                 tracker.onStrongAuthRequiredChanged(value, key);
80             } catch (RemoteException e) {
81                 Slog.e(TAG, "Exception while adding StrongAuthTracker.", e);
82             }
83         }
84     }
85 
handleRemoveStrongAuthTracker(IStrongAuthTracker tracker)86     private void handleRemoveStrongAuthTracker(IStrongAuthTracker tracker) {
87         mTrackers.unregister(tracker);
88     }
89 
handleRequireStrongAuth(int strongAuthReason, int userId)90     private void handleRequireStrongAuth(int strongAuthReason, int userId) {
91         if (userId == UserHandle.USER_ALL) {
92             for (int i = 0; i < mStrongAuthForUser.size(); i++) {
93                 int key = mStrongAuthForUser.keyAt(i);
94                 handleRequireStrongAuthOneUser(strongAuthReason, key);
95             }
96         } else {
97             handleRequireStrongAuthOneUser(strongAuthReason, userId);
98         }
99     }
100 
handleRequireStrongAuthOneUser(int strongAuthReason, int userId)101     private void handleRequireStrongAuthOneUser(int strongAuthReason, int userId) {
102         int oldValue = mStrongAuthForUser.get(userId, mDefaultStrongAuthFlags);
103         int newValue = strongAuthReason == STRONG_AUTH_NOT_REQUIRED
104                 ? STRONG_AUTH_NOT_REQUIRED
105                 : (oldValue | strongAuthReason);
106         if (oldValue != newValue) {
107             mStrongAuthForUser.put(userId, newValue);
108             notifyStrongAuthTrackers(newValue, userId);
109         }
110     }
111 
handleRemoveUser(int userId)112     private void handleRemoveUser(int userId) {
113         int index = mStrongAuthForUser.indexOfKey(userId);
114         if (index >= 0) {
115             mStrongAuthForUser.removeAt(index);
116             notifyStrongAuthTrackers(mDefaultStrongAuthFlags, userId);
117         }
118     }
119 
handleScheduleStrongAuthTimeout(int userId)120     private void handleScheduleStrongAuthTimeout(int userId) {
121         final DevicePolicyManager dpm =
122                 (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
123         long when = SystemClock.elapsedRealtime() + dpm.getRequiredStrongAuthTimeout(null, userId);
124         // cancel current alarm listener for the user (if there was one)
125         StrongAuthTimeoutAlarmListener alarm = mStrongAuthTimeoutAlarmListenerForUser.get(userId);
126         if (alarm != null) {
127             mAlarmManager.cancel(alarm);
128         } else {
129             alarm = new StrongAuthTimeoutAlarmListener(userId);
130             mStrongAuthTimeoutAlarmListenerForUser.put(userId, alarm);
131         }
132         // schedule a new alarm listener for the user
133         mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, when, STRONG_AUTH_TIMEOUT_ALARM_TAG,
134                 alarm, mHandler);
135     }
136 
notifyStrongAuthTrackers(int strongAuthReason, int userId)137     private void notifyStrongAuthTrackers(int strongAuthReason, int userId) {
138         int i = mTrackers.beginBroadcast();
139         try {
140             while (i > 0) {
141                 i--;
142                 try {
143                     mTrackers.getBroadcastItem(i).onStrongAuthRequiredChanged(
144                             strongAuthReason, userId);
145                 } catch (RemoteException e) {
146                     Slog.e(TAG, "Exception while notifying StrongAuthTracker.", e);
147                 }
148             }
149         } finally {
150             mTrackers.finishBroadcast();
151         }
152     }
153 
registerStrongAuthTracker(IStrongAuthTracker tracker)154     public void registerStrongAuthTracker(IStrongAuthTracker tracker) {
155         mHandler.obtainMessage(MSG_REGISTER_TRACKER, tracker).sendToTarget();
156     }
157 
unregisterStrongAuthTracker(IStrongAuthTracker tracker)158     public void unregisterStrongAuthTracker(IStrongAuthTracker tracker) {
159         mHandler.obtainMessage(MSG_UNREGISTER_TRACKER, tracker).sendToTarget();
160     }
161 
removeUser(int userId)162     public void removeUser(int userId) {
163         final int argNotUsed = 0;
164         mHandler.obtainMessage(MSG_REMOVE_USER, userId, argNotUsed).sendToTarget();
165     }
166 
requireStrongAuth(int strongAuthReason, int userId)167     public void requireStrongAuth(int strongAuthReason, int userId) {
168         if (userId == UserHandle.USER_ALL || userId >= UserHandle.USER_SYSTEM) {
169             mHandler.obtainMessage(MSG_REQUIRE_STRONG_AUTH, strongAuthReason,
170                     userId).sendToTarget();
171         } else {
172             throw new IllegalArgumentException(
173                     "userId must be an explicit user id or USER_ALL");
174         }
175     }
176 
reportUnlock(int userId)177     public void reportUnlock(int userId) {
178         requireStrongAuth(STRONG_AUTH_NOT_REQUIRED, userId);
179     }
180 
reportSuccessfulStrongAuthUnlock(int userId)181     public void reportSuccessfulStrongAuthUnlock(int userId) {
182         final int argNotUsed = 0;
183         mHandler.obtainMessage(MSG_SCHEDULE_STRONG_AUTH_TIMEOUT, userId, argNotUsed).sendToTarget();
184     }
185 
186     private class StrongAuthTimeoutAlarmListener implements OnAlarmListener {
187 
188         private final int mUserId;
189 
StrongAuthTimeoutAlarmListener(int userId)190         public StrongAuthTimeoutAlarmListener(int userId) {
191             mUserId = userId;
192         }
193 
194         @Override
onAlarm()195         public void onAlarm() {
196             requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_TIMEOUT, mUserId);
197         }
198     }
199 
200     private final Handler mHandler = new Handler() {
201         @Override
202         public void handleMessage(Message msg) {
203             switch (msg.what) {
204                 case MSG_REGISTER_TRACKER:
205                     handleAddStrongAuthTracker((IStrongAuthTracker) msg.obj);
206                     break;
207                 case MSG_UNREGISTER_TRACKER:
208                     handleRemoveStrongAuthTracker((IStrongAuthTracker) msg.obj);
209                     break;
210                 case MSG_REQUIRE_STRONG_AUTH:
211                     handleRequireStrongAuth(msg.arg1, msg.arg2);
212                     break;
213                 case MSG_REMOVE_USER:
214                     handleRemoveUser(msg.arg1);
215                     break;
216                 case MSG_SCHEDULE_STRONG_AUTH_TIMEOUT:
217                     handleScheduleStrongAuthTimeout(msg.arg1);
218                     break;
219             }
220         }
221     };
222 
223 }
224