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