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