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 17package com.android.server; 18 19import com.android.internal.widget.LockPatternUtils; 20import com.android.internal.widget.LockPatternUtils.StrongAuthTracker; 21 22import android.app.trust.IStrongAuthTracker; 23import android.content.Context; 24import android.os.DeadObjectException; 25import android.os.Handler; 26import android.os.Message; 27import android.os.RemoteException; 28import android.os.UserHandle; 29import android.util.Slog; 30import android.util.SparseIntArray; 31 32import java.util.ArrayList; 33 34import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED; 35 36/** 37 * Keeps track of requests for strong authentication. 38 */ 39public class LockSettingsStrongAuth { 40 41 private static final String TAG = "LockSettings"; 42 43 private static final int MSG_REQUIRE_STRONG_AUTH = 1; 44 private static final int MSG_REGISTER_TRACKER = 2; 45 private static final int MSG_UNREGISTER_TRACKER = 3; 46 private static final int MSG_REMOVE_USER = 4; 47 48 private final ArrayList<IStrongAuthTracker> mStrongAuthTrackers = new ArrayList<>(); 49 private final SparseIntArray mStrongAuthForUser = new SparseIntArray(); 50 private final int mDefaultStrongAuthFlags; 51 52 public LockSettingsStrongAuth(Context context) { 53 mDefaultStrongAuthFlags = StrongAuthTracker.getDefaultFlags(context); 54 } 55 56 private void handleAddStrongAuthTracker(IStrongAuthTracker tracker) { 57 for (int i = 0; i < mStrongAuthTrackers.size(); i++) { 58 if (mStrongAuthTrackers.get(i).asBinder() == tracker.asBinder()) { 59 return; 60 } 61 } 62 mStrongAuthTrackers.add(tracker); 63 64 for (int i = 0; i < mStrongAuthForUser.size(); i++) { 65 int key = mStrongAuthForUser.keyAt(i); 66 int value = mStrongAuthForUser.valueAt(i); 67 try { 68 tracker.onStrongAuthRequiredChanged(value, key); 69 } catch (RemoteException e) { 70 Slog.e(TAG, "Exception while adding StrongAuthTracker.", e); 71 } 72 } 73 } 74 75 private void handleRemoveStrongAuthTracker(IStrongAuthTracker tracker) { 76 for (int i = 0; i < mStrongAuthTrackers.size(); i++) { 77 if (mStrongAuthTrackers.get(i).asBinder() == tracker.asBinder()) { 78 mStrongAuthTrackers.remove(i); 79 return; 80 } 81 } 82 } 83 84 private void handleRequireStrongAuth(int strongAuthReason, int userId) { 85 if (userId == UserHandle.USER_ALL) { 86 for (int i = 0; i < mStrongAuthForUser.size(); i++) { 87 int key = mStrongAuthForUser.keyAt(i); 88 handleRequireStrongAuthOneUser(strongAuthReason, key); 89 } 90 } else { 91 handleRequireStrongAuthOneUser(strongAuthReason, userId); 92 } 93 } 94 95 private void handleRequireStrongAuthOneUser(int strongAuthReason, int userId) { 96 int oldValue = mStrongAuthForUser.get(userId, mDefaultStrongAuthFlags); 97 int newValue = strongAuthReason == STRONG_AUTH_NOT_REQUIRED 98 ? STRONG_AUTH_NOT_REQUIRED 99 : (oldValue | strongAuthReason); 100 if (oldValue != newValue) { 101 mStrongAuthForUser.put(userId, newValue); 102 notifyStrongAuthTrackers(newValue, userId); 103 } 104 } 105 106 private void handleRemoveUser(int userId) { 107 int index = mStrongAuthForUser.indexOfKey(userId); 108 if (index >= 0) { 109 mStrongAuthForUser.removeAt(index); 110 notifyStrongAuthTrackers(mDefaultStrongAuthFlags, userId); 111 } 112 } 113 114 private void notifyStrongAuthTrackers(int strongAuthReason, int userId) { 115 for (int i = 0; i < mStrongAuthTrackers.size(); i++) { 116 try { 117 mStrongAuthTrackers.get(i).onStrongAuthRequiredChanged(strongAuthReason, userId); 118 } catch (DeadObjectException e) { 119 Slog.d(TAG, "Removing dead StrongAuthTracker."); 120 mStrongAuthTrackers.remove(i); 121 i--; 122 } catch (RemoteException e) { 123 Slog.e(TAG, "Exception while notifying StrongAuthTracker.", e); 124 } 125 } 126 } 127 128 public void registerStrongAuthTracker(IStrongAuthTracker tracker) { 129 mHandler.obtainMessage(MSG_REGISTER_TRACKER, tracker).sendToTarget(); 130 } 131 132 public void unregisterStrongAuthTracker(IStrongAuthTracker tracker) { 133 mHandler.obtainMessage(MSG_UNREGISTER_TRACKER, tracker).sendToTarget(); 134 } 135 136 public void removeUser(int userId) { 137 mHandler.obtainMessage(MSG_REMOVE_USER, userId, 0).sendToTarget(); 138 } 139 140 public void requireStrongAuth(int strongAuthReason, int userId) { 141 if (userId == UserHandle.USER_ALL || userId >= UserHandle.USER_SYSTEM) { 142 mHandler.obtainMessage(MSG_REQUIRE_STRONG_AUTH, strongAuthReason, 143 userId).sendToTarget(); 144 } else { 145 throw new IllegalArgumentException( 146 "userId must be an explicit user id or USER_ALL"); 147 } 148 } 149 150 public void reportUnlock(int userId) { 151 requireStrongAuth(STRONG_AUTH_NOT_REQUIRED, userId); 152 } 153 154 private final Handler mHandler = new Handler() { 155 @Override 156 public void handleMessage(Message msg) { 157 switch (msg.what) { 158 case MSG_REGISTER_TRACKER: 159 handleAddStrongAuthTracker((IStrongAuthTracker) msg.obj); 160 break; 161 case MSG_UNREGISTER_TRACKER: 162 handleRemoveStrongAuthTracker((IStrongAuthTracker) msg.obj); 163 break; 164 case MSG_REQUIRE_STRONG_AUTH: 165 handleRequireStrongAuth(msg.arg1, msg.arg2); 166 break; 167 case MSG_REMOVE_USER: 168 handleRemoveUser(msg.arg1); 169 break; 170 } 171 } 172 }; 173} 174