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