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